标题栏随页面滑动之title移动定位效果——TitleLocate

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/java_android_man/article/details/78827661

可能小伙伴们会碰到这种需求,

页面Y轴方向是可滑动的ScrollView或者RecyclerViewListViewGridView

标题栏沉浸式,随着页面滑动,

标题栏随着做背景色的渐隐渐现效果,为了不遮挡图片或者沉浸式UI,标题也是随着滑动到某个距离时,才做显现。

今天就为大家带来这样一个示例。其实咱们掌握的最主要的是思路,理清思路后,再动手会更快哦。

言归正传,先放效果图:




看到效果图,是不是已经明白了这个效果的一大半呢。

布局代码:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <!--内容视图部分-->
    <com.titleanim.kevin.MyScrollView
        android:id="@+id/scrollView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">

            <ImageView
                android:layout_width="match_parent"
                android:layout_height="210dp"
                android:scaleType="fitXY"
                android:src="@drawable/k_astronauts" />

            <View
                android:id="@+id/v_left"
                android:layout_width="30dp"
                android:layout_height="15dp"
                android:background="@color/colorAccent" />

            <TextView
                android:id="@+id/tv_titleBottom"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="我是标题"
                android:textColor="@color/colorAccent"
                android:textSize="16sp" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="20dp"
                android:lineSpacingExtra="15dp"
                android:text="航天英雄杨利伟。。。"
                android:textColor="#666666"
                android:textSize="14sp" />

        </LinearLayout>
    </com.titleanim.kevin.MyScrollView>

    <!--标题部分-->
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="70dp">

        <View
            android:id="@+id/v_titleBg"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:alpha="0"
            android:background="@android:color/white" />

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="45dp"
            android:layout_alignParentBottom="true">

            <ImageView
                android:id="@+id/iv_back"
                android:layout_width="45dp"
                android:layout_height="match_parent"
                android:contentDescription="@null"
                android:scaleType="centerInside"
                android:src="@drawable/selector_back" />

            <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_centerHorizontal="true"
                android:gravity="center_horizontal"
                android:orientation="horizontal">

                <View
                    android:id="@+id/v_leftTop"
                    android:layout_width="30dp"
                    android:layout_height="15dp"
                    android:layout_marginTop="45dp"
                    android:background="@color/colorAccent" />

                <TextView
                    android:id="@+id/tv_titleTop"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="45dp"
                    android:paddingLeft="5dp"
                    android:text="我是标题"
                    android:textColor="@color/colorAccent"
                    android:textSize="16sp" />
            </LinearLayout>
        </RelativeLayout>
    </RelativeLayout>
</RelativeLayout>

布局很简单:

根布局是一个RelativeLayout ,标题部分覆盖在主视图上。默认初始化时标题栏背景色为透明。返回按钮为白色。

标题栏中间的文字和红色方块(也可以显示为小图片)默认topMargin为标题高度,这样初始化时就看不到中间标题了,为后续的定位作基础。

标题高度设置为70dp,为何多了25dp呢,是因为状态栏的高度为25dp。这个高度也可以通过代码获取动态设置,这个不是讨论的重点。

下面看图一起分析:




问题:

1.如何将页面上“1处”视图的滑动和“2处”标题栏中的标题绿色部分的显示关联起来呢?

2.如果页面一直往上滑动,该又如何保持“2处”的标题显示在正中后不会继续向上滑动呢?

既然咱们列出了两个问题,那就一个个来解决,当问题解决了,咱们的效果也就实现了。

思路:

1.监听ScrollView的滑动事件,在监听中计算滑动的偏移量,根据偏移量设置页面标记“2处”的上间距topMargin;

2.当思路1中的结果(topMargin)达到了我们想要的距离时,不再设置,从而保持“2处”标题栏的定位效果;

既然思路出来了,那咱们上关键代码:

scrollView.setScrollViewListener(new MyScrollView.ScrollViewListener() {
            @Override
            public void onScrollChanged(MyScrollView scrollView, int l, int t, int oldl, int oldt) {
                // 计算偏移差
                int dy = t - mLastTop;
                // 赋值最新的偏移量
                mLastTop = t;
                // 以图片的高度为基准计算滑动比值
                float progress = (float) (mLastTop) / (float) (topAreaHeight);
                if (progress > 1) {
                    progress = 1;
                } else if (progress < 0) {
                    progress = 0;
                }
                // 根据比值设置背景色
                v_titleBg.setAlpha(progress);
                // 设置返回按钮的状态
                iv_back.setSelected(progress > 0.5f);
                // 计算总的标题开始偏移后的偏移量
                if (mLastTop >= titleShowYOffset) {
                    totalTitleYOffset += dy;
                } else {
                    totalTitleYOffset = 0;
                }
                int titleTopMargin = maxTitleTopMargin - totalTitleYOffset;
                // 判断是否和上次的值是否一样
                if (titleTopMargin != titleParams.topMargin) {
                    titleParams.topMargin = titleTopMargin;
                    titleParams.topMargin = titleParams.topMargin <= minTitleTopMargin
                            ? minTitleTopMargin : titleParams.topMargin;
                    tv_titleTop.setLayoutParams(titleParams);
                    tv_titleTop.requestLayout();
                }
                // 计算总的红色方块开始偏移后的偏移量
                if (mLastTop >= leftShowYOffset) {
                    totalLeftYOffset += dy;
                } else {
                    totalLeftYOffset = 0;
                }
                int leftTopMargin = maxTitleTopMargin - totalLeftYOffset;
                // 判断是否和上次的值是否一样
                if (leftParams.topMargin != leftTopMargin) {
                    leftParams.topMargin = leftTopMargin;
                    leftParams.topMargin = leftParams.topMargin <= minLeftTopMargin
                            ? minLeftTopMargin : leftParams.topMargin;
                    v_leftTop.setLayoutParams(leftParams);
                    v_leftTop.requestLayout();
                }
            }
        });


不管是RecyclerView, 还是ListView实现的思路都是一样的,标题栏有几个View需要这样的效果,只要按照这个思路都是OK的。

Demo已上传github 地址:github仓库地址

CSDN资源下载地址:CSDN上资源demo下载


欢迎大家一起讨论哦!

猜你喜欢

转载自blog.csdn.net/java_android_man/article/details/78827661