安卓Design包之CollapsingToolbarLayout(可折疊的工具欄布局)的簡單使用


轉自:

CollapsingToolbarLayout的使用

2020.7.8記錄:

項目更新為androidX了,里面的包名相應的也要替換,否則會找不到包。

android.support.design.widget.CoordinatorLayout -> androidx.coordinatorlayout.widget.CustomCoordinatorLayout
android.support.design.widget.AppBarLayout -> com.google.android.material.appbar.AppBarLayout
android.support.design.widget.CollapsingToolbarLayout -> com.google.android.material.appbar.CollapsingToolbarLayout
android.support.v7.widget.Toolbar -> androidx.core.widget.Toolbar
android.support.design.widget.TabLayout -> com.google.android.material.appbar.TabLayout
android.support.v4.widget.NestedScrollView -> androidx.core.widget.NestedScrollView

 

注意:使用前需要添加Design依賴包,使用toolbar時需要隱藏標題頭

CollapsingToolbarLayout作用是提供了一個可以折疊的Toolbar,它繼承至FrameLayout,給它設置layout_scrollFlags,它可以控制包含在CollapsingToolbarLayout中的控件(如:ImageView、Toolbar)在響應layout_behavior事件時作出相應的scrollFlags滾動事件(移除屏幕或固定在屏幕頂端)

NestedScrollView:它是support-v4包提供的控件,繼承至FrameLayout, 並實現了NestedScrollingParent,NestedScrollingChild, ScrollingView接口. 

它的作用類似於Android.widget.ScrollView,不同點在於NestedScrollView支持嵌套滑動.

需實現的布局:

 最外層是CoorinatorLayout,然后里面包含了AppBarlayout和NestedScrollView

AppBarLayout里包含了CollspsingToolbar和Tableyout,它的作用是可以將所有的子控件都當成一個整體

CollapsingToolbarLayout里面則包含了一個ImageView和ToolBar作為伸縮的區域。

 

 

1. AppBarLayout的子布局有5種滾動標識(layout_scrollFlags屬性):

  • scroll:將此布局和滾動時間關聯。這個標識要設置在其他標識之前,沒有這個標識則布局不會滾動且其他標識設置無效。
  • enterAlways:任何向下滾動操作都會使此布局可見。這個標識通常被稱為“快速返回”模式。
  • enterAlwaysCollapsed:假設你定義了一個最小高度(minHeight)同時enterAlways也定義了,那么view將在到達這個最小高度的時候開始顯示,並且從這個時候開始慢慢展開,當滾動到頂部的時候展開完。
  • exitUntilCollapsed:當你定義了一個minHeight,此布局將在滾動到達這個最小高度的時候折疊。
  • snap:當一個滾動事件結束,如果視圖是部分可見的,那么它將被滾動到收縮或展開。例如,如果視圖只有底部25%顯示,它將折疊。相反,如果它的底部75%可見,那么它將完全展開。

  實踐證明,scroll和enterAlwaysCollapsed,scroll和exitUntilCollapsed使用時效果無陰影,scroll和enterAlways配合使用時,效果有陰影。

2.CollapsingToolbarLayout中通過layout_collapseMode屬性來指定其內部的子控件是折疊還是固定在屏幕上方。

 <!-- layout_collapseMode(折疊模式)-有兩個值: 1.parallax:在內容滾動時,CollapsingToolbarLayout中的View(比如ImageView)也可以同時滾動, 實現視差滾動效果,通常和layout_collapseParallaxMultiplier(設置視差因子)搭配使用。如果不想實現聯動效果,可以設置為0,效果就和scrollview一樣了 2.pin - 當CollapsingToolbarLayout完全收縮后,Toolbar還可以固定在屏幕上。 -->

xml文件:

<?xml version="1.0" encoding="utf-8"?> <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" xmlns:app="http://schemas.android.com/apk/res-auto" android:orientation="vertical" tools:context="fanggao.qf.collapsingtoolbarlayout.MainActivity"> <!-- android:fitsSystemWindow = "true" 表示整個布局展示是整個屏幕出去狀態欄,標題欄和導航欄剩下的區域--> <android.support.design.widget.AppBarLayout android:id="@+id/layout_appbar" android:layout_width="match_parent" android:layout_height = "wrap_content" > <!-- app:expandedTitleMarginStart="10dp" 設置擴張時候(還沒有收縮時)title離屏幕左邊的距離 app:contentScrim="?attr/colorPrimary" 設置當完全CollapsingToolbarLayout折疊(收縮)后的背景顏色 --> <android.support.design.widget.CollapsingToolbarLayout android:id="@+id/ctb" android:layout_width="match_parent" android:layout_height="250dp" android:fitsSystemWindows="true" app:contentScrim="?attr/colorPrimary" app:expandedTitleMarginStart="10dp" app:layout_scrollFlags="scroll|exitUntilCollapsed"> <ImageView android:id="@+id/image" android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="centerCrop" app:layout_collapseMode="parallax" android:src = "@drawable/cat" /> <!--標題--> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="30dp" app:layout_collapseMode="pin" app:title="Toolbar"/> </android.support.design.widget.CollapsingToolbarLayout> <!--選項卡--> <android.support.design.widget.TabLayout android:id="@+id/tabLayout" android:layout_width="match_parent" android:layout_height="wrap_content" app:tabIndicatorColor="@color/colorAccent" app:tabMode="scrollable" app:tabSelectedTextColor="@color/colorAccent" app:tabTextColor="@android:color/black"/> </android.support.design.widget.AppBarLayout> <android.support.v4.widget.NestedScrollView android:id="@+id/nestedScrollView" android:layout_width="match_parent" android:layout_height="match_parent" android:fillViewport="true" app:layout_behavior="@string/appbar_scrolling_view_behavior"> <android.support.v4.view.ViewPager android:id="@+id/viewPager" android:layout_width="match_parent" android:layout_height="wrap_content"/> </android.support.v4.widget.NestedScrollView> </android.support.design.widget.CoordinatorLayout>

主程序:

public class MainActivity extends AppCompatActivity { private Toolbar toolbar; private ImageView image; private ViewPager viewpager; private TabLayout tabLayout; private CollapsingToolbarLayout collapsingToolbarLayout; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); initData(); } private void initData() { toolbar.setLogo(R.mipmap.ic_launcher); setSupportActionBar(toolbar); //設置返回按鈕
        getSupportActionBar().setDisplayHomeAsUpEnabled(true); //設置收縮展開toolbar字體顏色
 collapsingToolbarLayout.setExpandedTitleColor(Color.WHITE); collapsingToolbarLayout.setCollapsedTitleTextColor(Color.BLACK); //設置tablayout與viewPager
        viewpager.setAdapter(new TestViewPageAdapter()); tabLayout.setupWithViewPager(viewpager); } private void initView() { toolbar = (Toolbar) findViewById(R.id.toolbar); image = (ImageView) findViewById(R.id.image); viewpager = (ViewPager) findViewById(R.id.viewPager); tabLayout = (TabLayout) findViewById(R.id.tabLayout); collapsingToolbarLayout = (CollapsingToolbarLayout) findViewById(R.id.ctb); } class TestViewPageAdapter extends PagerAdapter{ @Override public Object instantiateItem(ViewGroup container, int position) { TextView textView = new TextView(MainActivity.this); textView.setGravity(Gravity.CENTER); textView.setText("pager "+(position+1)); textView.setTextSize(30); textView.setTextColor(Color.BLUE); container.addView(textView); return textView; } @Override public void destroyItem(ViewGroup container, int position, Object object) { container.removeView((View)object); } @Override public int getCount() { return 5; } @Override public boolean isViewFromObject(View view, Object object) { return view == object; } /*獲得標題*/
        /*該方法必須寫,不然tablayout不能顯示標題*/ @Override public CharSequence getPageTitle(int position) { return "TAB"+(position+1); } } }

效果:

滑動前

向下滑動后:

 

 如果有viewpager嵌套fragment的場景,可以在fragment的根布局中加上NestedScrollView,這樣就不會產生滑動沖突事件。如果使用的是ScrollView,會導致上下2個分離,CollapsingToolbarLayout未滑動時,scrollview也可以滑動(不支持嵌套滑動),這樣就跟實際需求背離了。

NestedScrollView參考資料:

https://www.jianshu.com/p/f55abc60a879

 

add:

如何監聽CollapsingToolbarLayout的展開與折疊?

這里我們使用官方提供的AppBarLayout.OnOffsetChangedListener就可以實現了,不過封裝下效果更好。代碼如下。

import com.google.android.material.appbar.AppBarLayout

abstract class AppBarStateChangeListener : AppBarLayout.OnOffsetChangedListener {
    private var mCurrentState = State.IDLE

    enum class State {
        EXPANDED,
        COLLAPSED,
        IDLE
    }

    override fun onOffsetChanged(appBarLayout: AppBarLayout?, i: Int) {
        appBarLayout?.let {
            if (i == 0) {
                if (mCurrentState != State.EXPANDED) {
                    onStateChanged(it, State.EXPANDED)
                }
                mCurrentState = State.EXPANDED
            } else if (Math.abs(i) >= it.totalScrollRange) {
                if (mCurrentState != State.COLLAPSED) {
                    onStateChanged(it, State.COLLAPSED)
                }
                mCurrentState = State.COLLAPSED
            } else {
                if (mCurrentState != State.IDLE) {
                    onStateChanged(it, State.IDLE)
                }
                mCurrentState = State.IDLE
            }
        }
    }



    abstract fun onStateChanged(appBarLayout: AppBarLayout?, state: State)
}
View Code

使用:

 appbar_layout.addOnOffsetChangedListener(object : AppBarStateChangeListener() { override fun onStateChanged(appBarLayout: AppBarLayout?, state: State) { if( state == State.EXPANDED ) { //展開狀態
 }else if(state == State.COLLAPSED){ //折疊狀態 }else{ //中間狀態
 } } })

 

 

FAQ:

1.CoordinatorLayout中的recyclerview下拉刷新卡頓,當從下往上快速滑動時,每次需要等待幾秒才能刷新,怎么解決?

  當recyclerview快速滑動時,不能觸發下拉刷新,這是因為onSrollStateChanged()回調沒有及時調用,當快速滑動時,會調用

SCROLL_STATE_SETTLING(快速滑動)狀態,該狀態等到fling結束才會調用onSrollStateChanged()方法改變為SCROLL_STATE_IDLE(停止)狀態(大概時間為2-3秒)。
 
 recycleviewCars.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); if(newState == RecyclerView.SCROLL_STATE_SETTLING){ recycleviewCars.stopScroll(); } } });

 

 

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM