当前位置:   article > 正文

compose--修饰符Modifier

compose modifier

上次介绍了compose中大多数的标准组件,此外还有两个重要的组件:列表LazyColumnLazyRow,以及约束布局ConstraintLayout,在使用它们之前,先来认识Modifier

修饰符Modifier

Modifier之前已经运用过,它能做的事情很多,不仅仅是改变组件的样式,还能够改变组件的位置,以及自定义交互事件,关于Modifier的所有用法,可以查看官方文档:https://developer.android.google.cn/jetpack/compose/modifiers-list,这边只介绍常用的

一、Modifier顺序

首先我们必须要知道的是:Modifier的设置是有顺序的,下面的代码分别在设置padding之前和之后为Box设置点击事件:

  1. @Preview
  2. @Composable
  3. fun MyModifier1() {
  4. Row(
  5. horizontalArrangement = Arrangement.SpaceAround,
  6. verticalAlignment = Alignment.CenterVertically,
  7. modifier = Modifier.fillMaxSize()
  8. ) {
  9. Box(
  10. modifier = Modifier
  11. .size(100.dp)
  12. .background(
  13. color = MaterialTheme.colorScheme.primary,
  14. shape = MaterialTheme.shapes.medium
  15. )
  16. .clickable {
  17. }
  18. .padding(40.dp)
  19. )
  20. Box(
  21. modifier = Modifier
  22. .size(100.dp)
  23. .background(
  24. color = MaterialTheme.colorScheme.primary,
  25. shape = MaterialTheme.shapes.medium
  26. )
  27. .padding(20.dp)
  28. .clickable {
  29. }
  30. )
  31. }
  32. }

效果如下,左边为padding之前,padding之后,可以看到之后再设置点击事件,整个组件的点击范围变小了:

二、操作

对组件的操作有很多,如点击、长按、双击、拖拽、选中等

1.clickable-点击

clickable之前就使用过了,除了点击外,还有一些其他属性和提供无障碍操作(残疾人)使用:

  1. fun Modifier.clickable(
  2. interactionSource: MutableInteractionSource,// 只有第一次按下才会发送,并更新状态
  3. indication: Indication?,// 按下效果 如水波纹
  4. enabled: Boolean = true,
  5. onClickLabel: String? = null,//无障碍访问标签
  6. role: Role? = null,//为无障碍访问描述元素的类型
  7. onClick: () -> Unit
  8. )
2.combinedClickable-点击、长按、双击

combinedClickable组合了点击、长按、双击:

  1. @ExperimentalFoundationApi
  2. fun Modifier.combinedClickable(
  3. interactionSource: MutableInteractionSource,
  4. indication: Indication?,
  5. enabled: Boolean = true,
  6. onClickLabel: String? = null,
  7. role: Role? = null,
  8. onLongClickLabel: String? = null,
  9. onLongClick: (() -> Unit)? = null,
  10. onDoubleClick: (() -> Unit)? = null,
  11. onClick: () -> Unit
  12. )

例子:

  1. @OptIn(ExperimentalFoundationApi::class)
  2. @Preview
  3. @Composable
  4. fun MyCombineClick() {
  5. val snackbarState by remember { mutableStateOf(SnackbarHostState()) }
  6. val scope = rememberCoroutineScope()
  7. Box(
  8. modifier = Modifier
  9. .fillMaxSize(),
  10. contentAlignment = Alignment.Center
  11. ) {
  12. Text(
  13. text = "点我",
  14. color = Color.White,
  15. modifier = Modifier
  16. .combinedClickable(
  17. onClick = {
  18. scope.launch {
  19. snackbarState.showSnackbar(
  20. "onClick",
  21. duration = SnackbarDuration.Short
  22. )
  23. }
  24. },
  25. onDoubleClick = {
  26. scope.launch {
  27. snackbarState.showSnackbar(
  28. "onDoubleClick",
  29. duration = SnackbarDuration.Short
  30. )
  31. }
  32. },
  33. onLongClick = {
  34. scope.launch {
  35. snackbarState.showSnackbar(
  36. "onLongClick",
  37. duration = SnackbarDuration.Short
  38. )
  39. }
  40. }
  41. )
  42. .background(MaterialTheme.colorScheme.secondary, MaterialTheme.shapes.small)
  43. .padding(10.dp)
  44. )
  45. SnackbarHost(hostState = snackbarState, modifier = Modifier.align(Alignment.BottomCenter))
  46. }
  47. }

效果:

3.draggable-拖拽

draggable让组件可以响应拖动:

  1. fun Modifier.draggable(
  2. state: DraggableState,
  3. orientation: Orientation,// 水平还是竖直方向
  4. enabled: Boolean = true,
  5. interactionSource: MutableInteractionSource? = null,
  6. startDragImmediately: Boolean = false,//是否立即拖动,防止其他手势检测器对“向下”事件做出反应
  7. onDragStarted: suspend CoroutineScope.(startedPosition: Offset) -> Unit = {},//拖动开始
  8. onDragStopped: suspend CoroutineScope.(velocity: Float) -> Unit = {},//拖动结束
  9. reverseDirection: Boolean = false//是否反转方向
  10. )

例子:

  1. @Preview
  2. @Composable
  3. fun MyDraggable() {
  4. var offset by remember { mutableStateOf(0f) }
  5. val state = rememberDraggableState(onDelta = { delta ->
  6. offset += delta
  7. })
  8. Box(
  9. modifier = Modifier.fillMaxSize(),
  10. contentAlignment = Alignment.Center
  11. ) {
  12. Text(
  13. text = "拽我",
  14. modifier = Modifier
  15. .offset { IntOffset(offset.roundToInt(), 0) }//偏移组件
  16. .draggable(
  17. state = state,
  18. orientation = Orientation.Horizontal,// 水平拖拽
  19. )
  20. .background(Color.Cyan, RoundedCornerShape(5.dp))
  21. .padding(10.dp)
  22. )
  23. }
  24. }

效果:

4.swipeable-滑动

swipeable类似于Switch的效果,可以定义多个锚点,以及判定切换锚点滑动的阈值:

  1. @ExperimentalMaterialApi
  2. fun <T> Modifier.swipeable(
  3. state: SwipeableState<T>,
  4. anchors: Map<Float, T>,// 锚点集合
  5. orientation: Orientation,// 可滑动的方向
  6. enabled: Boolean = true,
  7. reverseDirection: Boolean = false,
  8. interactionSource: MutableInteractionSource? = null,
  9. thresholds: (from: T, to: T) -> ThresholdConfig = { _, _ -> FixedThreshold(56.dp) },// 滑动阈值,超于多少就滑动到下个锚点,反之则滑回来
  10. resistance: ResistanceConfig? = resistanceConfig(anchors.keys),
  11. // 滑动手指放开时,距离阈值没达到,但加速度达到阈值,则切换到下个锚点
  12. velocityThreshold: Dp = VelocityThreshold
  13. )

例子:

  1. @OptIn(ExperimentalMaterialApi::class)
  2. @Preview
  3. @Composable
  4. fun MySwipeable() {
  5. // 表示运行到哪个锚点的状态
  6. val swipeableState = rememberSwipeableState(initialValue = 0)
  7. val width = 100.dp
  8. Box(
  9. modifier = Modifier
  10. .width(200.dp)
  11. .border(
  12. 1.dp,
  13. Color.Red,
  14. RoundedCornerShape(5.dp)
  15. )
  16. .swipeable(
  17. state = swipeableState,
  18. anchors = mapOf(//锚点集合,表示每个锚点滑动的距离
  19. 0f to 0,
  20. with(LocalDensity.current) {//dp->px
  21. width.toPx()
  22. } to 1),
  23. orientation = Orientation.Horizontal//水平滑动
  24. ),
  25. contentAlignment = Alignment.TopStart
  26. ) {
  27. Button(
  28. onClick = { /*TODO*/ },
  29. modifier = Modifier
  30. .offset { IntOffset(swipeableState.offset.value.roundToInt(), 0) }// 根据滑动状态进行偏移操作
  31. .width(width) // 按钮宽度也设置为100dp
  32. ) {
  33. Text(text = "滑我", color = Color.White)
  34. }
  35. }
  36. }

效果:

三、对齐方式

除了前面介绍布局时每个布局自带属性的对齐方式外,Modifier也为各个不同的布局作用域(BoxScopeRowScopeColumnScope)设置了单独的布局方式,在这些作用域中,我们可以使用下面的对齐方式

1.BoxScope

align:将内容元素拉取到 Box 中的特定 Alignment

例子:

  1. @Preview
  2. @Composable
  3. fun MyBoxScope() {
  4. Box(modifier = Modifier.fillMaxSize()) {
  5. Button(
  6. onClick = { /*TODO*/ },
  7. modifier = Modifier.align(Alignment.Center)//将组件位于Box的中央
  8. ) {
  9. Text(text = "hi")
  10. }
  11. }
  12. }

效果:

2.RowScope
2.1 align

align:设置元素在Row中的垂直对齐方式:Top顶部、CenterHorizontally垂直居中、End底部

例子:

  1. @Preview
  2. @Composable
  3. fun MyRowScope() {
  4. Row(modifier = Modifier.fillMaxSize()) {
  5. Text(
  6. text = "align-CenterVertically",
  7. modifier = Modifier
  8. .align(Alignment.CenterVertically)
  9. .background(Color.LightGray, RoundedCornerShape(3.dp))
  10. .padding(10.dp)
  11. )
  12. }
  13. }

效果:

2.2 alignBy

alignBy:使其 alignmentLine 与同样配置为 alignBy 的同级元素对齐。

例子:

  1. @Preview
  2. @Composable
  3. fun MyRowScope2() {
  4. Row(modifier = Modifier.fillMaxSize()) {
  5. Text(
  6. text = "align-line1",
  7. modifier = Modifier
  8. .alignBy(FirstBaseline)
  9. .background(Color.LightGray, RoundedCornerShape(3.dp))
  10. .padding(10.dp)
  11. )
  12. Text(
  13. text = "align-line2",
  14. fontSize = 20.sp,
  15. modifier = Modifier
  16. .alignBy(FirstBaseline)
  17. .background(Color.LightGray, RoundedCornerShape(3.dp))
  18. .padding(10.dp)
  19. )
  20. }
  21. }

效果:

ColumnScope也是差不多的使用方式,这边就不做多介绍了

四、动画

1.animateItemPlacement

animateItemPlacement是作用于列表组件下的作用域中,可为列表Item元素添加动画效果

2.animateEnterExit

animateEnterExit:在AnimatedVisibilityScope动画可见作用域中自定义进入和出去的动画效果

例子:

  1. @OptIn(ExperimentalAnimationApi::class)
  2. @Preview
  3. @Composable
  4. fun MyAnimeScope() {
  5. var visible by remember { mutableStateOf(false) }
  6. Row(modifier = Modifier.fillMaxSize()) {
  7. Button(onClick = { visible = !visible }) {
  8. Text(text = "点我")
  9. }
  10. // 带动画的效果组件
  11. AnimatedVisibility(visible = visible) {
  12. Icon(
  13. Icons.Default.Info, contentDescription = null,
  14. // 自己指定进入和出去的动画
  15. modifier = Modifier.animateEnterExit(enter = scaleIn(), exit = scaleOut())
  16. )
  17. }
  18. }
  19. }

效果:

五、边框

border:可以为组件加上一个边框,需要指定Shape背景形状,还支持Brush(Shader(点击跳转详情))

例子:

  1. @Preview
  2. @Composable
  3. fun MyBorder() {
  4. Box(
  5. modifier = Modifier
  6. .size(100.dp)
  7. .padding(start = 10.dp, top = 10.dp)
  8. .border(
  9. 1.dp,// 边框粗细1dp
  10. Brush.linearGradient(
  11. 0f to Color.Cyan.copy(alpha = 0.5f),
  12. 1f to Color.Magenta
  13. ),// 线性渲染
  14. RoundedCornerShape(10.dp)// 形状带圆角
  15. )
  16. )
  17. }

预览效果:

六、绘图

1.alpha

alpha直接改变该组件的透明度:

  1. @Preview
  2. @Composable
  3. fun MyAlpha() {
  4. Row {
  5. Box(
  6. modifier = Modifier
  7. .background(Color.Red)
  8. .size(50.dp)
  9. ) {
  10. }
  11. Box(
  12. modifier = Modifier
  13. .alpha(0.2f)
  14. .background(Color.Red)
  15. .size(50.dp)
  16. ) {
  17. }
  18. }
  19. }

预览效果:

2.drawBehind

drawBehind提供一个画布,用于在绘制在内容后方:

  1. @Preview
  2. @Composable
  3. fun MyDrawBehind() {
  4. Text(
  5. text = "hi",
  6. modifier = Modifier.drawBehind {
  7. // 画个圆形背景
  8. drawCircle(color = Color.Cyan, 10f)
  9. }
  10. )
  11. }

预览效果:

3.clip

clip是将组件内容显示的画布进行裁剪,不可与background同时使用:

  1. @Preview
  2. @Composable
  3. fun MyClip() {
  4. Box(modifier = Modifier.clip(CircleShape)) {
  5. Box(
  6. Modifier
  7. .size(50.dp)
  8. .background(color = Color.Cyan))
  9. }
  10. }

预览效果:

4.drawWithContent

drawWithContent允许开发者在布局内容前后进行绘制,通过drawContent()方法绘制内容:

  1. @Preview
  2. @Composable
  3. fun MyDrawWithContent() {
  4. Text(
  5. text = "hi",
  6. modifier = Modifier.drawWithContent {
  7. // 先绘制内容
  8. this.drawContent()
  9. // 画个圆形背景
  10. drawCircle(color = Color.Cyan, 10f)
  11. }
  12. )
  13. }

预览效果:

5.indication

indication为交互设置效果,如水波纹,该效果在前面clickable等操作中也可以设置,pointerInput在后续指针中:

  1. @Preview
  2. @Composable
  3. fun MyIndication() {
  4. val interactionSource = remember { MutableInteractionSource() }
  5. Text(
  6. text = "hi",
  7. modifier = Modifier
  8. .indication(
  9. interactionSource = interactionSource,
  10. indication = rememberRipple(color = Color.Red) //红色水波纹
  11. )
  12. // 添加手势
  13. .pointerInput(interactionSource, true) {
  14. this.detectTapGestures(
  15. // 按下事件
  16. onPress = { offset ->
  17. val pressInteraction = PressInteraction.Press(offset)
  18. // 触发水波纹
  19. interactionSource.emit(pressInteraction)
  20. }
  21. )
  22. }
  23. .size(100.dp),
  24. textAlign = TextAlign.Center
  25. )
  26. }

效果:

6.paint

paint允许传入一个painter画笔,来对整个组件进行渲染:

  1. fun Modifier.paint(
  2. painter: Painter,
  3. sizeToIntrinsics: Boolean = true,
  4. alignment: Alignment = Alignment.Center,
  5. contentScale: ContentScale = ContentScale.Inside,
  6. alpha: Float = DefaultAlpha,
  7. colorFilter: ColorFilter? = null
  8. )

例子:

  1. @Preview
  2. @Composable
  3. fun MyPaint() {
  4. // 红色画笔
  5. val painter = ColorPainter(Color.Red)
  6. Box(modifier = Modifier.size(100.dp).paint(painter = painter)) {
  7. Text("hi")
  8. }
  9. }

预览效果:

7.shadow

shadow为组件设置一个阴影:

  1. @Stable
  2. fun Modifier.shadow(
  3. elevation: Dp,// 阴影大小
  4. shape: Shape = RectangleShape, //形状
  5. clip: Boolean = elevation > 0.dp,
  6. ambientColor: Color = DefaultShadowColor,
  7. spotColor: Color = DefaultShadowColor,
  8. )

例子:

  1. @Preview
  2. @Composable
  3. fun MyShadow() {
  4. Box(
  5. modifier = Modifier
  6. .size(100.dp),
  7. contentAlignment = Alignment.Center
  8. ) {
  9. Box(
  10. modifier = Modifier
  11. .size(50.dp)
  12. .shadow(2.dp)
  13. ) {
  14. }
  15. }
  16. }

预览效果:

七、焦点

1.onFocusChanged

onFocusChanged可以监听组件焦点的变化,需要和focusRequesterfocusable配合使用:

  1. @Preview
  2. @Composable
  3. fun MyFocus() {
  4. var focused by remember { mutableStateOf(false) }
  5. val focusRequester = remember { FocusRequester() }
  6. Box(
  7. modifier = Modifier.fillMaxSize(),
  8. contentAlignment = Alignment.Center
  9. ) {
  10. Box(
  11. modifier = Modifier
  12. .focusRequester(focusRequester)//绑定焦点请求者
  13. .onFocusChanged { focusStat ->
  14. focused = focusStat.isFocused
  15. }
  16. .focusable()
  17. .size(50.dp)
  18. .background(if (focused) Color.Cyan else Color.Red)
  19. ) {
  20. }
  21. Button(
  22. onClick = { focusRequester.requestFocus() },//点击触发焦点获取
  23. modifier = Modifier.align(Alignment.BottomCenter)
  24. ) {
  25. Text("click")
  26. }
  27. }
  28. }

效果:

八、布局

1.layout

使用layout摆放组件,和传统的自定义控件一样,layout是用于摆放位置的,下面小程序实现功能为基于baseLine进行一个偏移,最后通过重新

  1. fun Modifier.baseLineToTop(
  2. dp: Dp
  3. ) = this.then(//当前Modifier进行组合
  4. layout { measurable, constraints ->
  5. // 预先测量下组件
  6. val placeable = measurable.measure(constraints)
  7. // 获取baseline,为baseline到组件顶部的距离
  8. val baseLine = placeable[FirstBaseline]
  9. // 偏移后,组件的高度 = 原有高度+偏移量-baseline
  10. val height = placeable.height + dp.roundToPx() - baseLine
  11. // 重新定义组件的整体宽高
  12. layout(placeable.width, height) {
  13. //重新摆放组件,y轴进行偏移
  14. placeable.placeRelative(0, dp.roundToPx() - baseLine)
  15. }
  16. }
  17. )
  18. @Preview
  19. @Composable
  20. fun MyCustomLayoutModifier() {
  21. Row {
  22. Text(
  23. "hi",
  24. modifier = Modifier.baseLineToTop(24.dp)
  25. )
  26. Spacer(modifier = Modifier.width(20.dp))
  27. Text(
  28. "hi"
  29. )
  30. }
  31. }

预览效果:

九、内边距

1.absolutePadding

absolutePaddingpadding的区别在于,absolutePadding总认为是从左往右,从上往下摆放控件的,CompositionLocal会在后续进行介绍:

  1. @Preview
  2. @Composable
  3. fun MyPadding() {
  4. CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Rtl) {// 从右往左摆放组件
  5. Row(modifier = Modifier.height(IntrinsicSize.Min)) {
  6. Box(
  7. modifier = Modifier
  8. .size(100.dp)
  9. .padding(10.dp, 10.dp, 20.dp, 10.dp)
  10. .background(Color.Red)
  11. ) {
  12. Text("hi")
  13. }
  14. Divider(
  15. modifier = Modifier
  16. .width(1.dp)
  17. .fillMaxHeight()
  18. )
  19. Box(
  20. modifier = Modifier
  21. .size(100.dp)
  22. .absolutePadding(10.dp, 10.dp, 20.dp, 10.dp)
  23. .background(Color.Blue)
  24. ) {
  25. Text("hi")
  26. }
  27. }
  28. }
  29. }

预览效果,由于进行了反转,蓝色才是使用了absolutePadding

十、指针

除了操作中介绍的几种改变组件交互效果外,还可以使用pointerInput来自定义更自由的操作,它包含了一切触摸事件的监听,并且后续的效果由你自己定义

1.pointerInput

pointerInput就是处理触摸事件的一个修饰,官方推荐传入一个key,来确定何时取消上次的处理

  1. @Preview
  2. @Composable
  3. fun MyPointer() {
  4. var offsetX by remember { mutableStateOf(0f) }
  5. var offsetY by remember { mutableStateOf(0f) }
  6. Box(modifier = Modifier.fillMaxSize()) {
  7. Text(
  8. text = "hi",
  9. color = Color.White,
  10. modifier = Modifier
  11. .offset { IntOffset(offsetX.roundToInt(), offsetY.roundToInt()) }
  12. .background(
  13. MaterialTheme.colorScheme.primary,
  14. MaterialTheme.shapes.medium
  15. )
  16. .padding(10.dp)
  17. .pointerInput(Unit) {
  18. detectTransformGestures { centroid: Offset, pan: Offset, zoom: Float, rotation: Float ->
  19. pan.apply {
  20. offsetX += x
  21. offsetY += y
  22. }
  23. }
  24. },
  25. style = MaterialTheme.typography.labelMedium
  26. )
  27. }
  28. }

效果:

十一、变换

变换的效果包含:旋转,缩放,以及上面使用过的平移

1.rotate

rotate传入一个角度,以旋转组件:

  1. @Preview
  2. @Composable
  3. fun MyTrans() {
  4. var rotationState by remember { mutableStateOf(0f) }
  5. Box(
  6. modifier = Modifier
  7. .rotate(rotationState)
  8. .padding(10.dp)
  9. .size(300.dp)
  10. .background(Color.Red)
  11. .pointerInput(Unit) {
  12. detectTransformGestures { centroid: Offset, pan: Offset, zoom: Float, rotation: Float ->
  13. rotationState += rotation
  14. }
  15. }
  16. )
  17. }

效果:

2.scale

scale可以将组件进行缩放

  1. @Preview
  2. @Composable
  3. fun MyTrans2() {
  4. var scaleState by remember { mutableStateOf(1f) }
  5. Box(
  6. modifier = Modifier
  7. .scale(scaleState)
  8. .padding(10.dp)
  9. .size(300.dp)
  10. .background(Color.Red)
  11. .pointerInput(Unit) {
  12. detectTransformGestures { centroid: Offset, pan: Offset, zoom: Float, rotation: Float ->
  13. scaleState *= zoom
  14. }
  15. }
  16. )
  17. }

效果:

十一、图形

graphicsLayer就是有关组件显示的一切状态,包含了所有变换效果、透明度、背景shape、阴影,配合transformable能够对变换进行快速的处理:

  1. fun Modifier.graphicsLayer(
  2. scaleX: Float,
  3. scaleY: Float,
  4. alpha: Float,
  5. translationX: Float,
  6. translationY: Float,
  7. shadowElevation: Float,
  8. rotationX: Float,
  9. rotationY: Float,
  10. rotationZ: Float,
  11. cameraDistance: Float,
  12. transformOrigin: TransformOrigin,
  13. shape: Shape,
  14. clip: Boolean,
  15. renderEffect: RenderEffect?,
  16. ambientShadowColor: Color,
  17. spotShadowColor: Color
  18. )

例子:

  1. @Preview
  2. @Composable
  3. fun MyGraphicsLayer() {
  4. var scale by remember { mutableStateOf(1f) }
  5. var rotation by remember { mutableStateOf(0f) }
  6. var offset by remember { mutableStateOf(Offset.Zero) }
  7. val transformState =
  8. rememberTransformableState { zoomChange: Float, panChange: Offset, rotationChange: Float ->
  9. scale *= zoomChange
  10. rotation += rotationChange
  11. offset += panChange
  12. }
  13. Box(
  14. modifier = Modifier
  15. .graphicsLayer {
  16. scaleX = scale
  17. scaleY = scale
  18. rotationZ = rotation
  19. translationX = offset.x
  20. translationY = offset.y
  21. }
  22. .padding(10.dp)
  23. .size(300.dp)
  24. .background(Color.Red)
  25. .transformable(transformState)
  26. )
  27. }

效果:

十二、滚动

Modifier还能为组件添加可以滚动的支持,以及内嵌滚动、根据滚动状态显示或隐藏组件的支持

1.verticalScroll

verticalScroll可以让组件支持竖直滑动:

  1. @Preview
  2. @Composable
  3. fun MyScrollable() {
  4. val state = rememberScrollState()
  5. Column(
  6. modifier = Modifier
  7. .padding(10.dp)
  8. .size(300.dp)
  9. .background(MaterialTheme.colorScheme.primary)
  10. .verticalScroll(state)
  11. ) {
  12. repeat(10) { index ->
  13. Text(text = "hi${index}", modifier = Modifier.height(50.dp))
  14. }
  15. }
  16. }

效果:

2.overscroll

overscroll就是给组件加上滚动到边缘的效果:

  1. @OptIn(ExperimentalFoundationApi::class)
  2. @Preview
  3. @Composable
  4. fun MyScrollable2() {
  5. val state = rememberScrollState()
  6. Box(modifier = Modifier.fillMaxSize()) {
  7. Column(
  8. modifier = Modifier
  9. .padding(10.dp)
  10. .size(300.dp)
  11. .verticalScroll(state)
  12. .overscroll(ScrollableDefaults.overscrollEffect())//滑动到顶部和底部的涟漪效果
  13. ) {
  14. repeat(50) { index ->
  15. Text(text = "hi${index}", modifier = Modifier.height(50.dp))
  16. }
  17. }
  18. ExtendedFloatingActionButton(
  19. text = { Text(text = "点我") },
  20. icon = { Icon(Icons.Default.Close, contentDescription = null) },
  21. onClick = { /*TODO*/ },
  22. expanded = state.isScrollInProgress,
  23. modifier = Modifier.align(Alignment.BottomCenter)
  24. )
  25. }
  26. }

效果:

3.nestedScroll

nestedScroll将内容组件的滑动事件进行分享,以达到联动的效果:

  1. @OptIn(ExperimentalFoundationApi::class, ExperimentalMaterial3Api::class)
  2. @Preview
  3. @Composable
  4. fun MyScrollable3() {
  5. val state = rememberScrollState()
  6. val toolbarHeight = 48.dp
  7. val toolbarHeightPx = with(LocalDensity.current) { toolbarHeight.roundToPx().toFloat() }
  8. val toolbarOffsetHeightPx = remember { mutableStateOf(0f) }
  9. val nestedScrollConnection = remember {
  10. object : NestedScrollConnection {
  11. override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {
  12. //y方向的偏移量
  13. val delta = available.y
  14. val newOffset = toolbarOffsetHeightPx.value + delta
  15. toolbarOffsetHeightPx.value = newOffset.coerceIn(-toolbarHeightPx, 0f)
  16. return Offset.Zero
  17. }
  18. }
  19. }
  20. Box(
  21. modifier = Modifier
  22. .fillMaxSize()
  23. .nestedScroll(nestedScrollConnection)
  24. ) {
  25. Column(
  26. modifier = Modifier
  27. .padding(10.dp)
  28. .size(300.dp)
  29. .verticalScroll(state)
  30. .overscroll(ScrollableDefaults.overscrollEffect())//滑动到顶部和底部的涟漪效果
  31. ) {
  32. repeat(50) { index ->
  33. Text(text = "hi${index}", modifier = Modifier.height(50.dp))
  34. }
  35. }
  36. TopAppBar(
  37. modifier = Modifier
  38. .height(toolbarHeight)
  39. .offset { IntOffset(x = 0, y = toolbarOffsetHeightPx.value.roundToInt()) },
  40. title = {
  41. Text(
  42. stringResource(id = R.string.app_name)
  43. )
  44. },
  45. colors = TopAppBarDefaults.smallTopAppBarColors(containerColor = MaterialTheme.colorScheme.primary)
  46. )
  47. }
  48. }

效果:

十三、其他

其他再列举一些常用的修饰

1.blur

blur实现模糊滤镜效果,效果参考传统安卓处理方式:Android滤镜--Alpha值滤镜处理之MaskFilter

  1. @Preview
  2. @Composable
  3. fun MyBlur() {
  4. Row(horizontalArrangement = Arrangement.SpaceAround, modifier = Modifier.fillMaxWidth()) {
  5. Image(
  6. painter = painterResource(id = R.drawable.ic_launcher_background),
  7. contentDescription = null,
  8. modifier = Modifier.blur(50.dp)
  9. )
  10. Image(
  11. painter = painterResource(id = R.drawable.ic_launcher_background),
  12. contentDescription = null
  13. )
  14. }
  15. }

预览效果:

2.pullRefresh

pullRefresh让组件支持下拉刷新,配合PullRefreshState来显示PullRefreshIndicator刷新指示器:

  1. @OptIn(ExperimentalFoundationApi::class, ExperimentalMaterialApi::class)
  2. @Preview
  3. @Composable
  4. fun MyPullRefresh() {
  5. val state = rememberScrollState()
  6. var refreshing by remember { mutableStateOf(false) }
  7. val scope = rememberCoroutineScope()
  8. val refreshState = rememberPullRefreshState(
  9. refreshing = refreshing,
  10. onRefresh = {
  11. scope.launch {
  12. refreshing = true
  13. delay(1500)
  14. refreshing = false
  15. }
  16. }
  17. )
  18. Box(
  19. modifier = Modifier.pullRefresh(refreshState) //下拉刷新
  20. ) {
  21. Column(
  22. modifier = Modifier
  23. .padding(10.dp)
  24. .size(300.dp)
  25. .verticalScroll(state)
  26. .overscroll(ScrollableDefaults.overscrollEffect())//滑动到顶部和底部的涟漪效果
  27. ) {
  28. repeat(50) { index ->
  29. Text(text = "hi${index}", modifier = Modifier.height(50.dp))
  30. }
  31. }
  32. PullRefreshIndicator(// 刷新指示器
  33. refreshing,
  34. refreshState,
  35. modifier = Modifier.align(Alignment.TopCenter)
  36. )
  37. }
  38. }

效果:

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/254114
推荐阅读
相关标签
  

闽ICP备14008679号