Compose库中是没有原生的类似RefreshLayout的布局的
于是我们来自己实现一个RefreshLayout
先看看RefreshLayout实现的效果:

使用下拉刷新功能代码很简单(下拉+上拉,包括自定义也很简单):

看一下api:
- /**
- * 可以任意方向拖动刷新的容器
- * @param refreshContent 刷新布局内容区域
- * @param refreshLayoutState RefreshLayout的状态,可以调用[rememberRefreshLayoutState]方法创建state并传入一个刷新时触发的回调
- * @param modifier 修饰
- * @param refreshContentThreshold 刷新布局拖动的阈值,拖动超过多少松开才算真的刷新,如果为null,表示为[refreshContent]的宽或高
- * @param composePosition 设置刷新布局所在的位置,并且间接指定了滑动方向
- * @param contentIsMove content组件是否在刷新时跟着移动,true的效果类似于PullToRefresh,false的效果类似于SwipeRefreshLayout
- * @param dragEfficiency 拖动的'有效率',比如默认是手指拖动20px,只能拖出10px
- * @param isSupportCanNotScrollCompose 是否需要支持无法滚动的组件,为true的话内部会套一层可滚动组件
- * @param userEnable 用户是否可以拖动,等于false时用户拖动无反应,但代码可以修改刷新状态
- * @param content compose内容区域
- */
- @Composable
- fun RefreshLayout()
-
- /**
- * 下拉刷新
- * @param refreshLayoutState RefreshLayout的状态
- * @param modifier 修饰
- * @param refreshContent 刷新布局内容区域
- * @param content compose内容区域
- */
- @Composable
- fun PullToRefresh()
-
- /**
- * 下拉刷新+上拉加载,如果内部不支持上下滑动的话,则无法使用(可以给modifier加上[verticalScroll]修饰)
- * @param topRefreshLayoutState top的刷新布局的state,可以调用[rememberRefreshLayoutState]方法创建state并传入一个刷新时触发的回调
- * @param bottomRefreshLayoutState bottom的刷新布局的state,可以调用[rememberRefreshLayoutState]方法创建state并传入一个刷新时触发的回调
- * @param modifier 修饰
- * @param topRefreshContent top的刷新布局的content,有默认样式,可以传入lambda自定义
- * @param bottomIsLoadFinish bottom刷新布局是否刷新完成
- * @param bottomRefreshContent bottom的刷新布局的content,有默认样式,可以传入lambda自定义
- * @param content 内容
- */
- @Composable
- fun VerticalRefreshableLayout()
原理:
原理其实和安卓xml布局中的RefreshLayout一样,就是通过拦截滑动事件,分配此次事件是父项先用还是子项先用,具体可以参考nestedScroll Modifier,其中传入的connection属性配上下面的注释应该思路就很清晰了:
- val connectionState = remember {
- object : NestedScrollConnection {
- //获取Fling动作结束时的速度
- override suspend fun onPostFling(
- consumed: Velocity,//之前消费的所有速度
- available: Velocity//当前剩下还可用的速度
- ): Velocity {
- //返回:当前组件消费的速度,如果不消费,可以返回Velocity.Zero,否则剩下的速度会继续交由当前布局的父布局进行处理
- return super.onPostFling(consumed, available)
- }
-
- //获取子布局处理后剩下的滑动事件
- override fun onPostScroll(
- consumed: Offset,//被消费的所有滑动事件偏移量
- available: Offset,//当前还剩下可用的滑动事件偏移量
- source: NestedScrollSource//滑动事件的类型
- ): Offset {
- //返回:当前组件消费的滑动事件偏移量,如果不想消费,可以返回Offset.Zero,否则剩下的偏移量会继续交由当前布局的父布局进行处理
- return super.onPostScroll(consumed, available, source)
- }
-
- //获取Fling动作开始时的速度
- override suspend fun onPreFling(
- available: Velocity//Fling动作开始时的速度
- ): Velocity {
- //返回:当前组件消费的速度,如果不消费,可以返回Velocity.Zero
- return super.onPreFling(available)
- }
-
- //可以预先拦截滑动事件,消费后再交由子布局
- override fun onPreScroll(
- available: Offset, //当前可用的滑动事件偏移量
- source: NestedScrollSource//滑动事件的类型
- ): Offset {
- //返回:当前组件消费的滑动事件偏移量,如果不消费,可以返回Offset.Zero
- return super.onPreScroll(available, source)
- }
- }
- }
在根项目的build.gradle文件中加入:
- allprojects {
- repositories {
- maven { url 'https://jitpack.io' }
- ...
- }
- }
app的build.gradle中加上,最新版本参考:JitPack | Publish JVM and Android libraries
- dependencies{
- ...
- implementation 'com.github.ltttttttttttt:ComposeViews:1.1.4'
- }
然后就可以愉快的使用RefreshLayout了
项目已开源,欢迎star:GitHub - ltttttttttttt/ComposeViews
并且项目中不止有FlowLayout,还有更多好用的Compose组件,比如:
ComposePager
Banner
GoodTextField和PasswordTextField
FlowLayout
后续还会添加更多的Compose组件
end
对Kotlin或KMP感兴趣的同学可以进Q群 101786950
如果这篇文章对您有帮助的话
可以扫码请我喝瓶饮料或咖啡(如果对什么比较感兴趣可以在备注里写出来)

