当前位置: 首页 > ai >正文

Compose笔记(十九)--NestedScroll

        这一节了解一下Compose中的NestedScroll的使用,NestedScroll 在 Jetpack Compose 里主要用于处理嵌套滚动的场景,也就是当一个可滚动组件嵌套在另一个可滚动组件内部时,能让它们之间的滚动操作协同工作。

API
1. Modifier.nestedScroll()
含义:
为可滚动组件(如 LazyColumn、Box 等)添加嵌套滚动支持,使其能够与其他滚动组件交互。
作用:1)注册嵌套滚动连接:将自定义的 NestedScrollConnection 绑定到组件,定义滚动事件的分发逻辑。 2)协调父子滚动:通过 NestedScrollDispatcher 传递滚动增量(Offset)或抛掷速度(Velocity),实现父子组件的滚动同步或优先级控制。
参数:
connection:实现 NestedScrollConnection的实例,定义滚动事件的响应逻辑。
dispatcher:用于触发嵌套滚动周期(通常由可滚动组件内部提供,无需手动传递)。
2. NestedScrollConnection
含义:定义组件在嵌套滚动事件中的行为,包含四个核心回调方法,分别处理滚动前、滚动后、抛掷前、抛掷后的逻辑。
作用:1)控制滚动分配:决定父组件是否消费部分或全部滚动增量,避免滚动冲突。 2)实现自定义交互:例如折叠工具栏时,优先滚动顶部栏而非内容区域。
回调方法:
onPreScroll(available: Offset, source: NestedScrollSource): Offset
触发条件:子组件滚动前,父组件可优先消费滚动增量。
返回值:父组件实际消费的增量(Offset),未消费部分会传递给子组件。
用途:实现折叠工具栏时,优先折叠顶部栏。
onPostScroll(consumed: Offset, available: Offset, source: NestedScrollSource): Offset
触发条件:子组件滚动后,父组件可响应剩余滚动增量。
返回值:父组件额外消费的增量(通常用于补充滚动)。
用途:子组件滚动到边界后,父组件继续滚动。
onPreFling(available: Velocity): Velocity
触发条件:子组件抛掷(快速滑动)前,父组件可优先消费抛掷速度。
返回值:父组件实际消费的速度(Velocity),未消费部分会传递给子组件。
onPostFling(consumed: Velocity, available: Velocity): Velocity
触发条件:子组件抛掷后,父组件可响应剩余抛掷速度。
返回值:父组件额外消费的速度(通常用于补充抛掷)。

栗子:

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
import androidx.compose.ui.input.nestedscroll.NestedScrollSource
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.unit.dp
import androidx.compose.foundation.rememberScrollState@Composable
fun NestedScrollExample() {// 创建一个嵌套滚动连接val nestedScrollConnection = object : NestedScrollConnection {override fun onPreScroll(available: androidx.compose.ui.geometry.Offset, source: NestedScrollSource): androidx.compose.ui.geometry.Offset {return if (source == NestedScrollSource.Drag && available.y != 0f) {androidx.compose.ui.geometry.Offset(0f, available.y)} else {androidx.compose.ui.geometry.Offset.Zero}}override fun onPostScroll(consumed: androidx.compose.ui.geometry.Offset,available: androidx.compose.ui.geometry.Offset,source: NestedScrollSource): androidx.compose.ui.geometry.Offset {return androidx.compose.ui.geometry.Offset.Zero}}Column(modifier = Modifier.fillMaxSize().nestedScroll(nestedScrollConnection).verticalScroll(rememberScrollState())) {repeat(20) {Text(text = "Vertical Item $it",modifier = Modifier.fillMaxWidth().padding(16.dp).background(Color.LightGray))}Row(modifier = Modifier.fillMaxWidth().height(200.dp).horizontalScroll(rememberScrollState())) {repeat(20) {Text(text = "Horizontal Item $it",modifier = Modifier.padding(16.dp).background(Color.Green))}}}
}
import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.tween
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
import androidx.compose.ui.input.nestedscroll.NestedScrollSource
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.foundation.lazy.rememberLazyListState@Composable
fun NestedScrollExampleTest() {val headerHeight = 200.dpvar headerOffset by remember { mutableStateOf(0.dp) }val lazyListState = rememberLazyListState()val headerOffsetAnimatable = remember { Animatable(0f) }val nestedScrollConnection = remember {object : NestedScrollConnection {override fun onPreScroll(available: androidx.compose.ui.geometry.Offset, source: NestedScrollSource): androidx.compose.ui.geometry.Offset {val delta = available.yval newOffset = (headerOffset.value + delta).coerceIn(-headerHeight.value, 0f)headerOffset = newOffset.dpreturn if (delta > 0 && headerOffset.value < 0) {androidx.compose.ui.geometry.Offset(0f, -delta)} else {androidx.compose.ui.geometry.Offset.Zero}}override fun onPostScroll(consumed: androidx.compose.ui.geometry.Offset,available: androidx.compose.ui.geometry.Offset,source: NestedScrollSource): androidx.compose.ui.geometry.Offset {return androidx.compose.ui.geometry.Offset.Zero}}}LaunchedEffect(headerOffset) {headerOffsetAnimatable.animateTo(targetValue = headerOffset.value,animationSpec = tween(durationMillis = 200))}Column(modifier = Modifier.fillMaxSize().nestedScroll(nestedScrollConnection)) {Box(modifier = Modifier.fillMaxWidth().height(headerHeight).offset(y = headerOffsetAnimatable.value.dp).background(Color.Blue)) {Text(text = "Header",modifier = Modifier.padding(16.dp),color = Color.White)}LazyColumn(state = lazyListState,modifier = Modifier.fillMaxSize()) {items(100) { index ->Text(text = "Item $index",modifier = Modifier.fillMaxWidth().padding(16.dp))}}}
}

注意:
1 顺序问题:在使用多个修饰符时,nestedScroll 修饰符的位置可能会影响滚动行为。一般建议将其放在靠近 scroll 修饰符的位置,以确保嵌套滚动逻辑正确执行。
2 避免过度嵌套:过多的嵌套滚动组件会增加滚动处理的复杂度,降低性能。要尽量减少嵌套层级,保持滚动逻辑的简洁性。
3 保存和恢复滚动状态:在配置更改(如屏幕旋转)时,要确保嵌套滚动的状态能够正确保存和恢复。可以使用 rememberSaveable 来保存关键的滚动状态。

http://www.xdnf.cn/news/2227.html

相关文章:

  • Pygame核心概念解析:Surface、Clock与事件循环
  • 教育领域的AIGC革命:构建多模态智能教学系统
  • Dify + Mermaid 实现自然语言转图表
  • Rule.issuer(通过父路径配置loader处理器)
  • Windows怎样改变鼠标指针方案
  • 使用FME生成Delaunay三角形
  • 《淘宝API数据治理实践:采集字段标准化与数据质量监控体系》
  • 戴维斯双击选股公式如何编写?
  • Makefile---自动化构建和管理项目的文件
  • Java基础 — 循环
  • BS架构与CS架构的对比分析:了解两种架构的不同特点与应用
  • C语言函数调用与声明
  • HTML基础
  • QNX/LINUX/Android系统动态配置动态库.so文件日志打印级别的方法
  • 悟空统计平台在教育行业的落地:课程转化路径优化实践
  • Python 实现从 MP4 视频文件中平均提取指定数量的帧
  • vue3学习之防抖和节流
  • module.noParse(跳过指定文件的依赖解析)
  • Spring Boot安装指南
  • Qt 5.15 编译路径吐槽点
  • QML Date:日期处理示例
  • dijkstra
  • 个人电子白板(svg标签电子画板功能包含正方形、文本、橡皮 (颜色、尺寸、不透明度)、 撤销、取消撤销 等等功能,)
  • 计算机网络基本概念
  • 路由器重分发(OSPF+RIP),RIP充当翻译官,OSPF充当翻译官
  • 强化学习在大模型训练中的应用及策略优化算法详解:以LLM为例
  • 【C++ 类和数据抽象】消息处理示例(1):从设计模式到实战应用
  • Swift与iOS内存管理机制深度剖析
  • Java注解
  • AI辅助设计图转代码开发规范