天天看點

标題欄随頁面滑動之title移動定位效果——TitleLocate

可能小夥伴們會碰到這種需求,

頁面Y軸方向是可滑動的ScrollView或者RecyclerView,ListView,GridView,

标題欄沉浸式,随着頁面滑動,

标題欄随着做背景色的漸隐漸現效果,為了不遮擋圖檔或者沉浸式UI,标題也是随着滑動到某個距離時,才做顯現。

今天就為大家帶來這樣一個示例。其實咱們掌握的最主要的是思路,理清思路後,再動手會更快哦。

言歸正傳,先放效果圖:

标題欄随頁面滑動之title移動定位效果——TitleLocate

看到效果圖,是不是已經明白了這個效果的一大半呢。

布局代碼:

<?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。這個高度也可以通過代碼擷取動态設定,這個不是讨論的重點。

下面看圖一起分析:

标題欄随頁面滑動之title移動定位效果——TitleLocate

問題:

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下載下傳

歡迎大家一起讨論哦!