• Jetpack Compose学习(6)——关于Modifier的妙用


    原文: Jetpack Compose学习(6)——关于Modifier的妙用 | Stars-One的杂货小窝

    之前学习记录中也是陆陆续续地将常用的Modifier的方法穿插进去了,本期就来详细的讲解下关于modifier的使用

    限于篇幅,我是以常用的属性来讲解,漏讲了一些请见谅,毕竟方法真的太多了,之后可能有用的新的效果,会穿插地讲些

    本系列以往文章请查看此分类链接Jetpack compose学习

    基本使用

    我们直接以个简单的例子讲解下使用,设置Box布局的宽高各100dp,且内边距为16dp,背景色为绿色,代码如下

    Column {
        Box(
            Modifier
                .size(100.dp)
                .background(Color.Green)
                .padding(16.dp)
        )
        Box(
            Modifier
                .size(100.dp)
                .padding(16.dp)
                .background(Color.Green)
        )
    }
    

    由上面代码和效果可以看到,modifier中的顺序不同会导致效果不同,这是因为Modifier的设计如此

    如果我们先设置背景色,之后再设置padding,那么padding也是在绿色背景的基础上进行的,所以,就是图中全是绿色的效果

    如果是先设置padding,那么我们设置背景色是针对里面的布局进行设置,而不会讲padding也算到里面去

    宽高类和边距

    首先,先是讲解常用的属性,设置宽高和边距

    size

    同时设置宽高

    • size(size: Dp)
    • size(height: Dp, Dp)

    width

    单独设置宽度

    • width(intrinsicSize: IntrinsicSize) 这个参数是自定义布局测量里的,本篇暂时不讲解
    • width( Dp)

    hegiht

    单独设置高度

    • hegiht(intrinsicSize: IntrinsicSize) 这个参数是自定义布局测量里的,本篇暂时不讲解
    • hegiht(hegiht: Dp)

    defaultMinSize

    设置宽高的默认最小值

    defaultMinSize(
        minWidth: Dp = Dp.Unspecified,
        minHeight: Dp = Dp.Unspecified
    ):
    

    sizeIn

    设置宽高的最小值和最大值,宽度在minWidth~maxWidth之间,高度在minHeight~maxHeight之间

    sizeIn(
        minWidth: Dp = Dp.Unspecified,
        minHeight: Dp = Dp.Unspecified,
        maxWidth: Dp = Dp.Unspecified,
        maxHeight: Dp = Dp.Unspecified
    ):
    

    同理,也有单独给宽度或高度设置的方法

    • widthIn(min: Dp = Dp.Unspecified, max: Dp = Dp.Unspecified)
    • heightIn(min: Dp = Dp.Unspecified, max: Dp = Dp.Unspecified)

    fillMaxSize

    宽高都填充满父布局(相当于原生xml中的match_parent)

    fillMaxSize(fraction: Float = 1f)

    默认是1f,代表填充满父布局,如果设置为0.5f,则是填满父布局的0.5(即一半)

    除此之外,也有单独给宽度或高度方法
    = fillMaxWidth(fraction: Float = 1f)
    = fillMaxHegiht(fraction: Float = 1f)

    wrapContentSize

    组件的控件宽高若是小与定义的最小宽高,会将组件进行排列的设置

    wrapContentSize(
        align: Alignment = Alignment.Center,
        unbounded: Boolean = false
    ) 
    

    上面说的可能不是太好懂,以一个例子来说明吧

    Box(
        Modifier.sizeIn(minWidth = 40.dp, minHeight = 40.dp)
            .wrapContentSize(Alignment.TopCenter)
            .size(20.dp)
            .background(Color.Blue)
    )
    

    我们设置了Box的组件的最小宽高为40dp,但此Box的宽高实际设置成了20dp,如果没有加上这个方法wrapContentSize,那么最终渲染出的Box宽高其实是40dp x 40dp,且是蓝色背景

    而由于我们加上了这个方法,最终渲染出的Box宽高就为20dp x 20dp,且排列对齐方式会按照wrapContentSize中的align参数进行

    同理,也有单独设置宽度或高度的方法

    wrapContentHeight(
        align: Alignment.Vertical = Alignment.CenterVertically,
        unbounded: Boolean = false
    )
    
    //使用例子
    Box(
        Modifier.size(50.dp)
            .wrapContentHeight(Alignment.CenterVertically)
            .height(20.dp)
            .background(Color.Blue)
    )
    
    wrapContentWidth(
        align: Alignment.Horizontal = Alignment.CenterHorizontally,
        unbounded: Boolean = false
    )
    
    //使用例子
    Box(
        Modifier.size(50.dp)
            .wrapContentWidth(Alignment.CenterHorizontally)
            .width(20.dp)
            .background(Color.Blue)
    )
    

    padding

    有四种不同的参数,各位看着用就行,之前文章中也是有详细讲解,这里不再赘述

    padding(all: Dp)
    

    点击事件类(点击 双击 长按)

    clickable

    给任意组件(包括布局)设置点击事件,且自带点击水波纹效果

    clickable(
        enabled: Boolean = true,
        onClickLabel: String? = null,
        role: Role? = null,
        onClick: () -> Unit
    )
    

    onClickLabelrole主要是为残疾人(应该是盲人)设置的属性,可以不用设置

    此外,还有另外的参数列表

    clickable(
        interactionSource: MutableInteractionSource,
        indication: Indication?,
        enabled: Boolean = true,
        onClickLabel: String? = null,
        role: Role? = null,
        onClick: () -> Unit
    )
    

    interactionSource之前也有讲过,是用来判断按钮的点击状态,具体可以看之前讲解关于Button的使用的文章

    indication看文档说明是说用来绘制水波纹或者点击高亮的效果,具体使用没有深究,下面给个例子:

    val interactionSource = remember { MutableInteractionSource() }
    Column {
        Text(
            text = "Click me and my neighbour will indicate as well!",
            modifier = Modifier
                // clickable will dispatch events using MutableInteractionSource and show ripple
                .clickable(
                    interactionSource = interactionSource,
                    indication = rememberRipple()
                ) {
                    /**do something */
                }
                .padding(10.dp)
        )
        Spacer(Modifier.requiredHeight(10.dp))
        Text(
            text = "I'm neighbour and I indicate when you click the other one",
            modifier = Modifier
                // this element doesn't have a click, but will show default indication from the
                // CompositionLocal as it accepts the same MutableInteractionSource
                .indication(interactionSource, LocalIndication.current)
                .padding(10.dp)
        )
    }
    

    效果如下图所示

    combinedClickable

    组合点击事件,可以给组件点击,双击,长按监听操作

    不过,需要注意的是,此方法是实验性方法,也不知道后面版本更新会有所改变

    combinedClickable(
        enabled: Boolean = true,
        onClickLabel: String? = null,
        role: Role? = null,
        onLongClickLabel: String? = null,
        onLongClick: () -> Unit = null,
        onDoubleClick: () -> Unit = null,
        onClick: () -> Unit
    )
    

    看方法很好理解,onLongClick是长按操作,onDoubleClick是双击操作,onClick是点击操作

    val context = LocalContext.current
    Box(
        Modifier
            .size(50.dp)
            .background(Color.Blue)
            .combinedClickable(onLongClick = {
                Toast.makeText(context, "长按操作", Toast.LENGTH_SHORT).show()
            }, onDoubleClick = {
                Toast.makeText(context, "双击操作", Toast.LENGTH_SHORT).show()
            }, onClick = {
                Toast.makeText(context, "点击操作", Toast.LENGTH_SHORT).show()
            })
    )
    

    形状(shape) 边框(border) 背景(background)

    border

    设置边框宽度和形状

    border(border: BorderStroke, shape: Shape = RectangleShape)
    border( Dp, color: Color, shape: Shape = RectangleShape))
    border( Dp, brush: Brush, shape: Shape)
    

    Brush是设置渐变,如下面的例子

    //红蓝绿三色水平渐变
    val gradientBrush = Brush.horizontalGradient(
        colors = listOf(Color.Red, Color.Blue, Color.Green),
        startX = 0.0f,
        endX = 500.0f,
        tileMode = TileMode.Repeated
    )
    Text(
        "Text with gradient border",
        modifier = Modifier.padding(10.dp).border(width = 2.dp, brush = gradientBrush, shape = CircleShape)
            .padding(10.dp)
    )
    

    效果如下:

    后期再出一篇讲解Brush的使用

    background

    设置背景及背景形状

    background(color: Color, shape: Shape = RectangleShape)
    background(brush: Brush, shape: Shape = RectangleShape,alpha: Float = 1.0f)
    

    alpha是设置透明度

    background有两种参数列表,具体使用也是与上面的类似,这里不过多赘述

    阴影

    shadow(elevation: Dp, shape: Shape = RectangleShape, clip: Boolean)
    
    
    

    滚动效果

    之前在讲解布局的时候有提及,Row和Column布局里面的子组件,宽高若是大于父组件就是导致子组件被隐藏,我们可以将其设置为滚动效果

    但Compose没有Scrollview,要想Row或Column实现滚动效果,就得使用modifier来实现

    verticalScroll

    horizontalScroll(
        state: ScrollState,
        enabled: Boolean = true,
        flingBehavior: FlingBehavior? = null,
        reverseScrolling: Boolean = false
    )
    

    flingBehavior这个参数不是很理解做什么用的..

    Column(Modifier.verticalScroll(rememberScrollState())) {
        repeat(10){
            Box(
                Modifier
                    .fillMaxWidth()
                    .height(200.dp)
                    ){
                Text(text = "测试$it")
            }
        }
    }
    

    效果如下:

    如果不加上verticalScroll,Column是无法向下滚动的

    reverseScrolling设置为true的话,默认自动滚动到底部,效果如下所示

    Column一般和verticalScroll连用实现垂直方向的滚动效果,而Row则与horizontalScroll连用

    horizontalScroll

    horizontalScroll(
        state: ScrollState,
        enabled: Boolean = true,
        flingBehavior: FlingBehavior? = null,
        reverseScrolling: Boolean = false
    )
    

    使用与上面的类似,这里不再赘述

    scrollable

    scrollable(
        state: ScrollableState,
        orientation: Orientation,
        enabled: Boolean = true,
        reverseDirection: Boolean = false,
        flingBehavior: FlingBehavior? = null,
        interactionSource: MutableInteractionSource? = null
    )
    

    没太搞懂这个主要是实现什么效果的..

    文档的示例代码:

    // actual composable state that we will show on UI and update in `Scrollable`
    val offset = remember { mutableStateOf(0f) }
    Box(
        Modifier
            .size(150.dp)
            .scrollable(
                orientation = Orientation.Vertical,
                // state for Scrollable, describes how consume scroll amount
                state = rememberScrollableState { delta ->
                    offset.value = offset.value + delta // update the state
                    delta // indicate that we consumed all the pixels available
                }
            )
            .background(Color.LightGray),
        contentAlignment = Alignment.Center
    ) {
        Text(offset.value.roundToInt().toString(), style = TextStyle(fontSize = 32.sp))
    }
    

    效果

    选择

    selectable

    可用来实现单选功能

    val option1 = Color.Red
    val option2 = Color.Blue
    var selectedOption by remember { mutableStateOf(option1) }
    Column {
        Text("Selected: $selectedOption")
        Row {
            listOf(option1, option2).forEach { color ->
                val selected = selectedOption == color
                Box(
                    Modifier
                        .size(100.dp)
                        .background(color = color)
                        .selectable(
                            selected = selected,
                            onClick = { selectedOption = color }
                        )
                ){
                    if(selected) Text(text = "已选",color = Color.White)
                }
            }
        }
    }
    

    效果:

    toggleable

    类似复选框的勾选及不勾选

    var checked by remember { mutableStateOf(false) }
    // content that you want to make toggleable
    Text(
        modifier = Modifier.toggleable(value = checked, onValueChange = { checked = it }),
        text = checked.toString()
    )
    

    效果如下:

    变化类(旋转 缩放 放大)

    aspectRatio

    Box(Modifier.width(100.dp).aspectRatio(2f).background(Color.Green))
    

    rotate

    组件沿中心顺时针旋转,最高支持360°

    //顺时针旋转45°
    Box(
        Modifier.rotate(45f)
            .size(100.dp, 100.dp)
    )
    

    效果如下:

    scale

    缩放或放大

    Box(
        Modifier.scale(scaleX = 0.2f, scaleY = 0.5f)
            .background(Color.Black)
            .size(100.dp, 100.dp)
    )
    
    

    不过看实际效果,感觉是将宽和高都往中间缩放了

    参考


    提问之前,请先看提问须知 点击右侧图标发起提问 联系我 或者加入QQ群一起学习 Stars-One安卓学习交流群 TornadoFx学习交流群:1071184701
  • 相关阅读:
    解决点击状态栏时ScrollView自动滚动到初始位置失效办法
    如何设计用户、角色、权限表
    Subject的功能
    shiro授权的源码分析
    shiro之认证源码分析
    shiro配置
    JSONArray转JSONObject
    parameterType
    MyBatis:Parameter Maps collection does not contain value for 的问题解决
    mybatis报ORA-00911: 无效字符
  • 原文地址:https://www.cnblogs.com/stars-one/p/15364750.html
Copyright © 2020-2023  润新知