Preface
Recently I received a request that embarrassed me.(Here's some crap)
The effect is that the top is partially suspended, followed by some layouts, a few switchable Tab pages below, and then scroll ~~Well, well, let's just look at the picture.
The main thing is the suspension of the top and Tab, and the effect of being topped off.
To achieve this effect, my drawer's special chopping knife has been foolishly moved.
thinking
Let's start with the idea of implementation. The above effects can be roughly divided into two parts:
- 1. Suspend when Tab scrolls up to the top
Tab is floating on top after scrolling ~~This effect can be easily achieved using CoordinatorLayout + AppBarLayout.(What?You don't know how to use these two controls yet?Well, you should be able to barely understand what follows) - 2. Top suspension and the effect of being "topped off"
Simply wrap a FrameLayout around the CoordinatorLayout and change the top layout to it.Next listen for AppBarLayout scrolling and use topMargin to "top up" it
Now that the split is complete, the next step is to implement
Realization
-
Tab suspension effect
Tab suspension using CoordinatorLayout, AppBarLayout, TabLayout, ViewPager
<?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" android:background="#FFF"> <android.support.design.widget.AppBarLayout android:id="@+id/app_bar" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#FFF"> <LinearLayout android:id="@+id/ll" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" app:layout_scrollFlags="scroll|exitUntilCollapsed"> <ImageView android:id="@+id/header" android:layout_width="match_parent" android:layout_height="260dp" android:scaleType="centerCrop" android:src="@drawable/bg_header"/> </LinearLayout> <android.support.design.widget.TabLayout android:id="@+id/table_layout" android:layout_width="match_parent" android:layout_height="50dp" android:background="#FBDD9C" app:tabGravity="fill" app:tabIndicatorColor="#5f00" app:tabIndicatorHeight="4dp" app:tabMode="fixed" app:tabSelectedTextColor="#FFFFFF" app:tabTextColor="#FFFFFF"/> </android.support.design.widget.AppBarLayout> <android.support.v4.view.ViewPager android:id="@+id/vp" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior"/> </android.support.design.widget.CoordinatorLayout>
- Set app:layout_scrollFlags="scroll|exitUntilCollapsed" in LinearLayout and TabLayout does not set app:layout_scrollFlags property
- Use app:layout_behavior="@string/appbar_scrolling_view_behavior" in ViewPager
layout_scrollFlags: AppBarLayout's properties for Children View have five values: scroll, enterAlways, enterAlwaysCollapsed, snap, exitUntilCollapsed.Specific use can be referred to Android details five ScrollFlags for AppBarLayout
(I won't say much about the detailed use of CoordinatorLayout and AppBarLayout)
Then, just add a few list fragments to the ViewPager in Java code to see the following effect (Note: Lists can't be ListView s, you need RecyclerView)
So far, the effect has been mostly achieved.The final value needs to be pushed away.
-
Top "Topped off" effect
At this point, the layout changes a little.
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" xmlns:app="http://schemas.android.com/apk/res-auto"> <android.support.design.widget.CoordinatorLayout android:layout_width="match_parent" android:layout_height="match_parent" android:background="#FFF"> <android.support.design.widget.AppBarLayout android:id="@+id/app_bar" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#FFF"> <LinearLayout android:id="@+id/ll" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" app:layout_scrollFlags="scroll|exitUntilCollapsed"> <View android:layout_width="match_parent" android:layout_height="50dp"/> <ImageView android:id="@+id/header" android:layout_width="match_parent" android:layout_height="260dp" android:scaleType="centerCrop" android:src="@drawable/bg_header"/> </LinearLayout> <android.support.design.widget.TabLayout android:id="@+id/table_layout" android:layout_width="match_parent" android:layout_height="50dp" android:background="#FBDD9C" app:tabGravity="fill" app:tabIndicatorColor="#5f00" app:tabIndicatorHeight="4dp" app:tabMode="fixed" app:tabSelectedTextColor="#FFFFFF" app:tabTextColor="#FFFFFF"/> </android.support.design.widget.AppBarLayout> <android.support.v4.view.ViewPager android:id="@+id/vp" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior"/> </android.support.design.widget.CoordinatorLayout> <TextView android:id="@+id/sticky_view" android:layout_width="match_parent" android:layout_height="50dp" android:textColor="#FFFFFF" android:text="I will move except suspend" android:gravity="center" android:textSize="16sp" android:background="#39b9e9"/> </FrameLayout>
On the original basis, a FrameLayout is set, and the suspended part at the top can be achieved through FrameLayout.This also results in the following layout being partially covered, so an empty View of the same height as the suspended portion is added to the LinearLayout.
The layout is complete. How can the effect of being pushed away be achieved?Simply listen for AppBarLayout scrolling in MainActivity.
@BindView(R.id.app_bar) AppBarLayout mAppBar; @BindView(R.id.sticky_view) View mStickyView; @BindView(R.id.header) View mHeader; private void setAppBarListener() { mAppBar.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() { @Override public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) { //Head Height (Remove Top Covered Part) int minScrollHeight = mHeader.getMeasuredHeight(); int margin = minScrollHeight + verticalOffset; margin = margin > 0 ? 0 : margin; FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) mStickyView.getLayoutParams(); layoutParams.topMargin = margin; mStickyView.setLayoutParams(layoutParams); } }); }
Here the margin value is calculated by listening for AppBarLayout scrolling (when scrolling up, the verticalOffset value changes to 0, -1, -2... -n-1, -n).By changing topMargin, the effect of being "pushed away" is achieved.
Take a second look at the effect:
Knock here, I silently picked up the special kitchen knife for cutting products.
Tips
- Problem: Smooth scrolling with CoordinatorLayout
Solution: You can write a Behavior to add to AppBarLayout. Specific Solutions - Question: If you are trying to refresh a feature and you have a SwipeRefreshLayout on the outside of CoordinatorLayout, it triggers a refresh ~ (I've experienced it)
Solution: This problem can be handled by monitoring AppBarLayout and setting swipeLayout's Enabled
mAblAppBar.addOnOffsetChangedListener((appBarLayout, verticalOffset) -> { if (verticalOffset == 0) { swipeLayout.setEnabled(true); } else { if (!swipeLayout.isRefreshing()) { swipeLayout.setEnabled(false); } } });
Source Address
There are errors above, thank you for pointing out