Jetpack compose - 60行代码实现正方形验证码输入框

实现效果

总的来说就是对输入框显示进行重绘

img.png

1.监听用户输入

TextField是Jetpack compose中获取用户输入内容的常用输入框。
在此我们只需要获取输入法输入内容就行,不需要外观,因此使用BasicTextField即可。
验证码码一般都是纯数字组成,通过KeyboardOptions 的keyboardType来限制输入内容为数字(类似于EditText 的inputType)
但是还需要隐藏输入回显的文本,因此使用Modifier.drawWithContent { }重新覆盖绘制,就能去掉了。

var content by remember { mutableStateOf("") }
BasicTextField(
            value = content,
            keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),//设置仅输入数字
            onValueChange = {
                content = it//保存用户输入的内容
                
            },
            modifier = Modifier
                .drawWithContent { }//清除绘制内容
                .matchParentSize()//填充至父布局大小
        )

还需要响应点击调起输入法的效果,因此可以利用Box将BasicTextField覆盖在我们的重绘的控件上。用户点击的时候实际点击在BasicTextField上便能自动调起输入法。

Box {
    //重新绘制的验证码输入框

    BasicTextField(...
}

2.绘制验证码内容

接下来就是根据输入内容content进行重新绘制
验证码输入框的UI就是横着的一排矩形,使用一个Row完成,然后适当在中间加一些间距。
为了使得矩形框的样式更加灵活,可以将矩形框绘制通过Composable参数向上暴露。

Row(horizontalArrangement = Arrangement.Center,
    verticalAlignment = Alignment.CenterVertically) {
        repeat(digits) {//根据矩形框数量绘制
            if (it != 0) {
                //在中间添加间距
                Spacer(modifier = Modifier.width(horizontalMargin))
            }
            //获取当前框的文本
            val text = content.getOrNull(it)?.toString() ?: ""
            //是否正在输入的框
            val focused = it == content.length
            //绘制文本
            itemScope(text, focused)
        }
    }

然后完成单个矩形框的绘制,使用Text将验证码文本绘制出来就行,由于没发现使Text文本垂直居中的Modifier,所以套上了一个Box。

@Composable
fun SimpleVerificationCodeItem(text: String, focused: Boolean) {
    val borderColor = if (focused) Color.Gray else Color(0xeeeeeeee)

    Box(
        modifier = Modifier
            .border(1.dp, borderColor)
            .size(55.dp, 55.dp), contentAlignment = Alignment.Center
    ) {
        Text(
            text = text,
            fontSize = 24.sp,
            textAlign = TextAlign.Center,
            maxLines = 1
        )
    }

}

完整代码

验证码输入框


/**
 * @param text 文本内容
 * @param focused 是否高亮当前输入框
 */
@Composable
fun SimpleVerificationCodeItem(text: String, focused: Boolean) {
    val borderColor = if (focused) Color.Gray else Color(0xeeeeeeee)

    Box(
        modifier = Modifier
            .border(1.dp, borderColor)
            .size(55.dp, 55.dp), contentAlignment = Alignment.Center
    ) {
        Text(
            text = text,
            fontSize = 24.sp,
            textAlign = TextAlign.Center,
            maxLines = 1
        )
    }

}

/**
 * @param digits 验证码位数(框数量)
 * @param horizontalMargin 水平间距
 * @param inputCallback 输入回调
 */
@Composable
fun VerificationCodeField(
    digits: Int,
    horizontalMargin: Dp = 10.dp,
    inputCallback: (content: String) -> Unit = {},
    itemScope: @Composable (text: String, focused: Boolean) -> Unit
) {
    var content by remember { mutableStateOf("") }
    Box {
        Row(
            horizontalArrangement = Arrangement.Center,
            verticalAlignment = Alignment.CenterVertically
        ) {
            //绘制框
            repeat(digits) {
                if (it != 0) {
                    //添加间距
                    Spacer(modifier = Modifier.width(horizontalMargin))
                }
                //获取当前框的文本
                val text = content.getOrNull(it)?.toString() ?: ""
                //是否正在输入的框
                val focused = it == content.length
                //绘制文本
                itemScope(text, focused)
            }

        }
        BasicTextField(value = content, onValueChange = {
            content = it
            inputCallback(it)
        }, modifier = Modifier
            .drawWithContent { }//清楚绘制内容
            .matchParentSize())//填充至父布局大小
    }

}

使用方法

    VerificationCodeField(5){text,focused->
        SimpleVerificationCodeItem(text,focused)
    }

你可能感兴趣的:(Jetpack compose - 60行代码实现正方形验证码输入框)