一、前言

简单实现原生自带的滚动折叠效果。

二、简单滚动效果实例

2.1 Toolbar 滚动效果

Toolbar 帮我们实现了标题栏,但是很多时候并不能满足需求,所以不如自定义标题栏好。简单了解下 Toolbar的使用。

  • 滚动效果,效果图:

iShot2020-08-1322.28.48.gif
布局文件:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. xmlns:app="http://schemas.android.com/apk/res-auto">
  6. <com.google.android.material.appbar.AppBarLayout
  7. android:layout_width="match_parent"
  8. android:layout_height="wrap_content">
  9. <androidx.appcompat.widget.Toolbar
  10. android:id="@+id/tb_tb_scroll_tb"
  11. android:layout_width="match_parent"
  12. android:layout_height="wrap_content"
  13. app:navigationIcon="@mipmap/ic_navigation_back_white"
  14. app:title="toolbar滚动"
  15. app:titleTextColor="@color/white"
  16. android:background="@color/blue_74D3FF"
  17. app:layout_scrollFlags="scroll|enterAlways|snap"/>
  18. </com.google.android.material.appbar.AppBarLayout>
  19. <include layout="@layout/content_scrolling"/>
  20. <!-- <androidx.core.widget.NestedScrollView-->
  21. <!-- android:layout_width="match_parent"-->
  22. <!-- android:layout_height="match_parent"-->
  23. <!-- app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">-->
  24. <!-- <TextView-->
  25. <!-- android:layout_width="wrap_content"-->
  26. <!-- android:layout_height="wrap_content"-->
  27. <!-- android:layout_margin="@dimen/m12"-->
  28. <!-- android:text="@string/large_text" />-->
  29. <!-- </androidx.core.widget.NestedScrollView>-->
  30. <!-- 悬浮按钮-->
  31. <com.google.android.material.floatingactionbutton.FloatingActionButton
  32. android:id="@+id/fab_tb_scroll_menu"
  33. android:layout_width="wrap_content"
  34. android:layout_height="wrap_content"
  35. android:layout_gravity="end|bottom"
  36. android:layout_margin="@dimen/m12"
  37. android:src="@mipmap/ic_navigation_menu"/>
  38. </androidx.coordinatorlayout.widget.CoordinatorLayout>
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
  3. xmlns:app="http://schemas.android.com/apk/res-auto"
  4. xmlns:tools="http://schemas.android.com/tools"
  5. android:layout_width="match_parent"
  6. android:layout_height="match_parent"
  7. app:layout_behavior="@string/appbar_scrolling_view_behavior"
  8. >
  9. <TextView
  10. android:layout_width="wrap_content"
  11. android:layout_height="wrap_content"
  12. android:layout_margin="@dimen/m12"
  13. android:text="@string/large_text" />
  14. </androidx.core.widget.NestedScrollView>

2.2 简单折叠布局

效果图:
iShot2020-08-1323.13.13.gif
布局:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. xmlns:app="http://schemas.android.com/apk/res-auto">
  6. <com.google.android.material.appbar.AppBarLayout
  7. android:id="@+id/abl_collaspone_appbar"
  8. android:layout_width="match_parent"
  9. android:layout_height="250dp"
  10. android:background="@color/red_FF8EB7">
  11. <com.google.android.material.appbar.CollapsingToolbarLayout
  12. android:id="@+id/ctl_collaspone_collapsing"
  13. android:layout_width="match_parent"
  14. android:layout_height="match_parent"
  15. app:contentScrim="@color/blue_74D3FF"
  16. app:layout_scrollFlags="scroll|exitUntilCollapsed">
  17. <ImageView
  18. android:layout_width="match_parent"
  19. android:layout_height="match_parent"
  20. android:src="@mipmap/image13"
  21. android:scaleType="centerCrop"
  22. app:layout_collapseMode="parallax"/>
  23. <androidx.appcompat.widget.Toolbar
  24. android:id="@+id/tb_collaspingone_tb"
  25. android:layout_width="match_parent"
  26. android:layout_height="?attr/actionBarSize"
  27. app:layout_collapseMode="pin"
  28. app:titleTextColor="@color/white"
  29. app:navigationIcon="@mipmap/ic_navigation_back_white"/>
  30. </com.google.android.material.appbar.CollapsingToolbarLayout>
  31. </com.google.android.material.appbar.AppBarLayout>
  32. <include layout="@layout/content_scrolling"/>
  33. <com.google.android.material.floatingactionbutton.FloatingActionButton
  34. android:id="@+id/fab_collaspingone_fab"
  35. android:layout_width="wrap_content"
  36. android:layout_height="wrap_content"
  37. android:src="@drawable/ic_cloud"
  38. app:layout_anchor="@id/abl_collaspone_appbar"
  39. app:layout_anchorGravity="end|bottom"
  40. android:layout_margin="@dimen/m10"/>
  41. </androidx.coordinatorlayout.widget.CoordinatorLayout>

Activity:

  1. class CollapsingOneActivity: AppCompatActivity() {
  2. override fun onCreate(savedInstanceState: Bundle?) {
  3. super.onCreate(savedInstanceState)
  4. setContentView(R.layout.activity_collasping_one)
  5. /*
  6. layout_collapseMode: 用来指当前控件在 CollapsingToolbarLayout 在折叠过程中的折叠模式,
  7. 其中 Toolbar 指定成 pin, 表示在折叠过程中位置始终保持不变,
  8. ImageView 指定成 parallax,表示在折叠过程中会有一定的错位偏移
  9. */
  10. fab_collaspingone_fab.setOnClickListener {
  11. Snackbar.make(fab_collaspingone_fab,"hello",Snackbar.LENGTH_SHORT)
  12. .show()
  13. }
  14. tb_collaspingone_tb.setNavigationOnClickListener {
  15. finish()
  16. }
  17. }
  18. }

2.3 透明状态栏简单折叠布局

效果图:
iShot2020-08-1323.24.59.gif
布局:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. xmlns:app="http://schemas.android.com/apk/res-auto"
  4. android:layout_width="match_parent"
  5. android:layout_height="match_parent"
  6. android:fitsSystemWindows="true">
  7. <com.google.android.material.appbar.AppBarLayout
  8. android:id="@+id/abl_collaspone_appbar"
  9. android:layout_width="match_parent"
  10. android:layout_height="250dp"
  11. android:background="@color/red_FF8EB7"
  12. android:fitsSystemWindows="true">
  13. <com.google.android.material.appbar.CollapsingToolbarLayout
  14. android:id="@+id/ctl_collaspone_collapsing"
  15. android:layout_width="match_parent"
  16. android:layout_height="match_parent"
  17. android:fitsSystemWindows="true"
  18. app:contentScrim="@color/blue_74D3FF"
  19. app:layout_scrollFlags="scroll|exitUntilCollapsed">
  20. <ImageView
  21. android:layout_width="match_parent"
  22. android:layout_height="match_parent"
  23. android:fitsSystemWindows="true"
  24. android:scaleType="centerCrop"
  25. android:src="@mipmap/image13"
  26. app:layout_collapseMode="parallax" />
  27. <androidx.appcompat.widget.Toolbar
  28. android:id="@+id/tb_collaspingone_tb"
  29. android:layout_width="match_parent"
  30. android:layout_height="?attr/actionBarSize"
  31. app:layout_collapseMode="pin"
  32. app:navigationIcon="@mipmap/ic_navigation_back_white"
  33. app:titleTextColor="@color/white" />
  34. </com.google.android.material.appbar.CollapsingToolbarLayout>
  35. </com.google.android.material.appbar.AppBarLayout>
  36. <include layout="@layout/content_scrolling" />
  37. <com.google.android.material.floatingactionbutton.FloatingActionButton
  38. android:id="@+id/fab_collaspingone_fab"
  39. android:layout_width="wrap_content"
  40. android:layout_height="wrap_content"
  41. android:layout_margin="@dimen/m10"
  42. android:src="@drawable/ic_cloud"
  43. app:layout_anchor="@id/abl_collaspone_appbar"
  44. app:layout_anchorGravity="end|bottom" />
  45. </androidx.coordinatorlayout.widget.CoordinatorLayout>

Activity:

  1. class CollapsingOneActivity: AppCompatActivity() {
  2. override fun onCreate(savedInstanceState: Bundle?) {
  3. super.onCreate(savedInstanceState)
  4. setContentView(R.layout.activity_collasping_one)
  5. //设置沉浸式状态栏,可以设置状态栏颜色
  6. StatusBarUtils.initStatusBarStyle(this,true)
  7. /*
  8. layout_collapseMode: 用来指当前控件在 CollapsingToolbarLayout 在折叠过程中的折叠模式,
  9. 其中 Toolbar 指定成 pin, 表示在折叠过程中位置始终保持不变,
  10. ImageView 指定成 parallax,表示在折叠过程中会有一定的错位偏移
  11. */
  12. fab_collaspingone_fab.setOnClickListener {
  13. Snackbar.make(fab_collaspingone_fab,"hello",Snackbar.LENGTH_SHORT)
  14. .show()
  15. }
  16. tb_collaspingone_tb.setNavigationOnClickListener {
  17. finish()
  18. }
  19. }
  20. }

2.3 透明状态栏简单折叠布局带标题

设置折叠时标题居中无效,会因为设置了返回按钮而偏向右边,效果图:
iShot2020-08-1611.22.36.gif
布局和上面完全一样,可以在 xml 中设置图标相关,也可以在代码中设置,在代码中设置如下:

  1. //折叠标题设置
  2. ctl_collaspone_collapsing.title = "测试标题"
  3. ctl_collaspone_collapsing.collapsedTitleGravity = Gravity.START
  4. ctl_collaspone_collapsing.expandedTitleGravity = Gravity.BOTTOM
  5. ctl_collaspone_collapsing.setCollapsedTitleTextColor(ContextCompat.getColor(this,R.color.red))
  6. ctl_collaspone_collapsing.setExpandedTitleColor(ContextCompat.getColor(this,R.color.blue_74D3FF))

三、加上刷新

    1. 第一种,刷新和折叠布局平级,适用于折叠布局不是很高的情况

效果图:
iShot2020-08-1721.56.14.gif
xml 布局:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. xmlns:tools="http://schemas.android.com/tools"
  4. android:layout_width="match_parent"
  5. android:layout_height="match_parent"
  6. xmlns:app="http://schemas.android.com/apk/res-auto">
  7. <com.google.android.material.appbar.AppBarLayout
  8. android:id="@+id/appbar_refresh_appbar"
  9. android:layout_width="match_parent"
  10. android:layout_height="250dp"
  11. android:background="@color/red_FF8EB7"
  12. >
  13. <com.google.android.material.appbar.CollapsingToolbarLayout
  14. android:layout_width="match_parent"
  15. android:layout_height="match_parent"
  16. app:contentScrim="@color/blue_74D3FF"
  17. app:layout_scrollFlags="scroll|exitUntilCollapsed"
  18. >
  19. <ImageView
  20. android:layout_width="match_parent"
  21. android:layout_height="match_parent"
  22. android:scaleType="centerCrop"
  23. android:src="@mipmap/image13"
  24. app:layout_collapseMode="parallax" />
  25. <androidx.appcompat.widget.Toolbar
  26. android:id="@+id/tb_collaspingone_tb"
  27. android:layout_width="match_parent"
  28. android:layout_height="?attr/actionBarSize"
  29. app:layout_collapseMode="pin"
  30. app:navigationIcon="@mipmap/ic_navigation_back_white"
  31. app:titleTextColor="@color/white"
  32. />
  33. </com.google.android.material.appbar.CollapsingToolbarLayout>
  34. </com.google.android.material.appbar.AppBarLayout>
  35. <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
  36. android:id="@+id/srl_refresh_refresh"
  37. android:layout_width="match_parent"
  38. android:layout_height="match_parent"
  39. app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
  40. >
  41. <androidx.recyclerview.widget.RecyclerView
  42. android:id="@+id/rv_refresh_refresh"
  43. android:layout_width="match_parent"
  44. android:layout_height="wrap_content"/>
  45. </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
  46. <com.google.android.material.floatingactionbutton.FloatingActionButton
  47. android:id="@+id/fab_refresh_fab"
  48. android:layout_width="wrap_content"
  49. android:layout_height="wrap_content"
  50. android:layout_margin="@dimen/m10"
  51. android:src="@drawable/ic_cloud"
  52. app:layout_anchor="@id/appbar_refresh_appbar"
  53. app:layout_anchorGravity="end|bottom" />
  54. </androidx.coordinatorlayout.widget.CoordinatorLayout>

activity:

  1. class RefreshActivity:AppCompatActivity() {
  2. val list = arrayListOf("测试数据一","测试数据二","测试数据三","测试数据四","测试数据五","测试数据六"
  3. ,"测试数据七","测试数据八","测试数据九","测试数据一","测试数据二","测试数据三","测试数据四","测试数据五","测试数据六"
  4. ,"测试数据七","测试数据八","测试数据九")
  5. val mAdapter by lazy { RefreshAdapter() }
  6. override fun onCreate(savedInstanceState: Bundle?) {
  7. super.onCreate(savedInstanceState)
  8. setContentView(R.layout.activity_refresh)
  9. rv_refresh_refresh?.run {
  10. layoutManager = LinearLayoutManager(this@RefreshActivity)
  11. adapter = mAdapter
  12. setHasFixedSize(true)
  13. }
  14. mAdapter.setList(list)
  15. //mAdapter.setNewInstance()
  16. srl_refresh_refresh.setOnRefreshListener {
  17. srl_refresh_refresh.postDelayed({
  18. srl_refresh_refresh.isRefreshing = false
  19. },1000)
  20. }
  21. fab_refresh_fab.setOnClickListener {
  22. Snackbar.make(fab_refresh_fab,"hello", Snackbar.LENGTH_SHORT)
  23. .show()
  24. }
  25. }
  26. }

adapter:

  1. class RefreshAdapter(layoutId: Int = R.layout.item_refresh)
  2. : BaseQuickAdapter<String,BaseViewHolder>(layoutId){
  3. override fun convert(holder: BaseViewHolder, item: String) {
  4. holder.itemView.tv_item_refresh_text.text = item
  5. }
  6. }
    1. 刷新放在最外层,需要处理滑动冲突

效果图:
iShot2020-08-1721.59.35.gif
布局:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
  3. android:id="@+id/srl_refresh_refresh"
  4. xmlns:android="http://schemas.android.com/apk/res/android"
  5. xmlns:tools="http://schemas.android.com/tools"
  6. android:layout_width="match_parent"
  7. android:layout_height="match_parent"
  8. xmlns:app="http://schemas.android.com/apk/res-auto">
  9. <androidx.coordinatorlayout.widget.CoordinatorLayout
  10. android:layout_width="match_parent"
  11. android:layout_height="match_parent">
  12. <com.google.android.material.appbar.AppBarLayout
  13. android:id="@+id/appbar_refresh_appbar"
  14. android:layout_width="match_parent"
  15. android:layout_height="250dp"
  16. android:background="@color/red_FF8EB7"
  17. >
  18. <com.google.android.material.appbar.CollapsingToolbarLayout
  19. android:layout_width="match_parent"
  20. android:layout_height="match_parent"
  21. app:contentScrim="@color/blue_74D3FF"
  22. app:layout_scrollFlags="scroll|exitUntilCollapsed"
  23. >
  24. <ImageView
  25. android:layout_width="match_parent"
  26. android:layout_height="match_parent"
  27. android:scaleType="centerCrop"
  28. android:src="@mipmap/image13"
  29. app:layout_collapseMode="parallax" />
  30. <androidx.appcompat.widget.Toolbar
  31. android:id="@+id/tb_collaspingone_tb"
  32. android:layout_width="match_parent"
  33. android:layout_height="?attr/actionBarSize"
  34. app:layout_collapseMode="pin"
  35. app:navigationIcon="@mipmap/ic_navigation_back_white"
  36. app:titleTextColor="@color/white"
  37. />
  38. </com.google.android.material.appbar.CollapsingToolbarLayout>
  39. </com.google.android.material.appbar.AppBarLayout>
  40. <androidx.recyclerview.widget.RecyclerView
  41. android:id="@+id/rv_refresh_refresh"
  42. android:layout_width="match_parent"
  43. android:layout_height="match_parent"
  44. app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"/>
  45. <com.google.android.material.floatingactionbutton.FloatingActionButton
  46. android:id="@+id/fab_refresh_fab"
  47. android:layout_width="wrap_content"
  48. android:layout_height="wrap_content"
  49. android:layout_margin="@dimen/m10"
  50. android:src="@drawable/ic_cloud"
  51. app:layout_anchor="@id/appbar_refresh_appbar"
  52. app:layout_anchorGravity="end|bottom" />
  53. </androidx.coordinatorlayout.widget.CoordinatorLayout>
  54. </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

activity:

  1. class Refresh2Activity:AppCompatActivity() {
  2. val list = arrayListOf("测试数据一","测试数据二","测试数据三","测试数据四","测试数据五","测试数据六"
  3. ,"测试数据七","测试数据八","测试数据九","测试数据一","测试数据二","测试数据三","测试数据四","测试数据五","测试数据六"
  4. ,"测试数据七","测试数据八","测试数据九")
  5. val mAdapter by lazy { RefreshAdapter() }
  6. override fun onCreate(savedInstanceState: Bundle?) {
  7. super.onCreate(savedInstanceState)
  8. setContentView(R.layout.activity_refresh2)
  9. rv_refresh_refresh?.run {
  10. layoutManager = LinearLayoutManager(this@Refresh2Activity)
  11. adapter = mAdapter
  12. setHasFixedSize(true)
  13. }
  14. mAdapter.setList(list)
  15. //mAdapter.setNewInstance()
  16. srl_refresh_refresh.setOnRefreshListener {
  17. srl_refresh_refresh.postDelayed({
  18. srl_refresh_refresh.isRefreshing = false
  19. },1000)
  20. }
  21. //下拉刷新和下拉会有冲突
  22. appbar_refresh_appbar.addOnOffsetChangedListener(object : AppBarStateChangeListener(){
  23. override fun onStateChanged(appBarLayout: AppBarLayout?, state: State?) {
  24. if( state == State.EXPANDED ) {
  25. //展开状态
  26. srl_refresh_refresh.isEnabled = true
  27. }else if(state == State.COLLAPSED){
  28. //折叠状态
  29. srl_refresh_refresh.isEnabled = false
  30. }else {
  31. //中间状态
  32. srl_refresh_refresh.isEnabled = false
  33. }
  34. }
  35. })
  36. //悬浮按钮
  37. fab_refresh_fab.setOnClickListener {
  38. Snackbar.make(fab_refresh_fab,"hello", Snackbar.LENGTH_SHORT)
  39. .show()
  40. }
  41. }
  42. }

AppBarStateChangeListener:

  1. public abstract class AppBarStateChangeListener implements AppBarLayout.OnOffsetChangedListener {
  2. public enum State {
  3. EXPANDED,
  4. COLLAPSED,
  5. IDLE
  6. }
  7. private State mCurrentState = State.IDLE;
  8. @Override
  9. public final void onOffsetChanged(AppBarLayout appBarLayout, int i) {
  10. if (i == 0) {
  11. if (mCurrentState != State.EXPANDED) {
  12. onStateChanged(appBarLayout, State.EXPANDED);
  13. }
  14. mCurrentState = State.EXPANDED;
  15. } else if (Math.abs(i) >= appBarLayout.getTotalScrollRange()) {
  16. if (mCurrentState != State.COLLAPSED) {
  17. onStateChanged(appBarLayout, State.COLLAPSED);
  18. }
  19. mCurrentState = State.COLLAPSED;
  20. } else {
  21. if (mCurrentState != State.IDLE) {
  22. onStateChanged(appBarLayout, State.IDLE);
  23. }
  24. mCurrentState = State.IDLE;
  25. }
  26. }
  27. public abstract void onStateChanged(AppBarLayout appBarLayout, State state);
  28. }

四、地址和参考

demo
实现折叠式Toolbar:CollapsingToolbarLayout 使用完全解析
链接