Jetpack Compose 文本UI

一. Text文本视图详解

@Composable
fun Text(
    text: String,
    modifier: Modifier = Modifier, //修饰符
    color: Color = Color.Unspecified,
    fontSize: TextUnit = TextUnit.Unspecified,
    fontStyle: FontStyle? = null,
    fontWeight: FontWeight? = null,
    fontFamily: FontFamily? = null,
    letterSpacing: TextUnit = TextUnit.Unspecified,
    textDecoration: TextDecoration? = null,
    textAlign: TextAlign? = null,
    lineHeight: TextUnit = TextUnit.Unspecified,
    overflow: TextOverflow = TextOverflow.Clip,
    softWrap: Boolean = true,
    maxLines: Int = Int.MAX_VALUE,
    onTextLayout: (TextLayoutResult) -> Unit = {},
    style: TextStyle = LocalTextStyle.current
)

TextCompose 中最基本的布局组件,它可以显示文字

@Composable
fun TextDemo() {
    Text("Hello World")
}

res 中加载文字

@Composable
fun TextDemo() {
    Text(stringResource(id = R.string.content))
}
​

    examples
    桃之夭夭,灼灼其华。之子于归,宜其室家。

1. style 参数

style 参数可以帮助我们配置文本的行高,颜色,粗体等设置

Compose` 中内置的 `theme` 已经为我们准备了一些设计, 从 `h1` 到 `overline
@Composable
fun TextDemo() {
    Column{
        Text(
            text = "你好呀陌生人,这是一个标题",
            style = MaterialTheme.typography.h6
        )
        Text(
            text ="你好呀陌生人,我是内容",
            style = MaterialTheme.typography.body2
        )
    }
}

文字间距

@Composable
fun TextDemo() {
    Column(
        modifier = Modifier.fillMaxWidth(),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Text(
            text = "你好陌生人",
            style = TextStyle(
                fontWeight = FontWeight.W900, //设置字体粗细
                fontSize = 20.sp,
                letterSpacing = 7.sp
            )
        )
    }
}

Jetpack Compose 文本UI_第1张图片

2. maxLines 参数

使用 maxLines 参数可以帮助我们将文本限制在指定的行数之间,如果文本足够短则不会生效,如果文本超过 maxLines 所规定的行数,则会进行截断

@Composable
fun TextDemo() {
​
    Column{
        Text(
            text = "你好呀陌生人,这是一个标题,不是很长,因为我想不出其他什么比较好的标题了",
            style = MaterialTheme.typography.h6,
            maxLines = 1,
        )
        Text(
            text ="你好呀陌生人,我是内容",
            style = MaterialTheme.typography.body2
        )
    }
​
}

overflow 处理溢出

使用 overflow 参数可以帮助我们处理溢出的视觉效果

@Composable
fun TextDemo() {
​
    Column{
        Text(
            text = "你好呀陌生人,这是一个标题,不是很长,因为我想不出其他什么比较好的标题了",
            style = MaterialTheme.typography.h6,
            maxLines = 1,
            overflow = TextOverflow.Ellipsis
        )
        Text(
            text ="你好呀陌生人,我是内容",
            style = MaterialTheme.typography.body2
        )
    }
​
}

3. textAlign 参数

当我们在 Text 中设置了 fillMaxWidth() 之后,我们可以指定 Text 的对齐方式

@Composable
fun TextDemo() {
    Column {
        Text(
            text = "每天摸鱼",
            modifier = Modifier.fillMaxWidth(),
            textAlign = TextAlign.Left
        )
        Text(
            text = "这好吗",
            modifier = Modifier.fillMaxWidth(),
            textAlign = TextAlign.Center
        )
        Text(
            text = "这非常的好",
            modifier = Modifier.fillMaxWidth(),
            textAlign = TextAlign.Right
        )
    }
}

注意

需要注意区分的是,TextAlign 设置的是文本的对齐方式,而不是位置方向

4. lineHeight 参数

使用 lineHeight 参数可以让我们指定 Text 中每行的行高间距

Column {
    Text(
        text = "两面包夹芝士".repeat(15),
    )
    Spacer(Modifier.padding(vertical = 15.dp))
    Text(
        text = "两面包夹芝士".repeat(15),
        lineHeight = 30.sp
    )
}

5. fontFamily 参数

使用 fontFamily 参数可以让我们自定义字体,它的调用方法是这样的:

Column {
    Text("Hello World", fontFamily = FontFamily.Serif)
    Text("Hello World", fontFamily = FontFamily.SansSerif)
}

Jetpack Compose 文本UI_第2张图片

你也可以加载 res/font 下的字体。

创建一个 font 文件夹可以右键 res 文件夹,选择 Android Resource Directory -> 选择 font

Text(
    text = "在朋友家度过的一天,我们畅谈了许多美好的事情,由衷的庆幸大家似乎对未来有了更好的期待",
    fontFamily = FontFamily(
        Font(R.font.pingfang, FontWeight.W700)
    )
)

6. 可点击的 Text

有的时候也许您需要将文本当作按钮,那么只需要添加 Modifier.clickable 即可

代码如下:

@Composable
fun TextDemo() {
    Text(
        text = "确认编辑",
        modifier = Modifier.clickable(
            onClick = {
                  // TODO
            },
        )
    )
}

取消点击波纹

但是我们会发现,clickable 有自带的波纹效果,如果我们想要取消的话,只需要添加两个参数即可:

@Composable
fun TextDemo() {
​
    // 获取 context
    val context = LocalContext.current
​
    Text(
        text = "确认编辑",
        modifier = Modifier.clickable(
            onClick = {
                // 通知事件
                Toast.makeText(context, "你点击了此文本", Toast.LENGTH_LONG).show()
            },
            indication = null,
            interactionSource = MutableInteractionSource()
        )
    )
​
}

效果如下:

7. 特定的文字显示

如果我们想让一个 Text 语句中使用不同的样式,比如粗体提醒,特殊颜色

则我们需要使用到 AnnotatedString

AnnotatedString 是一个数据类,其中包含了:

  • 一个 Text 的值

  • 一个 SpanStyleRangeList,等同于位置范围在文字值内的内嵌样式

  • 一个 ParagraphStyleRangeList,用于指定文字对齐、文字方向、行高和文字缩进样式

inline fun  AnnotatedString.Builder.withStyle(
    style: SpanStyle,
    block: AnnotatedString.Builder.() -> crossinline R
): R

一个简单的代码演示:

@Composable
fun TextDemo() {
    Column(
        modifier = Modifier.fillMaxWidth(),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Text(
            buildAnnotatedString {
                append("你现在观看的章节是 ")
                withStyle(style = SpanStyle(fontWeight = FontWeight.W900)) {
                    append("Text")
                }
            }
        )
    }
}

效果如下:

Jetpack Compose 文本UI_第3张图片

8. 文字超链接?(ClickableText)

在第 6 部分我们已经介绍了可以通过 AnnotatedString 来完成在一个 Text 中给不同的文字应用不同的样式

在第 5 部分我们已经介绍了可以通过 Modifier.Clickable() 来完成检测 Text 的点击

但是 Modifier.Clickable() 无法检测 Text 中的部分点击,那如果我们需要检测一个 Text 中的部分点击事件该怎么办呢?就像我们经常在 App 底下看到的用户协议等

其实很简单,Compose 也给我们准备了 ClickableText,来看看如何使用吧!

val text = buildAnnotatedString {
    append("勾选即代表同意")
    withStyle(
        style = SpanStyle(
            color = Color(0xFF0E9FF2),
            fontWeight = FontWeight.Bold
        )
    ) {
        append("用户协议")
    }
}
​
ClickableText(
    text = text,
    onClick = { offset ->
        Log.d(TAG, "Hi,你按到了第 $offset 位的文字")
    }
)

但是...怎么才能检测用户协议这四个字符的点击事件呢?

也不用怕,Compose 还在 buildAnnotatedStringClickableText 中引入了相应的方法

先来看看代码吧!

val annotatedText = buildAnnotatedString {
    append("勾选即代表同意")
    pushStringAnnotation(
        tag = "tag",
        annotation = "一个用户协议啦啦啦,内容内容"
    )
    withStyle(
        style = SpanStyle(
            color = Color(0xFF0E9FF2),
            fontWeight = FontWeight.Bold
        )
    ) {
        append("用户协议")
    }
    pop()
}
​
ClickableText(
    text = annotatedText,
    onClick = { offset ->
        annotatedText.getStringAnnotations(
            tag = "tag", start = offset,
            end = offset
        ).firstOrNull()?.let { annotation ->
            Log.d(TAG, "你已经点到 ${annotation.item} 啦")
        }
    }
)

在上面的代码中

  1. 多了一个 pushStringAnnotation() 方法,它会将给定的注释附加到任何附加的文本上,直到相应的 pop 被调用

  2. getStringAnnotations() 方法是查询附加在这个 AnnotatedString 上的字符串注释。注释是附加在 AnnotatedString 上的元数据,例如,在我们的代码中 "tag" 是附加在某个范围上的字符串元数据。注释也与样式一起存储在 Range

小试牛刀

那么,你已经学会了如何自定义 Text 中的样式和点击事件,来尝试做出一个这样的效果?

9. 文字复制

默认情况下 Text 并不能进行复制等操作,我们需要设置 SelectionContainer 来包装 Text

@Composable
fun TextDemo() {
    
    SelectionContainer {
        Column{
            Text(
                text = "每天摸鱼",
                modifier = Modifier.fillMaxWidth(),
                textAlign = TextAlign.Left
            )
            Text(
                text = "这好吗",
                modifier = Modifier.fillMaxWidth(),
                textAlign = TextAlign.Center
            )
            Text(
                text = "这非常的好",
                modifier = Modifier.fillMaxWidth(),
                textAlign = TextAlign.Right
            )
        }
    }
    
}

10. 文字强调效果

文字根据不同情况来确定文字的强调程度,以突出重点并体现出视觉上的层次感。

Material Design 建议采用不同的不透明度来传达这些不同的重要程度,你可以通过 LocalContentAlpha 实现此功能。

您可以通过为此 CompositionLocal 提供一个值来为层次结构指定内容 Alpha 值。(CompositionLocal 是一个用于隐式的传递参数的组件,后续会讲到)

// 将内部 Text 组件的 alpha 强调程度设置为高
// 注意: MaterialTheme 已经默认将强调程度设置为 high
CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.high) {
    Text("这里是high强调效果")
}
// 将内部 Text 组件的 alpha 强调程度设置为中
CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.medium) {
    Text("这里是medium强调效果")
}
// 将内部 Text 组件的 alpha 强调程度设置为禁用
CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.disabled) {
    Text("这里是禁用后的效果")
}

这是运行效果:

这张图可以很好的说明这个效果

11. 文字水平位置

一般情况下,Text 不会水平居中,如果你在 Row, Column, Box 这些 Composable 里面想要实现居中的效果,你可以在 Text 外围写一个 Box, Row, Column

像这样:

Column {
    Text("123")
    Text("456")
    Box(
        modifier = Modifier.fillMaxWidth(),
        contentAlignment = Alignment.Center
    ) {
        Text("789")
    }
}

水平靠左: Alignment.Start

水平靠右: Alignment.End

如果你的 ColumnModifier.fillMaxWidth() 的属性或者指定了宽度/大小,那么你可以直接在 Text 里面写 Modifier.align(Alignment.CenterHorizontally) 来让 Text 处于水平居中的位置

二. Image图片视图详解

@Composable
fun Image(
    painter: Painter,
    contentDescription: String?,
    modifier: Modifier = Modifier,
    alignment: Alignment = Alignment.Center,
    contentScale: ContentScale = ContentScale.Fit,
    alpha: Float = DefaultAlpha,
    colorFilter: ColorFilter? = null
)

Image 可以帮我们加载一张图片。

@Composable
fun ImageDemo() {
​
    Image(
        painter = painterResource(id = R.drawable.wallpaper),
        contentDescription = null
    )
​
}

1. 图片大小

我们可以使用 Modifier.size() 来设置图片大小。

@Composable
fun ImageDemo() {
​
    Image(
        painter = painterResource(id = R.drawable.wallpaper),
        contentDescription = null,
        modifier = Modifier.size(350.dp)
    )
​
}

2. 图片形状

我们可以使用 Surface 来帮助我们设置形状,或者在 Image 组件中使用 modifier.clip() 来裁剪形状。

@Composable
fun ImageDemo() {
​
    Surface(
        shape = CircleShape
    ) {
        Image(
            painter = painterResource(id = R.drawable.wallpaper),
            contentDescription = null,
            modifier = Modifier.size(350.dp)
        )
    }
​
}

是不是有一点小问题?似乎只有左右两边变成了圆形,而上下并没有。

这是因为 Image 中源码的 contentScale 参数默认是 ContentScale.Fit

也就是保持图片的宽高比,缩小到可以完整显示整张图片。

ContentScale.Crop 也是保持宽高比,但是尽量让宽度或者高度完整的占满。

所以我们将 contentScale 设置成 ContentScale.Crop

@Composable
fun ImageDemo() {
​
    Surface(
        shape = CircleShape
    ) {
        Image(
            painter = painterResource(id = R.drawable.wallpaper),
            contentDescription = null,
            modifier = Modifier.size(350.dp),
            contentScale = ContentScale.Crop
        )
    }
​
}

3. 图像边框

你可以利用 Surface 中的 border 参数来设置边框。

@Composable
fun ImageDemo() {
​
    Surface(
        shape = CircleShape,
        border = BorderStroke(5.dp, Color.Gray)
    ) {
        Image(
            painter = painterResource(id = R.drawable.wallpaper),
            contentDescription = null,
            modifier = Modifier.size(350.dp),
            contentScale = ContentScale.Crop
        )
    }
​
}

4. 使用 Coil 来动态加载图片

Compose 自带的 Image 只能加载资源管理器中的图片文件,如果想加载网络图片或者是其他本地路径下的文件,则需要考虑其他的库,比如 Coil

简单使用 Coil 加载网络图片:

记得打开网络权限测试

Image(
    painter = rememberImagePainter(data = "https://picsum.photos/300/300"),
    contentDescription = null
)

三. TextField输入框视图详解

@Composable
fun TextField(
    value: String,
    onValueChange: (String) -> Unit,
    modifier: Modifier = Modifier,
    enabled: Boolean = true,
    readOnly: Boolean = false,
    textStyle: TextStyle = LocalTextStyle.current,
    label: @Composable (() -> Unit)? = null,
    placeholder: @Composable (() -> Unit)? = null,
    leadingIcon: @Composable (() -> Unit)? = null,
    trailingIcon: @Composable (() -> Unit)? = null,
    isError: Boolean = false,
    visualTransformation: VisualTransformation = VisualTransformation.None,
    keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
    keyboardActions: KeyboardActions = KeyboardActions(),
    singleLine: Boolean = false,
    maxLines: Int = Int.MAX_VALUE,
    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
    shape: Shape =
        MaterialTheme.shapes.small.copy(bottomEnd = ZeroCornerSize, bottomStart = ZeroCornerSize),
    colors: TextFieldColors = TextFieldDefaults.textFieldColors()
)

下面是一个TextFiled的简单例子:

TextField(
    value = text,
    onValueChange = {
        text = it
    },
    modifier = Modifier.height(20.dp)
)

如果你想自定义一个 TextField 的高度,以及其他的自定义效果,你应该使用 BasicTextField

一个简单的 TextField 使用的例子是这样的:

import androidx.compose.runtime.*
​
@Composable
fun TextFieldDemo() {
    var text by remember{ mutableStateOf("")}
​
    TextField(
        value = text,
        onValueChange = {
            text = it
        }
    )
}

1. singleLine 参数

使用 singleLine 参数可以将 TextField 设置成只有一行

设置了 singleLine 再设置 maxLines 将无效

@Composable
fun TextFieldDemo() {
    var text by remember{ mutableStateOf("")}
​
    TextField(
        value = text,
        onValueChange = {
            text = it
        },
        singleLine = true
    )
}

2. label 参数

label 标签可以运用在 TextField 中,当聚焦的时候会改变字体大小

@Composable
fun TextFieldDemo() {
    var text by remember{ mutableStateOf("")}
​
    Column(
        modifier = Modifier
            .fillMaxWidth(),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        TextField(
            value = text,
            onValueChange = {
                text = it
            },
            singleLine = true,
            label = {
                Text("邮箱")
            }
        )
    }
}

3. leadingIcon 参数

leadingIcon 参数可以在 TextField 前面布置 lambda 表达式所接收到的东西

TextField(
    value = text,
    onValueChange = {
        text = it
    },
    leadingIcon = {
        Icon(Icons.Filled.Search, null)
    },
)

Jetpack Compose 文本UI_第4张图片

虽然名字上叫做 leadingIcon,但是 leadingIcon 接收来自一个 @Composable 函数的 lambda 表达式,

我们也可以在里面填入 Text 函数

TextField(
    value = text,
    onValueChange = {
        text = it
    },
    leadingIcon = {
        Text("联系人")
    },
)

Jetpack Compose 文本UI_第5张图片

4. trailingIcon 参数

trailingIcon 参数可以在 TextField 尾部布置 lambda 表达式所接收到的东西

TextField(
    value = text,
    onValueChange = {
        text = it
    },
    trailingIcon = {
        Text("@163.com")
    },
)

trailingIcon = {
    IconButton(onClick = {
        
    }){
        Icon(Icons.Filled.Send, null)
    }
},

5. Color 参数

@Composable
fun textFieldColors(
    // 输入的文字颜色
    textColor: Color = LocalContentColor.current.copy(LocalContentAlpha.current),
​
    // 禁用 TextField 时,已有的文字颜色
    disabledTextColor: Color = textColor.copy(ContentAlpha.disabled),
​
    // 输入框的背景颜色,当设置为 Color.Transparent 时,将透明
    backgroundColor: Color = MaterialTheme.colors.onSurface.copy(alpha = BackgroundOpacity),
​
    // 输入框的光标颜色
    cursorColor: Color = MaterialTheme.colors.primary,
​
    // 当 TextField 的 isError 参数为 true 时,光标的颜色
    errorCursorColor: Color = MaterialTheme.colors.error,
​
    // 当输入框处于焦点时,底部指示器的颜色
    focusedIndicatorColor: Color = MaterialTheme.colors.primary.copy(alpha = ContentAlpha.high),
​
    // 当输入框不处于焦点时,底部指示器的颜色
    unfocusedIndicatorColor: Color = MaterialTheme.colors.onSurface.copy(alpha = UnfocusedIndicatorLineOpacity),
​
    // 禁用 TextField 时,底部指示器的颜色
    disabledIndicatorColor: Color = unfocusedIndicatorColor.copy(alpha = ContentAlpha.disabled),
​
    // 当 TextField 的 isError 参数为 true 时,底部指示器的颜色
    errorIndicatorColor: Color = MaterialTheme.colors.error,
​
    // TextField 输入框前头的颜色
    leadingIconColor: Color = MaterialTheme.colors.onSurface.copy(alpha = IconOpacity),
​
    // 禁用 TextField 时 TextField 输入框前头的颜色
    disabledLeadingIconColor: Color = leadingIconColor.copy(alpha = ContentAlpha.disabled),
​
    // 当 TextField 的 isError 参数为 true 时 TextField 输入框前头的颜色
    errorLeadingIconColor: Color = leadingIconColor,
​
    // TextField 输入框尾部的颜色
    trailingIconColor: Color = MaterialTheme.colors.onSurface.copy(alpha = IconOpacity),
​
    // 禁用 TextField 时 TextField 输入框尾部的颜色
    disabledTrailingIconColor: Color = trailingIconColor.copy(alpha = ContentAlpha.disabled),
​
    // 当 TextField 的 isError 参数为 true 时 TextField 输入框尾部的颜色
    errorTrailingIconColor: Color = MaterialTheme.colors.error,
​
    // 当输入框处于焦点时,Label 的颜色
    focusedLabelColor: Color = MaterialTheme.colors.primary.copy(alpha = ContentAlpha.high),
​
    // 当输入框不处于焦点时,Label 的颜色
    unfocusedLabelColor: Color = MaterialTheme.colors.onSurface.copy(ContentAlpha.medium),
​
    // 禁用 TextField 时,Label 的颜色
    disabledLabelColor: Color = unfocusedLabelColor.copy(ContentAlpha.disabled),
​
    // 当 TextField 的 isError 参数为 true 时,Label 的颜色
    errorLabelColor: Color = MaterialTheme.colors.error,
​
    // Placeholder 的颜色
    placeholderColor: Color = MaterialTheme.colors.onSurface.copy(ContentAlpha.medium),
​
    // 禁用 TextField 时,placeholder 的颜色
    disabledPlaceholderColor: Color = placeholderColor.copy(ContentAlpha.disabled)
)

调用方法

TextField(
    value = text,
    onValueChange = {
        text = it
    },
    leadingIcon = {
        Icon(Icons.Filled.Search, null)
    },
    colors = TextFieldDefaults.textFieldColors(
        textColor = Color(0xFF0079D3),
        backgroundColor = Color.Transparent
    )
)

在你使用 IDE 智能补全的时候可能遇到这种情况

解决方法如下,手动打完函数名

6. visualTransformation 参数

visualTransformation 可以帮助我们应用输入框的显示模式

var text by remember{mutableStateOf("")}
var passwordHidden by remember{ mutableStateOf(false)}
​
TextField(
    value = text,
    onValueChange = {
        text = it
    },
    trailingIcon = {
        IconButton(
            onClick = {
                passwordHidden = !passwordHidden
            }
        ){
            Icon(painterResource(id = R.drawable.visibility), null)
        }
    },
    label = {
        Text("密码")
    },
    visualTransformation = if(passwordHidden) PasswordVisualTransformation() else VisualTransformation.None
)

四. BasicTextField视图讲解

@Composable
fun BasicTextField(
  value: String,
  onValueChange: (String) -> Unit,
  modifier: Modifier = Modifier,
  enabled: Boolean = true,
  readOnly: Boolean = false,
  textStyle: TextStyle = TextStyle.Default,
  keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
  keyboardActions: KeyboardActions = KeyboardActions.Default,
  singleLine: Boolean = false,
  maxLines: Int = Int.MAX_VALUE,
  visualTransformation: VisualTransformation = VisualTransformation.None,
  onTextLayout: (TextLayoutResult) -> Unit = {},
  // 当输入框内文本触发更新时候的回调,包括了当前文本的各种信息
  interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
  cursorBrush: Brush = SolidColor(Color.Black),
  // 输入框光标的颜色
  decorationBox: @Composable (innerTextField: @Composable () -> Unit) -> Unit =
    @Composable { innerTextField -> innerTextField() }
  // 是一个允许在 TextField 周围添加修饰的 @Composable lambda
  // 我们需要在布局中调用 innerTextField() 才能完成 TextField 的构建
)

使用 BasicTextField 可以让你拥有更高的自定义效果

1. 简单使用

一个简单的使用例子如下:

var text by remember { mutableStateOf("") }
​
Box(
    modifier = Modifier
        .fillMaxSize()
        .background(Color(0xFFD3D3D3)),
    contentAlignment = Alignment.Center
) {
    BasicTextField(
        value = text,
        onValueChange = {
            text = it
        },
        modifier = Modifier
            .background(Color.White, CircleShape)
            .height(35.dp)
            .fillMaxWidth(),
        decorationBox = { innerTextField ->
            Row(
                verticalAlignment = Alignment.CenterVertically,
                modifier = Modifier.padding(horizontal = 10.dp)
            ) {
                IconButton(
                    onClick = { }
                ) {
                    Icon(painterResource(id = R.drawable.mood), null)
                }
                Box(
                    modifier = Modifier.weight(1f),
                    contentAlignment = Alignment.CenterStart
                ) {
                    innerTextField()
                }
                IconButton(
                    onClick = { },
                ) {
                    Icon(Icons.Filled.Send, null)
                }
            }
        }
    )
}

在刚才的例子中,我们在 decorationBox 里面写了很多布局组件,最后通过调用一次 innerTextFiled() 来完成输入框的构建。

2. 其他效果

五. Button按钮视图详解

1. Button属性

@OptIn(ExperimentalMaterialApi::class)
@Composable
fun Button(
    onClick: () -> Unit,
    modifier: Modifier = Modifier,
    enabled: Boolean = true,
    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
    elevation: ButtonElevation? = ButtonDefaults.elevation(),
    shape: Shape = MaterialTheme.shapes.small,
    border: BorderStroke? = null,
    colors: ButtonColors = ButtonDefaults.buttonColors(),
    contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
    content: @Composable RowScope.() -> Unit
)

ComposeButton 是基于 Material Design 理念设计的

2. 使用示例

2.1 基本使用

以下是简单创建一个默认的 Button 代码:

import androidx.compose.material.Button
import androidx.compose.material.Text
​
@Composable
fun ButtonDemo() {
    Button(
        onClick = { /*TODO*/ }
    ) {
        Text("确认")
    }
}

效果如图所示:

Jetpack Compose 文本UI_第6张图片

也许您想添加图标在文字的旁边,也只需:

@Composable
fun ButtonDemo() {
    Button(onClick = { /*TODO*/ }) {
        Icon(
            // Material 库中的图标,有 Filled, Outlined, Rounded, Sharp, Two Tone 等
            Icons.Filled.Favorite,
            contentDescription = null,
            modifier = Modifier.size(ButtonDefaults.IconSize)
        )
        // 添加间隔
        Spacer(Modifier.size(ButtonDefaults.IconSpacing))
        Text("喜欢")
    }
}

Jetpack Compose 文本UI_第7张图片

2.2 不同点击状态下的按钮状态

创建 Data class 来记录不同状态下按钮的样式

data class ButtonState(var text: String, var textColor: Color, var buttonColor: Color)

使用 MutableInteractionSource() 获取状态,根据不同状态创建样式

// 获取按钮的状态
val interactionState = remember { MutableInteractionSource() }
​
// 使用 Kotlin 的解构方法
val (text, textColor, buttonColor) = when {
    interactionState.collectIsPressedAsState().value  -> ButtonState("Just Pressed", Color.Red, Color.Black)
    else -> ButtonState( "Just Button", Color.White, Color.Red)
}

Button 的实现

Button(
    onClick = { /*TODO*/ },
    interactionSource = interactionState,
    elevation = null,
    shape = RoundedCornerShape(50),
    colors = ButtonDefaults.buttonColors(
        backgroundColor = buttonColor,
    ),
    modifier = Modifier.width(IntrinsicSize.Min).height(IntrinsicSize.Min)
) {
    Text(
        text = text, color = textColor
    )
}

六. Alertdialog弹出框详解

@Composable
fun AlertDialog(
    onDismissRequest: () -> Unit,
    confirmButton: () -> Unit,
    modifier: Modifier = Modifier,
    dismissButton: () -> Unit = null,
    title: () -> Unit = null,
    text: () -> Unit = null,
    shape: Shape = MaterialTheme.shapes.medium,
    backgroundColor: Color = MaterialTheme.colors.surface,
    contentColor: Color = contentColorFor(backgroundColor),
    properties: DialogProperties = DialogProperties()
): @Composable Unit

1. 简单使用

val openDialog = remember { mutableStateOf(true) }
​
if (openDialog.value) {
    AlertDialog(
        onDismissRequest = {
            // 当用户点击对话框以外的地方或者按下系统返回键将会执行的代码
            openDialog.value = false
        },
        title = {
            Text(
                text = "开启位置服务",
                fontWeight = FontWeight.W700,
                style = MaterialTheme.typography.h6
            )
        },
        text = {
            Text(
                text = "这将意味着,我们会给您提供精准的位置服务,并且您将接受关于您订阅的位置信息",
                fontSize = 16.sp
            )
        },
        confirmButton = {
            TextButton(
                onClick = {
                    openDialog.value = false
                },
            ) {
                Text(
                    "确认",
                    fontWeight = FontWeight.W700,
                    style = MaterialTheme.typography.button
                )
            }
        },
        dismissButton = {
            TextButton(
                onClick = {
                    openDialog.value = false
                }
            ) {
                Text(
                    "取消",
                    fontWeight = FontWeight.W700,
                    style = MaterialTheme.typography.button
                )
            }
        }
    )
}

如果一切顺利,运行程序,您将会看到:

AlertDialog 将根据可用空间来定位其按钮。默认情况下,它将尝试将它们水平地放在彼此的旁边,如果没有足够的空间,则退回到水平放置。还有另一个版本的 Composable,它有一个按钮槽,可以提供自定义的按钮布局

@Composable
fun AlertDialog(
    onDismissRequest: () -> Unit,
    buttons: () -> Unit,
    modifier: Modifier = Modifier,
    title: () -> Unit = null,
    text: () -> Unit = null,
    shape: Shape = MaterialTheme.shapes.medium,
    backgroundColor: Color = MaterialTheme.colors.surface,
    contentColor: Color = contentColorFor(backgroundColor),
    properties: DialogProperties = DialogProperties()
): @Composable Unit

简单的一个实现代码:

val openDialog = remember { mutableStateOf(true) }
​
if (openDialog.value) {
    AlertDialog(
        onDismissRequest = {
            openDialog.value = false
        },
        title = {
            Text(
                text = "开启位置服务",
                fontWeight = FontWeight.W700,
                style = MaterialTheme.typography.h6
            )
        },
        text = {
            Text(
                text = "这将意味着,我们会给您提供精准的位置服务,并且您将接受关于您订阅的位置信息",
                fontSize = 16.sp
            )
        },
        buttons = {
            Row(
                modifier = Modifier.padding(all = 8.dp),
                horizontalArrangement = Arrangement.Center
            ) {
                Button(
                    modifier = Modifier.fillMaxWidth(),
                    onClick = { openDialog.value = false }
                ) {
                    Text("必须接受!")
                }
            }
        }
    )
}

2. Dialog

AlertDialog 在一些情况下有可能还是无法满足我们的业务要求,这时候我们就可以使用更底层的一个 @Composable 函数 —— Dialog

var flag by remember{ mutableStateOf(false) }
Box(
    modifier = Modifier.fillMaxSize(),
    contentAlignment = Alignment.Center
) {
    Button(
        onClick = { flag = true }
    ) {
        Text("弹窗")
    }
}
if(flag) {
    Dialog(
        onDismissRequest = { flag = false }
    ) {
        Box(
            modifier = Modifier
                .size(300.dp)
                .background(Color.White),
            contentAlignment = Alignment.Center
        ) {
            Column {
                LinearProgressIndicator()
                Text("加载中 ing...")
            }
        }
    }
}

你可能感兴趣的:(Android,ui,java,前端)