ScrollView实现粘性头部

上一篇文章实现了RecyclerView的粘性头部,这次来介绍下ScrollView如何实现粘性头部,其实实现思路几乎一样!

效果图

上一篇文章类似效果

实现思路

1.布局结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">


<!--toolbar-->
<android.support.design.widget.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content">

<android.support.v7.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:navigationIcon="?attr/homeAsUpIndicator"
app:title="title" />

</android.support.design.widget.AppBarLayout>

<android.support.v4.widget.NestedScrollView
android:id="@+id/rv_scrollview"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
>
<include layout="@layout/scroll_content"/>
</android.support.v4.widget.NestedScrollView>


<TextView
android:id="@+id/sticky_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="20dp"
android:background="#e89112"
android:gravity="center"
android:text="sticky header"
android:textColor="@android:color/white"
/>


</android.support.design.widget.CoordinatorLayout>

scroll_content

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#f2f2f2"
>


<ImageView
android:layout_width="match_parent"
android:layout_height="200dp"
android:src="@mipmap/girl"
android:scaleType="centerCrop"
/>


<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="20dp"
/>


<TextView
android:layout_marginBottom="1dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="A"
android:padding="20dp"
android:background="@android:color/white"
/>

<TextView
android:layout_marginBottom="1dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="B"
android:padding="20dp"
android:background="@android:color/white"
/>

......
</LinearLayout>

ps:NestedScrollView中包括三部分,普通header、sticky header、item;其中sticky header是假view,只是为了占个高度。真正的sticky header在CoordinatorLayout中。

2.滑动处理
主要就是添加滑动监听,把NestedScrollView的滑动距离算出来(与RecyclerView的区别就是不需要累加,scrollY就是滑动的总距离),然后与最大滑动距离比较,即普通header的高度,如果差值>0,则滑动此距离,<0就不滑动。这样就可以把某个header定在一处。

主要代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

//200dp是普通header的高度
maxDist=ScreenUtils.dip2px(this,200);
stickyView=findViewById(R.id.sticky_header);
scrollView= (NestedScrollView) findViewById(R.id.rv_scrollview);

appbar= (AppBarLayout) findViewById(R.id.appbar);
appbar.post(new Runnable() {
@Override
public void run() {
barHeight= appbar.getMeasuredHeight();
stickyView.setTranslationY(maxDist+barHeight);
}
});


scrollView.setOnScrollChangeListener(new NestedScrollView.OnScrollChangeListener() {
@Override
public void onScrollChange(NestedScrollView v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
Log.e(TAG,"scrollY:"+scrollY);
int tranY=Math.max(0,maxDist-scrollY);
//移动距离超过maxDist,就定在0处 ,barHeight是appbar的高度,必须加上
stickyView.setTranslationY(tranY+barHeight);
}
});