可能小夥伴們會碰到這種需求,
頁面Y軸方向是可滑動的ScrollView或者RecyclerView,ListView,GridView,
标題欄沉浸式,随着頁面滑動,
标題欄随着做背景色的漸隐漸現效果,為了不遮擋圖檔或者沉浸式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下載下傳
歡迎大家一起讨論哦!