调研了一下微博和豆瓣等大体量的APP,发现内容详情页的评论吸顶效果非常常见。
以截图自豆瓣的效果为例,当上划至内容部分消失时,滑动中的回复条会置顶,并保持在位置不动。
笔者通过实践,记录下目前发现的最easy 的写法,只改变布局,不需要代码动态修改。使用方式如下:
View A: 当滑动时,需要滑动上去不见的部分
View B:当滑动到顶端时,需要保持可见的部分
View C:一般来说是一个RecyclerView
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="140dp">
<View
android:id="@+id/view_A"
android:layout_width="match_parent"
android:layout_height="100dp"
android:gravity="center"
android:background="@color/teal_700"
app:layout_scrollFlags="scroll|enterAlways"/>
<View
android:id="@+id/view_B"
android:id="@+id/hot_title"
android:layout_width="match_parent"
android:layout_height="40dp"
tools:ignore="MissingConstraints" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/view_C"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
主要是通过CoordinateLayout(协调者布局)和AppBarLayout两者相结合。通过app:layout_behavior的设置达到效果。
简单介绍一下CoordinateLayout吧。
/** * CoordinatorLayout is a super-powered {@link android.widget.FrameLayout FrameLayout}. * * <p>CoordinatorLayout is intended for two primary use cases:</p> * <ol> * <li>As a top-level application decor or chrome layout</li> * <li>As a container for a specific interaction with one or more child views</li> * </ol> * * <p>By specifying {@link Behavior Behaviors} for child views of a * CoordinatorLayout you can provide many different interactions within a single parent and those * views can also interact with one another. View classes can specify a default behavior when * used as a child of a CoordinatorLayout using the * {@link DefaultBehavior} annotation.</p>
官方给出的解释是加强版的FrameLayout,所以基本使用跟FrameLayout一样。要不就是layout中最顶层的父View,也就是上图包括View A,View B,View C的情况,要不就是当成一个layout容器在父视图中。我们这次使用的的是第一种情况,作为父布局的情况。
CoordinatorLayout主要多增加的属性就是app:layout_behavior了。不设置时就是默认不添加behavior的情况,像View B这样。在例子中,是包含在CoordinatorLayout中的View C设置了behavior属性,使用的是官方默认的,当然如果你需要的话,也可以自定义behavior来使用。
具体的引用值如下
<string name="appbar_scrolling_view_behavior" translatable="false">com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior</string> <string name="bottom_sheet_behavior" translatable="false">com.google.android.material.bottomsheet.BottomSheetBehavior</string> <string name="fab_transformation_scrim_behavior" translatable="false">com.google.android.material.transformation.FabTransformationScrimBehavior</string> <string name="fab_transformation_sheet_behavior" translatable="false">com.google.android.material.transformation.FabTransformationSheetBehavior</string> <string name="hide_bottom_view_on_scroll_behavior" translatable="false">com.google.android.material.behavior.HideBottomViewOnScrollBehavior</string>
根据name也可以看出来使用场景了,这里不赘述了。这边使用的是和AppBarLayout配套的app:layout_behavior="@string/appbar_scrolling_view_behavior"。啥意思呢,就是viewC这个childView,要把自己放在appBar底下滑动。
再看滑着滑着就不见的View A,放置在AppBarLayout这个容器里面,特别设置了一个属性:app:layout_scrollFlags="scroll|enterAlways" 这个scrollFlags属性呢,有5个值可以填。
scroll :跟着滑动,在屏幕里面滑进滑出。这个属性是主要属性,底下的属性就是附加效果。只有scroll这个属性时,View C滑到顶,第一个item可见,View A才滑动显示出来。
enterAlways:View C快滑到顶的时候,View A先滑动显示出来,最后View C才划到第一个Item可见。
enterAlwaysCollapsed:往下滑时,View A先逐渐滑动,到最小值时,View C再滑动
snap:上下滑手指离开时,View A要么全显示,要么不显示,没中间过渡态
exitUntilCollapsed:往上滑时,View A滑到最小状态,然后View C再滑动