-
Notifications
You must be signed in to change notification settings - Fork 353
2.布局吸顶
要实现布局的吸顶效果,在以前,我们可能会写两个一摸一样的布局,一个隐藏在顶部,一个嵌套在ScrollView下,通过监听ScrollView的滑动来显示和隐藏顶部的布局。这种方式实现起来既麻烦也不优雅。ConsecutiveScrollerLayout内部实现了子View吸附顶部的功能,只要设置属性app:layout_isSticky="true"
,就可以实现吸顶功能。而且支持设置多个子View吸顶,后面的View要吸顶时会把前面的吸顶View推出屏幕。
<?xml version="1.0" encoding="utf-8"?>
<com.donkingliang.consecutivescroller.ConsecutiveScrollerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/scrollerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical">
<!-- 设置app:layout_isSticky="true"就可以使View吸顶 -->
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/white"
android:padding="10dp"
android:text="吸顶View - 1"
android:textColor="@android:color/black"
android:textSize="18sp"
app:layout_isSticky="true" />
<WebView
android:id="@+id/webView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/white"
android:orientation="vertical"
app:layout_isSticky="true">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="吸顶View - 2 我是个LinearLayout"
android:textColor="@android:color/black"
android:textSize="18sp" />
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView1"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/white"
android:padding="10dp"
android:text="吸顶View - 3"
android:textColor="@android:color/black"
android:textSize="18sp"
app:layout_isSticky="true" />
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
</androidx.core.widget.NestedScrollView>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/white"
android:padding="10dp"
android:text="吸顶View - 4"
android:textColor="@android:color/black"
android:textSize="18sp"
app:layout_isSticky="true" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView2"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</com.donkingliang.consecutivescroller.ConsecutiveScrollerLayout>
如果你不希望吸顶的view被后面的吸顶view顶出屏幕,而是多个吸顶view排列吸附在顶部,你可以设置常驻吸顶模式:app:isPermanent="true"
。
<?xml version="1.0" encoding="utf-8"?>
<com.donkingliang.consecutivescroller.ConsecutiveScrollerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/scrollerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:isPermanent="true" // 常驻吸顶
android:scrollbars="vertical">
</com.donkingliang.consecutivescroller.ConsecutiveScrollerLayout>
默认情况下,吸顶view在吸顶状态下,会显示在布局上层,悬浮在布局顶部,覆盖其他布局。
如果你希望吸顶View吸顶时,不是悬浮在顶部,而是像抽屉一样收起隐藏在布局下层,你可以把吸顶View设置为下沉模式。属性:app:layout_isSink="true"
。设置了下沉模式,view在吸顶时会显示在下层,被其他布局覆盖,隐藏在下面。
<?xml version="1.0" encoding="utf-8"?>
<com.donkingliang.consecutivescroller.ConsecutiveScrollerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/scrollerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical">
<!-- 这个吸顶View吸顶时,会隐藏在布局下层 -->
<FrameLayout
android:id="@+id/fl_sink"
android:layout_width="match_parent"
android:layout_height="400dp"
app:layout_isSink="true" // 设置这个吸顶View为吸顶下沉模式
app:layout_isTriggerScroll="true"
app:layout_isSticky="true">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitXY"
android:src="@drawable/temp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="30dp"
android:layout_marginRight="30dp"
android:layout_marginTop="30dp"
android:textColor="@android:color/white"
android:textSize="16sp"
android:text="这是个下沉的吸顶view,它不会被推出屏幕,而是覆盖隐藏在其他布局下面。"/>
</FrameLayout>
</com.donkingliang.consecutivescroller.ConsecutiveScrollerLayout>
吸顶View默认是悬浮停留在ConsecutiveScrollerLayout的顶部,如果你希望吸顶View悬停的位置是距离顶部往上或者往下一定距离的位置,那么你可以使用app:stickyOffset
属性设置吸顶位置的偏移。
<com.donkingliang.consecutivescroller.ConsecutiveScrollerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/scrollerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:stickyOffset="50dp"> // 吸顶偏移
</com.donkingliang.consecutivescroller.ConsecutiveScrollerLayout>
// 设置吸顶View到顶部的距离,在距离顶部一定距离时开始悬停吸顶
// 使用这个方法可以动态改变吸顶View的吸顶位置
scrollerLayout.setStickyOffset(int offset);
子View悬浮吸顶时,会覆盖遮挡下面的布局,如果你希望下面的布局不被吸顶view覆盖,可以设置属性app:autoAdjustHeightAtBottomView="true"
,它能让ConsecutiveScrollerLayout的最后一个子View
自动调整自己的高度,使布局内容不被吸顶View覆盖。
<com.donkingliang.consecutivescroller.ConsecutiveScrollerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/scrollerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:autoAdjustHeightAtBottomView="true"> // 自动调整底部子view高度
</com.donkingliang.consecutivescroller.ConsecutiveScrollerLayout>
自动调整子view高度的时候,除了考虑吸顶View的高度以外,可能还需要考虑其他的一些额外因素。比如使用stickyOffset
属性改变了吸顶View的吸顶位置,那么就有可能调整了子view高度后,吸顶View依然会遮挡布局。这时你可以通过app:adjustHeightOffset
属性设置子view高度调整时的额外高度偏移,在调整子view高度时,会将这个高度偏移量考虑进去。
<com.donkingliang.consecutivescroller.ConsecutiveScrollerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/scrollerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:adjustHeightOffset="50dp"> // 调整子view高度的额外偏移量
</com.donkingliang.consecutivescroller.ConsecutiveScrollerLayout>
解析:
autoAdjustHeightAtBottomView属性和adjustHeightOffset属性只会对ConsecutiveScrollerLayout的最后一个子View期作用,也就是说,只有最后一个子View的高度会被调整。
不调整子view高度时,子View的最大高度不大于ConsecutiveScrollerLayout的高度。调整子view高度后,子View的最大高度不大于ConsecutiveScrollerLayout的高度 - 吸顶View高度 - adjustHeightOffset
。adjustHeightOffset可以为负数,但是吸顶View高度 + adjustHeightOffset
不能为负数,也就是后调整子view高度依然不大于ConsecutiveScrollerLayout的高度。
如果你使用了吸顶View功能,就应该设置app:autoAdjustHeightAtBottomView="true"
。
stickyOffset表示吸顶View的吸顶位置偏移,可以动态改变吸顶view的位置。adjustHeightOffset表示自动调整子View高度时的额外高度偏移量,不可以动态改变。当你设置了stickyOffset,就有可能需要设置adjustHeightOffset避免布局被覆盖遮挡,但不是必须的,这取决于你的布局和业务。
autoAdjustHeightAtBottomView属性和adjustHeightOffset属性虽然大部分时候是跟吸顶功能配合使用的,但是也可以单独使用。比如下面的例子中,如果Toolbar开始为透明,当ConsecutiveScrollerLayout滑动时变为不透明,就会覆盖ConsecutiveScrollerLayout的顶部,那么你就可以使用autoAdjustHeightAtBottomView和adjustHeightOffset调整ConsecutiveScrollerLayout的子View高度,使它在滑动到底部时,最后一个子View的内容不被遮挡覆盖。
<FrameLayout 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">
<com.donkingliang.consecutivescroller.ConsecutiveScrollerLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:adjustHeightOffset="48dp"
app:autoAdjustHeightAtBottomView="true">
</com.donkingliang.consecutivescroller.ConsecutiveScrollerLayout>
<androidx.appcompat.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="48dp" />
</FrameLayout>
// 监听吸顶变化(普通模式)
scrollerLayout.setOnStickyChangeListener(OnStickyChangeListener);
// 监听吸顶变化(常驻模式)
scrollerLayout.setOnPermanentStickyChangeListener(OnPermanentStickyChangeListener);
// 获取当前吸顶view(普通模式)
scrollerLayout.getCurrentStickyView();
// 获取当前吸顶view(常驻模式)
scrollerLayout.getCurrentStickyViews();
// 设置吸顶常驻模式
public void setPermanent(boolean isPermanent);
// 判断子view是否处于吸顶状态
public boolean theChildIsStick(View child);
// 判断子view是否是吸顶view
public boolean isStickyView(View child);
/**
* 在View吸顶的状态下,是否可以触摸view来滑动ConsecutiveScrollerLayout布局。
* 默认为false,则View吸顶的状态下,不能触摸它来滑动布局
*/
app:layout_isTriggerScroll="true"