详解Jetpack Compose中的Modifier修饰符

这篇具有很好参考价值的文章主要介绍了详解Jetpack Compose中的Modifier修饰符。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

        本文将会介绍Jetpack Compose中的Modifier。在谷歌官方文档中它的描述是这么一句话:Modifier元素是一个有序、不可变的集合,它可以往Jetpack Compose UI元素中添加修饰或者各种行为。例如,背景、填充和单击事件监听器装饰或添加行为到文本或按钮。  

        Modifier修饰符的作用是快速的修改组件的显示大小、边距、边框、背景颜色、剪裁、点击等等,Modifier在Compose的全部组件上都有存在,需要熟练的掌握。另外Modifier是可以被扩展函数扩展的,所以此篇博客只举例通用的Modifier,不举例只在某些组件下才能使用的Modifier修饰符(例如Box(align属性)与constraintlayout(constrainAs方法))。

        Modifier 可以通过链式调用的写法来为组件应用一系列的样式,每个基础的 Composable 组件都有一个 modifier 属性。

有序性

官方对修饰符定义的这个特性包含两个层面的意思,一是修饰符的使用是链式的它是有先后排列顺序的,二是这些顺序不仅仅是排列上的先后同时也是属性对UI展示效果起作用的先后顺序。接下来举一个例子来说明修饰符的有序的特性。

Box {
  val padding = 16.dp
  val onClick = Unit;
  Box(
      Modifier
          .clickable(onClick = { onClick })
          .padding(padding)
          .align(Alignment.Center)
          .size(50.dp, 50.dp)
          .background(Color.Green)
  )
}
Box {
    val padding = 16.dp
    val onClick = Unit;
    Box(
        Modifier
            .padding(padding)
            .clickable(onClick = { onClick })
            .align(Alignment.Center)
            .size(50.dp, 50.dp)
            .background(Color.Green)
    )
}

上面两段代码的意思都是在一个绿色背景宽高为50,50的Box控件中设置点击事件和Padding。首先我们可以直观的看到修饰符的使用是链式的符合咱们说的第一个有序性。可以清楚的看到第一张图波纹是作用范围是涵盖了边距的而第二张水波动画的范围仅仅作用在绿色矩形内部。第一段代码是先设置的点击事件而后设置的边距,而第二段代码是先设置边距而后设置了点击事件,就出现了不同的动画表现。我们通过这个例子就可以直观的看到修饰符的第二个有序性,也就是修饰属性对于UI展示作用的有序性,即属性发生作用的先后顺序和设置顺序是一致的。

不可变性

对于修饰符的不可变性笔者认为就是当设置的属性值确定时,被修饰的UI就确定了不会再变了。下面就展示一个位于屏幕中心,背景为绿色,旋转45度,宽度等比例拉伸2倍的正方形。

Box {
  Box(
      Modifier
          .rotate(45f)
          .scale(2f)
          .align(Alignment.Center)
          .size(50.dp, 50.dp)
          .background(Color.Green)
  )
}

如图:

详解Jetpack Compose中的Modifier修饰符

 

设置背景

设置背景颜色

    @Preview
    @Composable
    fun MyText() {
        Text(
            text = "你好",
            color = Color.Gray,
            modifier = Modifier.background(Color.White)
        )
    }

效果图:

详解Jetpack Compose中的Modifier修饰符

 

设置圆角背景

    @Preview
    @Composable
    fun MyText() {
        Text(
            text = "你好",
            color = Color.Gray,
            modifier = Modifier.background(Color.White, shape = RoundedCornerShape(10.dp))
        )
    }

效果图:

详解Jetpack Compose中的Modifier修饰符

渐变色背景

    @Preview
    @Composable
    fun MyText() {
        val colors = listOf(Color(0xFF005599),Color(0xFF3FFFED))
        Text(
            text = "你好",
            color = Color.White,
            modifier = Modifier.background(brush = Brush.linearGradient(colors),//设置线性渐变效果
                shape = RoundedCornerShape(10.dp),
                alpha = 1f)//设置透明度
        )
    }

效果图

详解Jetpack Compose中的Modifier修饰符

设置宽高

设置指定宽高

    @Preview
    @Composable
    fun MyText() {
        Text(
            text = "你好",
            color = Color.White,
            modifier = Modifier
                .width(100.dp)
                .height(100.dp)
        )
    }

效果:

详解Jetpack Compose中的Modifier修饰符

填满宽高

    @Preview
    @Composable
    fun MyText() {
        Column(
            modifier = Modifier
                .width(100.dp)
                .height(100.dp)
                .background(Color.Black)
        ) {
            Text(
                text = "你好",
                color = Color.Black,
                modifier = Modifier
                    .background(Color.White)
                    .fillMaxSize()//填满宽高
            )
        }
    }

效果图:

详解Jetpack Compose中的Modifier修饰符

自适应子组件高宽

 IntrinsicSize.Min 这个是关键

    @Preview
    @Composable
    fun MyText() {
        Box(
            modifier = Modifier
                .width(IntrinsicSize.Min)
                .height(IntrinsicSize.Min)
                .background(Color.Gray)
        ) {
            Text(
                text = "你好世界",
                modifier = Modifier.width(60.dp)
            )
        }
    }

效果图:

详解Jetpack Compose中的Modifier修饰符

按比例填充宽高

    @Preview
    @Composable
    fun MyText() {
        Column(
            modifier = Modifier
                .width(100.dp)
                .height(100.dp)
                .background(Color.Black)
        ) {
            Text(
                text = "你好",
                color = Color.Black,
                modifier = Modifier
                    .background(Color.White)
                    .fillMaxSize(0.5f)//以50%比例填满宽高
            )
        }
    }

效果:

详解Jetpack Compose中的Modifier修饰符

 

填满宽度或者高度

    @Preview
    @Composable
    fun MyText() {
        Column(
            modifier = Modifier
                .width(100.dp)
                .height(100.dp)
                .background(Color.Black)
        ) {
            Text(
                text = "你好",
                color = Color.Black,
                modifier = Modifier
                    .background(Color.Red)
                    .fillMaxWidth() //填满宽度
            )
            Text(
                text = "世界",
                color = Color.Black,
                modifier = Modifier
                    .background(Color.Yellow)
                    .fillMaxHeight() //填满高度
            )
        }
    }

效果:

详解Jetpack Compose中的Modifier修饰符

按比例填充宽度与高度

    @Preview
    @Composable
    fun MyText() {
        Column(
            modifier = Modifier
                .width(100.dp)
                .height(100.dp)
                .background(Color.Black)
        ) {
            Text(
                text = "你好",
                color = Color.Black,
                modifier = Modifier
                    .background(Color.Red)
                    .fillMaxWidth(0.5f) //填满宽度
            )
            Text(
                text = "世界",
                color = Color.Black,
                modifier = Modifier
                    .background(Color.Yellow)
                    .fillMaxHeight(0.5f) //填满高度
            )
        }
    }

效果图:

详解Jetpack Compose中的Modifier修饰符

默认最小宽高

    @Preview
    @Composable
    fun MyText() {
        Text(
            text = "你好",
            color = Color.Black,
            modifier = Modifier
                .background(Color.Red)
                .defaultMinSize(minWidth = 50.dp, minHeight = 50.dp)
        )
    }

设置边距

    @Preview
    @Composable
    fun MyText() {
        Column(
            modifier = Modifier
                .width(100.dp)
                .height(150.dp)
                .background(Color.Black)
        ) {
            Text(
                text = "A",
                color = Color.Black,
                modifier = Modifier
                    .background(Color.Red)
                    .padding(5.dp) //设置全部边距
            )

            Text(
                text = "B",
                color = Color.Black,
                modifier = Modifier
                    .background(Color.Green)
                    .padding(horizontal = 20.dp) //设置横向边距
            )

            Text(
                text = "C",
                color = Color.Black,
                modifier = Modifier
                    .background(Color.Yellow)
                    .padding(vertical = 10.dp) //设置竖向边距
            )

            Text(
                text = "D",
                color = Color.Black,
                modifier = Modifier
                    .background(Color.Blue)
                    .padding(0.dp,5.dp,50.dp,0.dp) //设置指定方向边距
            )
        }
    }

效果图:

详解Jetpack Compose中的Modifier修饰符

设置边框

 一共有三种重载方法

  1. fun Modifier.border(border: BorderStroke, shape: Shape = RectangleShape) = border(width = border.width, brush = border.brush, shape = shape)
  2. fun Modifier.border(width: Dp, color: Color, shape: Shape = RectangleShape) = border(width, SolidColor(color), shape)
  3. fun Modifier.border(width: Dp, brush: Brush, shape: Shape): Modifier

第一种实现渐变色边框

    @Preview
    @Composable
    fun MyLayout() {
        val colors = listOf(Color(0xFF005599), Color(0xFF3FFFED))
        Column(
            modifier = Modifier
                .width(25.dp)
                .height(25.dp)
                .background(Color.White)
                .border(  //设置渐变边框
                    border = BorderStroke(1.dp, Brush.linearGradient(colors)), //设置边框粗细与边框渐变色
                    shape = RoundedCornerShape(5.dp) //圆角形状
                )
        ){ }
    }

效果图:

详解Jetpack Compose中的Modifier修饰符

第二种实现单色边框

    @Preview
    @Composable
    fun MyLayout() {
        Column(
            modifier = Modifier
                .width(25.dp)
                .height(25.dp)
                .background(Color.White)
                .border(
                    width = 1.dp, //设置边框粗细
                    color = Color(0xFF000000), //边框颜色
                    shape = CutCornerShape (5.dp,5.dp,5.dp,5.dp) //切角矩形形状
                )
        ){ }
    }

效果图:

详解Jetpack Compose中的Modifier修饰符

第三种实现渐变色边框

 其实与第一种差不多,只是没有了BorderStroke包装

    @Preview
    @Composable
    fun MyLayout() {
        val colors = listOf(Color(0xFF005599), Color(0xFF3FFFED))
        Column(
            modifier = Modifier
                .width(25.dp)
                .height(25.dp)
                .background(Color.White)
                .border(
                    width = 1.dp,
                    brush = Brush.linearGradient(colors),
                    shape = RoundedCornerShape(0.dp,0.dp,5.dp,5.dp)
                )
        ){ }
    }

效果图:

详解Jetpack Compose中的Modifier修饰符

偏移位置

offset这个偏移是偏移自身这个组件 

    @Preview
    @Composable
    fun MyLayout() {
        Column(
            modifier = Modifier
                .width(100.dp)
                .height(100.dp)
                .background(Color.White)
        ){ 
            Text(text = "你好", color = Color.Black,
                //相对偏移 这个修改会根据布局方向自动调整水平偏移量(应该是为了阿拉伯语设计的):
                //当布局方向为从左到右时,正x偏移量会将内容向右移动,当布局方向为从右到左时,正x偏移量会将内容向左移动。
                modifier = Modifier.offset(x = 20.dp,y = 25.dp))

            Text(text = "世界", color = Color.Black,
                //绝对偏移 这个修改将不考虑布局方向:正的x偏移总是将内容向右移动
                modifier = Modifier.absoluteOffset(x = 45.dp,y = 20.dp))
        }
    }

效果图:

详解Jetpack Compose中的Modifier修饰符

 

缩放

    @Preview
    @Composable
    fun MyScale() {
        val scale = remember {
            mutableStateOf(1.5f)
        }
        Column(
            modifier = Modifier
                .fillMaxSize()
                .background(Color.Gray)
        ) {
            //默认
            Image(
                painter = painterResource(id = R.mipmap.ic_logo),
                contentDescription = null,
            )
            //比例缩放
            Image(
                painter = painterResource(id = R.mipmap.ic_logo),
                contentDescription = null,
                modifier = Modifier
                    .padding(top = 30.dp, start = 30.dp)
                    .scale(scale.value) //放大1.5倍
            )
            //指定宽高缩放
            Image(
                painter = painterResource(id = R.mipmap.ic_logo),
                contentDescription = null,
                modifier = Modifier
                    .padding(top = 70.dp, start = 90.dp)
                    .scale(3f,2f) //宽高缩放
            )
        }
    }

效果图:

详解Jetpack Compose中的Modifier修饰符

旋转

    @Preview
    @Composable
    fun MyRotate() {
        val rotate = remember { mutableStateOf(180f) }
        Column(
            modifier = Modifier
                .width(300.dp)
                .height(300.dp)
                .background(Color.Gray)
        ) {
            Image(
                painter = painterResource(id = R.mipmap.ic_logo),
                contentDescription = null,
                modifier = Modifier
                    .padding(100.dp)
                    .rotate(rotate.value) //设置旋转
            )
        }
    }

效果图:

详解Jetpack Compose中的Modifier修饰符

旋转与偏移位置的组合

请注意,Modifier一直强调组合的位置不同会出现不同的效果。如果你想实现旋转与拖动功能,那么旋转一定要在前面,否则会出现拖动的时候,实际移动的X轴与Y轴出现相反的问题。

@Composable
fun rotationAndOffset(){
    val rotation = remember { mutableStateOf(0f) }
    val offsetX = remember { mutableStateOf(0f) }
    val offsetY = remember { mutableStateOf(0f) }
    AsyncImage(
        model = if (mIsUrl.value) mUrl.value else mFile.value,
        contentDescription = null,
        modifier = Modifier
            .rotate(rotation.value) //rotate一定要在前面
            .offset { IntOffset(offsetX.value.roundToInt(), offsetY.value.roundToInt()) }
    )
}

输入操作(点击、双击、长按、拖动、触控、滚动)

单指操作_单击、按下、双击、长按、触控

    @OptIn(ExperimentalFoundationApi::class)
    @Preview
    @Composable
    fun MyClick() {
        val isEnableClick = remember {
            mutableStateOf(true)
        }

        Column(
            modifier = Modifier
                .width(100.dp)
                .height(150.dp)
                .background(Color.Black)
        ) {
            //方式一 单击监听
            Text(
                text = "A",
                color = Color.Black,
                modifier = Modifier
                    .background(Color.White)
                    .clickable(isEnableClick.value) { //设置点击
                        Log.e("zh", "A单击")
                    }
            )
            //方式二 组合性点击
            Text(
                text = "B",
                color = Color.Black,
                modifier = Modifier
                    .background(Color.White)
                    .combinedClickable( //注意!此Api是实验性的
                        onClick = {
                            Log.e("zh", "B单击")

                        },
                        onDoubleClick = {
                            Log.e("zh", "B双击")

                        },
                        onLongClick = {
                            Log.e("zh", "B长按")

                        }
                    )
            )
            //方式三 输入监听
            Text(
                text = "C",
                color = Color.Black,
                modifier = Modifier
                    .background(Color.White)
                    .pointerInput(Unit) {

                    detectTapGestures(
                        onPress = {
                            Log.e("zh", "C按下")
                        },
                        onDoubleTap = {
                            Log.e("zh", "C双击")
                        },
                        onLongPress = {
                            Log.e("zh", "C长按")
                        },
                        onTap = {
                            Log.e("zh", "C触控")
                        }
                    )
                }
            )
        }
    }

多指操作_缩放、旋转、拖动

双指缩放

    @Preview
    @Composable
    fun MyScale() {
        val scale = remember {
            mutableStateOf(1f)
        }
        Column(
            modifier = Modifier
                .width(300.dp)
                .height(300.dp)
                .background(Color.Gray)
        ) {
            //多点触控
            Image(
                painter = painterResource(id = R.mipmap.ic_logo),
                contentDescription = null,
                modifier = Modifier
                    .padding(100.dp)
                    .scale(scale.value)
                    .transformable(state = TransformableState { zoomChange, panChange, rotationChange ->
                        scale.value *= zoomChange
                        Log.e("zh", "缩放 ${zoomChange}" )
                        Log.e("zh", "坐标 ${panChange}")
                        Log.e("zh", "旋转 ${rotationChange}" )
                    })
            )
        }
    }

效果图:

详解Jetpack Compose中的Modifier修饰符

双指旋转

    @Preview
    @Composable
    fun MyRotate() {
        val rotate = remember { mutableStateOf(0f) }
        Box(
            modifier = Modifier
                .width(300.dp)
                .height(300.dp)
                .background(Color.Gray),
            contentAlignment = Alignment.Center

        ) {
            Image(
                painter = painterResource(id = R.mipmap.ic_logo),
                contentDescription = null,
                modifier = Modifier
                    .fillMaxSize(0.5f)
                    .rotate(rotate.value) //设置旋转
                    .transformable(state = TransformableState { zoomChange, panChange, rotationChange ->
                        Log.e("zh", "缩放 ${zoomChange}" )
                        Log.e("zh", "坐标 ${panChange}")
                        rotate.value += rotationChange //旋转变化
                        Log.e("zh", "旋转 ${rotationChange}" )
                    })
            )
        }
    }

效果图:

详解Jetpack Compose中的Modifier修饰符

双指拖动

    @Preview
    @Composable
    fun MyOffset() {
        val offsetX = remember { mutableStateOf(0f) }
        val offsetY = remember { mutableStateOf(0f) }
        Box(
            modifier = Modifier
                .width(300.dp)
                .height(300.dp)
                .background(Color.Gray),
            contentAlignment = Alignment.Center

        ) {
            Image(
                painter = painterResource(id = R.mipmap.ic_logo),
                contentDescription = null,
                modifier = Modifier
                    .fillMaxSize(0.5f)
                    .offset { IntOffset(offsetX.value.roundToInt(), offsetY.value.roundToInt()) } //设置偏移
                    .transformable(state = TransformableState { zoomChange, panChange, rotationChange ->
                        Log.e("zh", "缩放 ${zoomChange}" )
                        Log.e("zh", "坐标 ${panChange}")
                        offsetX.value += panChange.x
                        offsetY.value += panChange.y
                        Log.e("zh", "旋转 ${rotationChange}" )
                    })
            )
        }
    }

效果图:

详解Jetpack Compose中的Modifier修饰符

双指多操作组合

同时拖动、旋转、缩放

    @Preview
    @Composable
    fun MyCombination() {
        val scale  = remember { mutableStateOf(1f) }
        val offsetX = remember { mutableStateOf(0f) }
        val offsetY = remember { mutableStateOf(0f) }
        val rotation = remember { mutableStateOf(0f) }
        Box(
            modifier = Modifier
                .width(300.dp)
                .height(300.dp)
                .background(Color.Gray),
            contentAlignment = Alignment.Center

        ) {
            Image(
                painter = painterResource(id = R.mipmap.ic_logo),
                contentDescription = null,
                modifier = Modifier
                    .fillMaxSize(0.5f)
                    .graphicsLayer{
                        scaleX = scale.value
                        scaleY = scale.value
                        translationX = offsetX.value
                        translationY = offsetY.value
                        rotationZ = rotation.value
                    }
                    .transformable(state = TransformableState { zoomChange, panChange, rotationChange ->
                        scale.value *= zoomChange
                        offsetX.value += panChange.x
                        offsetY.value += panChange.y
                        rotation.value += rotationChange
                    })
            )
        }
    }

效果图:

详解Jetpack Compose中的Modifier修饰符

单指拖动

单方向拖动

如果你发现拖动会超出父类布局,但是你希望不超出父类布局,请参考博客下面的 “让子组件不超出当前父组件范围” 内容

    @Preview
    @Composable
    fun MyImage() {
        var offset = remember { mutableStateOf(0f) }
        Column(
            modifier = Modifier
                .width(200.dp)
                .height(200.dp)
                .background(Color.Gray)
        ) {
            Image(
                painter = painterResource(id = R.mipmap.ic_logo),
                contentDescription = null,
                contentScale = ContentScale.None,
                modifier = Modifier
                    .draggable(state = rememberDraggableState() { //设置拖动
                        offset.value += it
                    }, orientation = Orientation.Vertical) //设置方向 还能设置横向Orientation.Horizontal
                    .offset { IntOffset(0, offset.value.roundToInt()) }
            )
        }
    }

效果图:

详解Jetpack Compose中的Modifier修饰符

双方向拖动

    @Preview
    @Composable
    fun MyImage() {
        val offsetX = remember { mutableStateOf(0f) }
        val offsetY = remember { mutableStateOf(0f) }
        Column(
            modifier = Modifier
                .width(200.dp)
                .height(200.dp)
                .background(color = Color.Gray)

        ) {
            Image(
                painter = painterResource(id = R.mipmap.ic_logo),
                contentDescription = null,
                modifier = Modifier
                    .offset { IntOffset(offsetX.value.roundToInt(), offsetY.value.roundToInt()) }
                    .pointerInput(Unit) {
                        //检测拖动手势
                        detectDragGestures { change, dragAmount ->
                            Log.e("zh", "MyImage:检测拖动 当前指针输入数据 = ${change} ")
                            Log.e("zh", "MyImage:检测拖动 每次偏移量 = ${dragAmount} ")
                            offsetX.value += dragAmount.x
                            offsetY.value += dragAmount.y
                        }
                    }
            )
        }
    }

效果图:

详解Jetpack Compose中的Modifier修饰符

 

设置可滚动

横竖两个方向的滚动

    @Preview
    @Composable
    fun MyScroll() {
        Column(modifier = Modifier.fillMaxSize()) {
            //Row横向排列滚动
            Row(
                modifier = Modifier
                    .fillMaxWidth()
                    .horizontalScroll(rememberScrollState()) //设置横向滚动
            ) {
                for (i in 1..10) {
                    Image(
                        painter = painterResource(id = R.mipmap.ic_logo),
                        contentDescription = null,
                    )
                }
            }
            //Column竖向排列滚动
            Column(
                modifier = Modifier
                    .padding(10.dp)
                    .height(250.dp)
                    .verticalScroll(rememberScrollState()) //设置竖向滚动
            ) {
                for (i in 1..10) {
                    Image(
                        painter = painterResource(id = R.mipmap.ic_logo),
                        contentDescription = null,
                    )
                }
            }
        }

效果图:

详解Jetpack Compose中的Modifier修饰符

监听滚动偏移量、滚动位置与滚动位置跳转操作

    @Preview
    @Composable
    fun MyScroll() {
        val state = rememberScrollState()
        val position = remember {
            derivedStateOf {
                state.value
            }
        }
        val scope = rememberCoroutineScope() //这个是在Composable调用协程的一种方式

        Column() {
            Text(
                text = "豫章故郡,洪都新府。星分翼轸,地接衡庐。" +
                        "襟三江而带五湖,控蛮荆而引瓯越。" +
                        "物华天宝,龙光射牛斗之墟;" +
                        "人杰地灵,徐孺下陈蕃之榻。" +
                        "雄州雾列,俊采星驰。" +
                        "台隍枕夷夏之交,宾主尽东南之美。" +
                        "都督阎公之雅望,棨戟遥临;" +
                        "宇文新州之懿范,襜帷暂驻。" +
                        "十旬休假,胜友如云;" +
                        "千里逢迎,高朋满座。" +
                        "腾蛟起凤,孟学士之词宗;" +
                        "紫电青霜,王将军之武库。" +
                        "家君作宰,路出名区;" +
                        "童子何知,躬逢胜饯。",
                modifier = Modifier
                    .padding(10.dp)
                    .width(100.dp)
                    .height(100.dp)
                    //监听滚动位置
                    .scrollable(state = rememberScrollableState(consumeScrollDelta = {
                        Log.e("zh", "当前滚动偏移量:${it}")
                        it
                    }), orientation = Orientation.Vertical)
                    .verticalScroll(state)
            )

            Text(
                color = Color.Red,
                text = "当前滚动位置${position.value}",
            )

            Button(onClick = {
                scope.launch {
                    state.scrollTo(0)
                }
            }) {
                Text(text = "回到起点")
            }
        }
    }

效果图:

详解Jetpack Compose中的Modifier修饰符

指针输入

指针输入监听,与上面各色方法类似

    @Preview
    @Composable
    fun MyPointerInput() {
        Box(
            modifier = Modifier
                .width(300.dp)
                .height(300.dp)
                .background(Color.Gray)
        ) {
            Text(
                text = "你好",
                color = Color.Black,
                modifier = Modifier
                    .align(Alignment.Center)
                    .fillMaxSize(0.5f)
                    .background(color = Color.Green)
                    .pointerInput(Unit) {
                        /**
                         * 下面的只能存在一个手势Gestures方法,多了后续的手势方法会不执行,这边是方便观看全部贴出来
                         */
                        detectDragGestures { change, dragAmount ->
                            Log.e("zh", "检测拖动手势: change = $change \n dragAmount = $dragAmount")
                        }
                        detectDragGesturesAfterLongPress { change, dragAmount ->
                            Log.e("zh", "检测长按后的拖拽手势:  change = $change \n dragAmount = $dragAmount")
                        }
                        detectTapGestures {
                            /**
                             * 检测轻按、双击和长按手势,检测到时分别调用onTap、onDoubleTap和onLongPress。当检测到按压和pressgestuscope时调用onPress。
                             * tryAwaitRelease PressGestureScope。awaitRelease可以用来检测指针何时被释放或手势何时被取消。
                             * 第一个向下的指针和最后一个向上的指针被消耗,
                             * 在长按的情况下,检测到长按后的所有更改都被消耗。
                             */
                            Log.e("zh", "检测触控:  Offset = $it \n")
                        }
                        detectTapGestures(
                            onTap = {
                                Log.e("zh", "单击: Offset = $it \n")
                            },
                            onDoubleTap = {
                                Log.e("zh", "双击: Offset = $it \n")
                            },
                            onLongPress = {
                                Log.e("zh", "长按: Offset = $it \n")
                            },
                            onPress = {
                                Log.e("zh", "按下: Offset = $it \n")
                            })

                        detectTransformGestures { centroid, pan, zoom, rotation ->
                            Log.e("zh", "旋转、平移和缩放的手势检测器:  centroid = $centroid \n pan = $pan \n zoom = $zoom rotation = $rotation")

                        }
                        detectHorizontalDragGestures { change, dragAmount ->
                            Log.e("zh", "检测水平拖动手势:  change = $change \n dragAmount = $dragAmount")
                        }
                        detectVerticalDragGestures { change, dragAmount ->
                            Log.e("zh", "检测垂直拖动手势:  change = $change \n dragAmount = $dragAmount")
                        }
                    }
            )
        }
    }

graphicsLayer 

graphicsLayer可用于对内容应用效果,如缩放、旋转、不透明度、阴影和剪切。当你的层属性由androidx. composition .runtime. state或动画值支持时,最好使用这个版本,因为读取块中的状态只会导致层属性更新,而不会触发重新组合和重新布局。

    @Preview
    @Composable
    fun MyGraphicsLayer() {
        Box(
            modifier = Modifier
                .width(300.dp)
                .height(300.dp)
                .background(Color.Gray)
        ) {
            Text(
                text = "你好",
                color = Color.Black,
                modifier = Modifier
                    .align(Alignment.Center)
                    .fillMaxSize(0.5f)
                    .background(color = Color.Green)
                    .graphicsLayer{
                        //绘制区域的水平比例尺。默认值为“1”
                        scaleX = 1f
                        //绘制区域的垂直比例尺。默认值为“1”。
                        scaleY = 1f
                        //绘制区域的alpha。设置为“1”以外的值将导致绘制的内容是半透明的,设置为“0”将使其完全不可见。默认值为' 1 ',取值范围为' 0 ' ~ ' 1 '。
                        alpha = 1f
                        //该层相对于其左边界的水平像素偏移量。默认值为' 0 '。
                        translationX = 0f
                        //该层相对于其上边界的垂直像素偏移量。默认值为' 0 '
                        translationY = 0f
                        //以像素为单位设置阴影的仰角。默认值为“0”,且不能为负值
                        shadowElevation = 0f
                        //范围阴影颜色
                        ambientShadowColor = Color(0xFFFF0000)
                        //点阴影颜色
                        spotShadowColor = Color(0xFFFF0000)
                        //X轴旋转角度
                        rotationX = 0f
                        //Y轴旋转角度
                        rotationY= 0f
                        //Z轴旋转角度
                        rotationZ = 0f
                        //观察相机视角距离
                        cameraDistance = 0f
                        //旋转or缩放的中心点
                        transformOrigin =  TransformOrigin.Center
                        transformOrigin =  TransformOrigin(0.1f,0.1f)
                        //形状
                        shape = RectangleShape
                        //设置为' true '将内容剪辑到[shape]。默认值为' false '
                        clip = false
                        //渲染效果,比如下面设置的模糊效果
                        renderEffect = BlurEffect(20f, 0.5f, TileMode.Clamp)
                    }
            )
        }
    }

裁剪

clip的裁剪

    @Preview
    @Composable
    fun MyImage() {
        Column(
            modifier = Modifier
                .width(100.dp)
                .height(100.dp)
                .background(Color.White)
                //clip的剪裁是对当前组件的内部内容进行裁剪,这里使用了CircleShape圆形进行裁剪.
                //也可以使用RectangleShape 或者 RoundedCornerShape() 矩形进行裁剪
                .clip(shape = CircleShape)

        ) {
            Image(
                painter = painterResource(id = R.mipmap.ic_logo),
                contentDescription = null,
                modifier = Modifier.fillMaxSize()
            )
        }
    }

效果图:

详解Jetpack Compose中的Modifier修饰符

上面是使用常用形状裁剪,这里在举例一个自定义形状的裁剪方式,如下使用path绘制了一个三角形进行裁剪

    /**
     * 裁剪三角形
     */
    @Preview
    @Composable
    fun MyImage() {
        val customShape = object : Shape {
            override fun createOutline(size: Size, layoutDirection: LayoutDirection, density: Density): Outline {
                val path = Path()
                path.moveTo(size.width/2, 0f)
                path.lineTo(0f,size.height)
                path.lineTo(size.width,size.height)
                path.close()
                val outline = Outline.Generic(path)
                return outline
            }
        }
        Column(
            modifier = Modifier
                .width(100.dp)
                .height(100.dp)
                .background(Color.White)
                .clip(shape = customShape)

        ) {
            Image(
                painter = painterResource(id = R.mipmap.ic_logo),
                contentDescription = null,
                modifier = Modifier.fillMaxSize()
            )
        }
    }

效果图:

详解Jetpack Compose中的Modifier修饰符

让子组件不超出当前父组件范围

clipToBounds 按照指定的边界裁切内容。强制限制当前布局下的子组件不允许超出到外部。另外这个属性与clip属性无关联。

反面例子代码,下面的代码中注释了clipToBounds 

    @Preview
    @Composable
    fun MyImage() {
        var offset  =  remember { mutableStateOf(0f) }
        //必须在套一个布局设置最大范围的父类布局,以展示下面的Image在拖动的时候超出的效果
        Column(modifier = Modifier.fillMaxSize().padding(200.dp)) {
            Column(
                modifier = Modifier
                    .width(200.dp)
                    .height(200.dp)
                    .background(Color.Gray) //这里设置背景色为灰色,以观察布局的大小
//                .clipToBounds()

            ) {
                Image(
                    painter = painterResource(id = R.mipmap.ic_logo),
                    contentDescription = null,
                    contentScale = ContentScale.None,
                    modifier = Modifier
                        .draggable(state = rememberDraggableState() {
                            offset.value += it
                        }, orientation = Orientation.Horizontal)
                        .offset { IntOffset(offset.value.roundToInt(), 0) }
                )
            }
        }
    }

 反面例子效果图,图片在拖动的时候可以超出布局范围:

详解Jetpack Compose中的Modifier修饰符

调用clipToBounds 后的效果图(代码就不重复贴了,直接将clipToBounds 注释取消就行):

详解Jetpack Compose中的Modifier修饰符

模糊

注意!blur这个api需要Android版本12 31 API的设备上才能生效

    @Preview
    @Composable
    fun MyBlur() {
        Box(
            modifier = Modifier
                .width(300.dp)
                .height(300.dp)
                .background(Color.Gray)
        ) {
            Image(
                painter = painterResource(id = R.mipmap.ic_logo),
                contentDescription = null,
                modifier = Modifier
                    .align(Alignment.Center)
                    //注意blur这个api需要Android 12 31 API 才能生效
                    .blur(radius = 10.dp, edgeTreatment = BlurredEdgeTreatment.Rectangle) //设置模糊
            )
        }
    }

效果图:

BlurredEdgeTreatment.Rectangle 是矩形边缘清晰中间模糊

详解Jetpack Compose中的Modifier修饰符

BlurredEdgeTreatment.Unbounded 无边界模糊的效果图:

详解Jetpack Compose中的Modifier修饰符

透明度

    @Preview
    @Composable
    fun MyAlpha() {
        Box(
            modifier = Modifier
                .width(300.dp)
                .height(300.dp)
                .background(Color.Gray)
        ) {
            Image(
                painter = painterResource(id = R.mipmap.ic_logo),
                contentDescription = null,
                modifier = Modifier
                    .align(Alignment.Center)
                    .alpha(0.1f) //设置透明度
            )
        }
    }

效果图:

详解Jetpack Compose中的Modifier修饰符

绘制阴影

注意!shadow这个api需要Android版本10的设备上才能生效

    @Preview
    @Composable
    fun MyShadow() {
        Box(
            modifier = Modifier
                .width(300.dp)
                .height(300.dp)
                .background(Color.White)
        ) {
            Image(
                painter = painterResource(id = R.mipmap.ic_logo),
                contentDescription = null,
                modifier = Modifier
                    .align(Alignment.Center)
                    .shadow( //设置阴影,调用此api需要设备Android版本为10
                        elevation = 50.dp, //隐藏长度
                        shape = RectangleShape, //阴影形状
                        ambientColor = Color.Red, //环境颜色
                        spotColor = Color.Red, //阴影颜色
                        clip = true //是否跟随裁剪形状改变阴影形状
                    )
            )
        }
    }

详解Jetpack Compose中的Modifier修饰符

绘制

drawBehind绘制,将增加的绘制内容显示到组件图层的最下层

    @Preview
    @Composable
    fun MyDrawBehind() {
        Box(
            modifier = Modifier
                .width(300.dp)
                .height(300.dp)
                .background(Color.White)
        ) {
            Image(
                painter = painterResource(id = R.mipmap.ic_logo),
                contentDescription = null,
                modifier = Modifier
                    .align(Alignment.Center)
                    .drawBehind { //绘制到最下面的图层
                        val radius = size.width / 3
                        val centerOffset = Offset(size.width, 0f)
                        drawCircle(
                            color = Color.Red,
                            radius = radius,
                            center = centerOffset,
                            style = Fill
                        )
                    }
            )
        }
    }

在下面的效果图里,可以看到红圈在图片的下层:

详解Jetpack Compose中的Modifier修饰符

drawWithContent 人为控制绘制内容的顺序

    @Preview
    @Composable
    fun MyDrawWithContent() {
        Box(
            modifier = Modifier
                .width(300.dp)
                .height(300.dp)
                .background(Color.White)
        ) {
            Image(
                painter = painterResource(id = R.mipmap.ic_logo),
                contentDescription = null,
                modifier = Modifier
                    .align(Alignment.Center)
                    .drawWithContent {
                        /*
                        drawContent()是理解drawWithContent的关键
                        drawContent这个是这个组件本身需要绘制的内容。
                        控制这个方法的位置你就可以控制绘制的顺序。
                         */
                        drawContent()
                        val radius = size.width / 3
                        val centerOffset = Offset(size.width, 0f)
                        drawCircle(
                            color = Color.Red,
                            radius = radius,
                            center = centerOffset,
                            style = Stroke(25f)
                        )
                    }
            )
        }
    }

 

因为代码中是先绘制了drawContent()然后在绘制圆环,所以下面的效果图圆环在图片的上层:

详解Jetpack Compose中的Modifier修饰符

drawWithCache 提供缓存数据避免重组的绘制方式

    @Preview
    @Composable
    fun MyDrawWithCache() {
        val count = remember { mutableStateOf(0) }
        Box(
            modifier = Modifier
                .width(300.dp)
                .height(300.dp)
                .background(Color.White)
        ) {
            Text(
                text = "计数",
                modifier = Modifier
                    .align(Alignment.Center)
                    .clickable { count.value++ }
                    /*
                     * drawWithCache 需要配合 onDrawWithContent 或者 onDrawBehind 使用
                     */
                    .drawWithCache {
                        val x = size.width + 20
                        val y = size.height - 10
                        val paint = Paint()
                        paint.textSize = 50f
                        paint.textAlign = Paint.Align.CENTER
                        Log.e("zh", "触发重组1 在这个代码块里不会发生重组")
                        onDrawWithContent {
                            Log.e("zh", "触发重组2 在这个代码块里发生重组,但是请注意mutableStateOf的数据也要放到这个代码块中")
                            drawIntoCanvas { canvas ->
                                canvas.nativeCanvas.drawText("${count.value}", x, y, paint)
                            }
                            drawContent()
                        }
                    }
            )
        }
    }

效果图:

详解Jetpack Compose中的Modifier修饰符

Painter绘制

绘制图形

    @Preview
    @Composable
    fun MyPaint() {
        Box(
            modifier = Modifier
                .width(100.dp)
                .height(100.dp)
                .background(Color.White)
        ) {
            Text(
                text = "你好",
                modifier = Modifier
                    .align(Alignment.Center)
                    .paint(painter = object : Painter() {
                        override val intrinsicSize: Size
                            get() = Size(50f, 50f)

                        override fun DrawScope.onDraw() {
                            drawLine(
                                color = Color.Red,
                                Offset(0f, 0f),
                                Offset(size.width, size.height),
                                strokeWidth = 10f
                            )
                        }
                    })
            )
        }
    }

效果图:

详解Jetpack Compose中的Modifier修饰符

绘制图像

有一些人会利用这个来绘制组件的背景,的确可以但是个人认为不太妥当...

    @Preview
    @Composable
    fun MyPaint() {
        Box(
            modifier = Modifier
                .width(300.dp)
                .height(300.dp)
                .background(Color.White)
        ) {
            Text(
                text = "你好",
                color = Color.White,
                modifier = Modifier
                    .align(Alignment.Center)
                    .paint(painterResource(id = R.mipmap.ic_logo))
            )
        }
    }

效果图:

详解Jetpack Compose中的Modifier修饰符

组合顺序的影响

 Modifier的方法组合顺序是会影响到组件的实际效果的,这里使用两段代码演示(可以根据下面2代码看到点击范围发生了改变):

代码1:

    @Preview
    @Composable
    fun MyText() {
        Text(
            text = "你好世界你好世界",
            color = Color.Black,
            modifier = Modifier
                .background(Color.Green)
                .size(150.dp)
                .clickable { //点击在前
                    Log.e("zh", "MyGraphicsLayer: ")
                }
                .padding(50.dp) //padding在后
        )
    }

效果图:

详解Jetpack Compose中的Modifier修饰符

代码2:

    @Preview
    @Composable
    fun MyText() {
        Text(
            text = "你好世界你好世界",
            color = Color.Black,
            modifier = Modifier
                .background(Color.Green)
                .size(150.dp)
                .padding(50.dp) //padding在前
                .clickable { //点击在后
                    Log.e("zh", "MyGraphicsLayer: ")
                }
        )
    }

效果图:

详解Jetpack Compose中的Modifier修饰符

多个Modifier组合

下面的代码种,分别创建了backgroundModifier  与 borderModifier, 并且使用then将他们组合 

    @Preview
    @Composable
    fun MyText() {
        val backgroundModifier = Modifier
            .background(Color.Green)
            .fillMaxSize(0.2f)

        val borderModifier = Modifier
            .border(
                width = 1.dp, //设置边框粗细
                color = Color(0xFF000000), //边框颜色
                shape = RoundedCornerShape(5.dp) //切角矩形形状
            )

        Column {
            Text(
                text = "A",
                color = Color.Black,
                textAlign = TextAlign.Center,
                modifier = Modifier
                    .then(backgroundModifier)
                    .then(borderModifier)
                    .clickable {
                        Log.e("zh", "点击A")
                    }
            )
            Text(
                text = "B",
                color = Color.Black,
                textAlign = TextAlign.Center,
                modifier = Modifier
                    .then(backgroundModifier)
                    .then(borderModifier)
                    .clickable {
                        Log.e("zh", "点击B")
                    }
            )

        }
    }

end.文章来源地址https://www.toymoban.com/news/detail-457639.html

到了这里,关于详解Jetpack Compose中的Modifier修饰符的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Jetpack Compose 中的动态加载、插件化技术探索

    在传统的 Android 开发模式中,由于界面过分依赖于 Activity 、 Fragment 这样的组件,一个业务模块中往往会存在着大量的 Activity 类,因此诞生了很多的插件化框架,这些插件化框架基本都是想方设法的使用各种Hook/反射手段来解决使用未注册的组件问题。在进入 Jetpack Compose 的世

    2024年02月14日
    浏览(36)
  • Android Jetpack Compose 中的分页与缓存展示

    在几乎任何类型的移动项目中,移动开发人员在某个时候都会处理分页数据。如果数据列表太大,无法一次从服务器检索完毕,这就是必需的。因此,我们的后端同事为我们提供了一个端点,返回分页数据列表,并期望我们知道如何在客户端处理它。 在本文中,我们将重点介

    2024年02月13日
    浏览(47)
  • Jetpack Compose布局控件Column、Row、Box 详解

    本篇文章介绍 Compose 的布局控件 Column 、 Row 、 Box ,在 Android XML 模式开发中,常用的布局控件有 LinearLayout 、 RelativeLayout 、 FrameLayout 以及 ConstraintLayout , Compose 没有延用之前的布局设计,而是提供了全新的布局控件,不仅实现了 XML 模式的相关功能并且更加灵活好用。 Compos

    2024年02月03日
    浏览(45)
  • Jetpack Compose UI创建布局绘制流程+原理 —— 内含概念详解(手撕源码)

    本文是我去年首发于稀土掘金平台的文章 全文较长 : 共1万5千字 ,适合有耐心❤️的人学习 有些概念不懂的可以去 4.部分概念详解 这个目录先稍微学习一下 Compose源码 基于最新的 Compose 版本: 1.0.1 系统源码 基于最新的 Android11 版本 注意: 后续Compose版本升级之后,有可能

    2023年04月11日
    浏览(39)
  • Android开发中的前五个代码异味:Jetpack Compose UI和MVVM

    代码异味是指软件代码中潜在问题的指标,可能并不一定是错误,但可能会导致问题,如增加维护复杂性、降低性能或降低可读性。我们将探讨Android开发中的前五个代码异味,其中包括使用Jetpack Compose UI和Model-View-ViewModel(MVVM)架构的示例。 上帝对象或上帝类是指试图做太

    2024年02月02日
    浏览(38)
  • Jetpack Compose 深入探索系列四: Compose UI

    通过 Compose runtime 集成 UI Compose UI 是一个 Kotlin 多平台框架。它提供了通过可组合函数发出 UI 的构建块和机制。除此之外,这个库还包括 Android 和 Desktop 源代码,为 Android 和 Desktop 提供集成层。 JetBrains积极维护Desktop代码库,而Google维护Android和通用代码库。Android和Desktop源代码

    2024年02月12日
    浏览(48)
  • Jetpack Compose(6)——动画

    目录 一、低级别动画 API 1.1 animate*AsState 1.2 Animatable 1.3 Transition 动画 1.3.1 updateTransition 1.3.2 createChildTransition 1.3.3 封装并复用 Transition 动画 1.4 remeberInfiniteTransition —— 无限循环的 transition 动画 1.5 小结 二、Android Studio 对 Compose 动画调试的支持 三、AnimationSpec 动画规格 3.1 Sprin

    2024年04月26日
    浏览(31)
  • Jetpack Compose 学习汇总

    关于 Jetpack Compose 的学习本想只是简单的快速学习一下,结果万万没想到,竟然一下子折腾了好几个月。。。 下面将之前记录的 Jetpack Compose 相关的学习博文进行一个汇总链接整理,方便我以后自己查阅,也希望能帮到一些有正在学习 Compose 的道友。 Jetpack Compose 中的基础组件

    2024年02月12日
    浏览(39)
  • Jetpack Compose(4)——重组

    目录 一、状态变化 1.1 状态变化是什么 1.2 mutableStateListOf 和 mutableStateMapOf 二、重组的特性 2.1 Composable 重组是智能的 2.2 Composable 会以任意顺序执行 2.3 Composable 会并发执行 2.4 Composable 会反复执行 2.5 Composable 的执行是“乐观”的 三、重组范围 四、参数类型的稳定性 4.1 稳定和不

    2024年04月08日
    浏览(38)
  • Android Jetpack Compose 别裁

    一、简介 二、compose优缺点 三、compose好学吗 四、Android Jetpack Compose 跟 fluter 哪个更好 五、Android Jetpack Compose 跟 fluter 技能学习选择 之所以叫Android Jetpack Compose别裁是希望能取舍网上的对compose的资料,推出别出心裁的文章,文章结束都会有一个案例,通过实践学习,让学习的

    2024年02月03日
    浏览(63)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包