【Android】這效果,我沒法描述
前言
最近接到一個需求,這需求讓我表示很尷尬。(下面是一些廢話)
要求的效果是這樣的,頂部有部分懸浮,接著是一些布局,在下面是幾個可切換的Tab頁面,然后滾動的時候~~吧啦吧啦吧啦吧啦~~ 還是直接看圖吧
主要就是頂部和Tab的懸浮,還有就是被頂掉的那個效果。
聽到要實現這樣的效果,我抽屜那把砍產品專用菜刀已經蠢蠢欲動了。
思路
先說說實現的思路吧,上面的效果大致可以分成兩個部分:
1、Tab向上滾動到頂部時懸浮
Tab滾動后懸浮在頂部嘛~~ 這效果使用CoordinatorLayout + AppBarLayout就能輕松實現。(什么?你還不懂這兩個控件怎么使用?額,應該可以勉強看懂后面的內容)
2、頂部懸浮以及“被頂走”的效果
只要在CoordinatorLayout外面套一層FrameLayout,然后把這個頂部的布局改在上面。接著監聽AppBarLayout的滾動,利用topMargin實現被“頂上去”的效果
拆分完畢,接下來就是實現了
實現
- Tab的懸浮效果
利用CoordinatorLayout、AppBarLayout、TabLayout、ViewPager來實現Tab的懸浮效果
- <br>
LinearLayout中設置app:layout_scrollFlags="scroll|exitUntilCollapsed" 而 TabLayout 不設置app:layout_scrollFlags屬性
ViewPager中使用app:layout_behavior="@string/appbar_scrolling_view_behavior"
layout_scrollFlags:AppBarLayout供Children View使用的屬性,一共有五種值:scroll,enterAlways,enterAlwaysCollapsed,snap,exitUntilCollapsed。具體的使用可以參考Android 詳細分析AppBarLayout的五種ScrollFlags
(CoordinatorLayout、AppBarLayout的詳細用法我就不多說了)
然后,只要在Java代碼中為ViewPager添加幾個列表Fragment就能看到以下的效果(注意:列表不可以是ListView,需要用RecyclerView)
到目前為止,效果已經實現了大半。最后值需要實現“被頂走”的效果就好了。
- 頂部“被頂走”的效果
這時候,布局稍微改變下。
- <br>
在原有的基礎上,套了個FrameLayout,頂部的懸浮部分可以通過FrameLayout來實現。這樣也導致下面的布局被蓋住了一部分,因此在LinearLayout中加了與懸浮部分相同高度的空View。
布局是完成了,那個“被頂走”的效果怎么實現呢?這時候只要在MainActivity中對AppBarLayout的滾動進行監聽即可。
- @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) {
- //頭部高度(除去被頂部覆蓋的部分)
- 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);
- }
- });
- }
這里通過AppBarLayout滾動的進行監聽(向上滾動時,verticalOffset值的變化為:0、-1 、-2 ... -n-1、-n)來計算margin值。通過改變topMargin,實現“被頂走”的效果。
再看一眼效果:
敲到這里,我才默默的收起了那把砍產品專用菜刀。
Tips
問題:使用CoordinatorLayout時,滾動不流暢問題
解決方案:可以寫個Behavior添加到AppBarLayout中。具體的解決方案
問題:如果你在想要刷新功能,在CoordinatorLayout外面套了一個SwipeRefreshLayout,一不小心就觸發了刷新~~(自己體會)
解決方案:這個問題可以通過對AppBarLayout的監聽,設置swipeLayout的Enabled來處理
- mAblAppBar.addOnOffsetChangedListener((appBarLayout, verticalOffset) -> {
- if (verticalOffset == 0) {
- swipeLayout.setEnabled(true);
- } else {
- if (!swipeLayout.isRefreshing()) {
- swipeLayout.setEnabled(false);
- }
- }
- });