一、前言
二、简单滚动效果实例
2.1 Toolbar 滚动效果
Toolbar 帮我们实现了标题栏,但是很多时候并不能满足需求,所以不如自定义标题栏好。简单了解下 Toolbar的使用。
- 滚动效果,效果图:
布局文件:
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout 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">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.appcompat.widget.Toolbar
android:id="@+id/tb_tb_scroll_tb"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:navigationIcon="@mipmap/ic_navigation_back_white"
app:title="toolbar滚动"
app:titleTextColor="@color/white"
android:background="@color/blue_74D3FF"
app:layout_scrollFlags="scroll|enterAlways|snap"/>
</com.google.android.material.appbar.AppBarLayout>
<include layout="@layout/content_scrolling"/>
<!-- <androidx.core.widget.NestedScrollView-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="match_parent"-->
<!-- app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">-->
<!-- <TextView-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:layout_margin="@dimen/m12"-->
<!-- android:text="@string/large_text" />-->
<!-- </androidx.core.widget.NestedScrollView>-->
<!-- 悬浮按钮-->
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab_tb_scroll_menu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|bottom"
android:layout_margin="@dimen/m12"
android:src="@mipmap/ic_navigation_menu"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView 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"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/m12"
android:text="@string/large_text" />
</androidx.core.widget.NestedScrollView>
2.2 简单折叠布局
效果图:
布局:
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout 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">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/abl_collaspone_appbar"
android:layout_width="match_parent"
android:layout_height="250dp"
android:background="@color/red_FF8EB7">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/ctl_collaspone_collapsing"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:contentScrim="@color/blue_74D3FF"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@mipmap/image13"
android:scaleType="centerCrop"
app:layout_collapseMode="parallax"/>
<androidx.appcompat.widget.Toolbar
android:id="@+id/tb_collaspingone_tb"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:titleTextColor="@color/white"
app:navigationIcon="@mipmap/ic_navigation_back_white"/>
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<include layout="@layout/content_scrolling"/>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab_collaspingone_fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_cloud"
app:layout_anchor="@id/abl_collaspone_appbar"
app:layout_anchorGravity="end|bottom"
android:layout_margin="@dimen/m10"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
Activity:
class CollapsingOneActivity: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_collasping_one)
/*
layout_collapseMode: 用来指当前控件在 CollapsingToolbarLayout 在折叠过程中的折叠模式,
其中 Toolbar 指定成 pin, 表示在折叠过程中位置始终保持不变,
ImageView 指定成 parallax,表示在折叠过程中会有一定的错位偏移
*/
fab_collaspingone_fab.setOnClickListener {
Snackbar.make(fab_collaspingone_fab,"hello",Snackbar.LENGTH_SHORT)
.show()
}
tb_collaspingone_tb.setNavigationOnClickListener {
finish()
}
}
}
2.3 透明状态栏简单折叠布局
效果图:
布局:
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.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:fitsSystemWindows="true">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/abl_collaspone_appbar"
android:layout_width="match_parent"
android:layout_height="250dp"
android:background="@color/red_FF8EB7"
android:fitsSystemWindows="true">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/ctl_collaspone_collapsing"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
app:contentScrim="@color/blue_74D3FF"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:scaleType="centerCrop"
android:src="@mipmap/image13"
app:layout_collapseMode="parallax" />
<androidx.appcompat.widget.Toolbar
android:id="@+id/tb_collaspingone_tb"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:navigationIcon="@mipmap/ic_navigation_back_white"
app:titleTextColor="@color/white" />
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<include layout="@layout/content_scrolling" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab_collaspingone_fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/m10"
android:src="@drawable/ic_cloud"
app:layout_anchor="@id/abl_collaspone_appbar"
app:layout_anchorGravity="end|bottom" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
Activity:
class CollapsingOneActivity: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_collasping_one)
//设置沉浸式状态栏,可以设置状态栏颜色
StatusBarUtils.initStatusBarStyle(this,true)
/*
layout_collapseMode: 用来指当前控件在 CollapsingToolbarLayout 在折叠过程中的折叠模式,
其中 Toolbar 指定成 pin, 表示在折叠过程中位置始终保持不变,
ImageView 指定成 parallax,表示在折叠过程中会有一定的错位偏移
*/
fab_collaspingone_fab.setOnClickListener {
Snackbar.make(fab_collaspingone_fab,"hello",Snackbar.LENGTH_SHORT)
.show()
}
tb_collaspingone_tb.setNavigationOnClickListener {
finish()
}
}
}
2.3 透明状态栏简单折叠布局带标题
设置折叠时标题居中无效,会因为设置了返回按钮而偏向右边,效果图:
布局和上面完全一样,可以在 xml 中设置图标相关,也可以在代码中设置,在代码中设置如下:
//折叠标题设置
ctl_collaspone_collapsing.title = "测试标题"
ctl_collaspone_collapsing.collapsedTitleGravity = Gravity.START
ctl_collaspone_collapsing.expandedTitleGravity = Gravity.BOTTOM
ctl_collaspone_collapsing.setCollapsedTitleTextColor(ContextCompat.getColor(this,R.color.red))
ctl_collaspone_collapsing.setExpandedTitleColor(ContextCompat.getColor(this,R.color.blue_74D3FF))
三、加上刷新
- 第一种,刷新和折叠布局平级,适用于折叠布局不是很高的情况
效果图:
xml 布局:
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.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">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar_refresh_appbar"
android:layout_width="match_parent"
android:layout_height="250dp"
android:background="@color/red_FF8EB7"
>
<com.google.android.material.appbar.CollapsingToolbarLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:contentScrim="@color/blue_74D3FF"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
>
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:src="@mipmap/image13"
app:layout_collapseMode="parallax" />
<androidx.appcompat.widget.Toolbar
android:id="@+id/tb_collaspingone_tb"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:navigationIcon="@mipmap/ic_navigation_back_white"
app:titleTextColor="@color/white"
/>
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/srl_refresh_refresh"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_refresh_refresh"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab_refresh_fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/m10"
android:src="@drawable/ic_cloud"
app:layout_anchor="@id/appbar_refresh_appbar"
app:layout_anchorGravity="end|bottom" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
activity:
class RefreshActivity:AppCompatActivity() {
val list = arrayListOf("测试数据一","测试数据二","测试数据三","测试数据四","测试数据五","测试数据六"
,"测试数据七","测试数据八","测试数据九","测试数据一","测试数据二","测试数据三","测试数据四","测试数据五","测试数据六"
,"测试数据七","测试数据八","测试数据九")
val mAdapter by lazy { RefreshAdapter() }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_refresh)
rv_refresh_refresh?.run {
layoutManager = LinearLayoutManager(this@RefreshActivity)
adapter = mAdapter
setHasFixedSize(true)
}
mAdapter.setList(list)
//mAdapter.setNewInstance()
srl_refresh_refresh.setOnRefreshListener {
srl_refresh_refresh.postDelayed({
srl_refresh_refresh.isRefreshing = false
},1000)
}
fab_refresh_fab.setOnClickListener {
Snackbar.make(fab_refresh_fab,"hello", Snackbar.LENGTH_SHORT)
.show()
}
}
}
adapter:
class RefreshAdapter(layoutId: Int = R.layout.item_refresh)
: BaseQuickAdapter<String,BaseViewHolder>(layoutId){
override fun convert(holder: BaseViewHolder, item: String) {
holder.itemView.tv_item_refresh_text.text = item
}
}
- 刷新放在最外层,需要处理滑动冲突
效果图:
布局:
<?xml version="1.0" encoding="utf-8"?>
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/srl_refresh_refresh"
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">
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar_refresh_appbar"
android:layout_width="match_parent"
android:layout_height="250dp"
android:background="@color/red_FF8EB7"
>
<com.google.android.material.appbar.CollapsingToolbarLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:contentScrim="@color/blue_74D3FF"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
>
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:src="@mipmap/image13"
app:layout_collapseMode="parallax" />
<androidx.appcompat.widget.Toolbar
android:id="@+id/tb_collaspingone_tb"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:navigationIcon="@mipmap/ic_navigation_back_white"
app:titleTextColor="@color/white"
/>
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_refresh_refresh"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"/>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab_refresh_fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/m10"
android:src="@drawable/ic_cloud"
app:layout_anchor="@id/appbar_refresh_appbar"
app:layout_anchorGravity="end|bottom" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
activity:
class Refresh2Activity:AppCompatActivity() {
val list = arrayListOf("测试数据一","测试数据二","测试数据三","测试数据四","测试数据五","测试数据六"
,"测试数据七","测试数据八","测试数据九","测试数据一","测试数据二","测试数据三","测试数据四","测试数据五","测试数据六"
,"测试数据七","测试数据八","测试数据九")
val mAdapter by lazy { RefreshAdapter() }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_refresh2)
rv_refresh_refresh?.run {
layoutManager = LinearLayoutManager(this@Refresh2Activity)
adapter = mAdapter
setHasFixedSize(true)
}
mAdapter.setList(list)
//mAdapter.setNewInstance()
srl_refresh_refresh.setOnRefreshListener {
srl_refresh_refresh.postDelayed({
srl_refresh_refresh.isRefreshing = false
},1000)
}
//下拉刷新和下拉会有冲突
appbar_refresh_appbar.addOnOffsetChangedListener(object : AppBarStateChangeListener(){
override fun onStateChanged(appBarLayout: AppBarLayout?, state: State?) {
if( state == State.EXPANDED ) {
//展开状态
srl_refresh_refresh.isEnabled = true
}else if(state == State.COLLAPSED){
//折叠状态
srl_refresh_refresh.isEnabled = false
}else {
//中间状态
srl_refresh_refresh.isEnabled = false
}
}
})
//悬浮按钮
fab_refresh_fab.setOnClickListener {
Snackbar.make(fab_refresh_fab,"hello", Snackbar.LENGTH_SHORT)
.show()
}
}
}
AppBarStateChangeListener:
public abstract class AppBarStateChangeListener implements AppBarLayout.OnOffsetChangedListener {
public enum State {
EXPANDED,
COLLAPSED,
IDLE
}
private State mCurrentState = State.IDLE;
@Override
public final void onOffsetChanged(AppBarLayout appBarLayout, int i) {
if (i == 0) {
if (mCurrentState != State.EXPANDED) {
onStateChanged(appBarLayout, State.EXPANDED);
}
mCurrentState = State.EXPANDED;
} else if (Math.abs(i) >= appBarLayout.getTotalScrollRange()) {
if (mCurrentState != State.COLLAPSED) {
onStateChanged(appBarLayout, State.COLLAPSED);
}
mCurrentState = State.COLLAPSED;
} else {
if (mCurrentState != State.IDLE) {
onStateChanged(appBarLayout, State.IDLE);
}
mCurrentState = State.IDLE;
}
}
public abstract void onStateChanged(AppBarLayout appBarLayout, State state);
}