實(shí)現(xiàn)效果
總的來說就是對輸入框顯示進(jìn)行重繪
1.監(jiān)聽用戶輸入
TextField是Jetpack compose中獲取用戶輸入內(nèi)容的常用輸入框。
在此我們只需要獲取輸入法輸入內(nèi)容就行埂陆,不需要外觀,因此使用BasicTextField即可。
驗(yàn)證碼碼一般都是純數(shù)字組成,通過KeyboardOptions 的keyboardType來限制輸入內(nèi)容為數(shù)字(類似于EditText 的inputType)
但是還需要隱藏輸入回顯的文本,因此使用Modifier.drawWithContent { }
重新覆蓋繪制振劳,就能去掉了。
var content by remember { mutableStateOf("") }
BasicTextField(
value = content,
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),//設(shè)置僅輸入數(shù)字
onValueChange = {
content = it//保存用戶輸入的內(nèi)容
},
modifier = Modifier
.drawWithContent { }//清除繪制內(nèi)容
.matchParentSize()//填充至父布局大小
)
還需要響應(yīng)點(diǎn)擊調(diào)起輸入法的效果油狂,因此可以利用Box將BasicTextField覆蓋在我們的重繪的控件上历恐。用戶點(diǎn)擊的時(shí)候?qū)嶋H點(diǎn)擊在BasicTextField上便能自動調(diào)起輸入法。
Box {
//重新繪制的驗(yàn)證碼輸入框
BasicTextField(...
}
2.繪制驗(yàn)證碼內(nèi)容
接下來就是根據(jù)輸入內(nèi)容content進(jìn)行重新繪制
驗(yàn)證碼輸入框的UI就是橫著的一排矩形专筷,使用一個(gè)Row完成弱贼,然后適當(dāng)在中間加一些間距。
為了使得矩形框的樣式更加靈活磷蛹,可以將矩形框繪制通過Composable參數(shù)向上暴露吮旅。
Row(horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically) {
repeat(digits) {//根據(jù)矩形框數(shù)量繪制
if (it != 0) {
//在中間添加間距
Spacer(modifier = Modifier.width(horizontalMargin))
}
//獲取當(dāng)前框的文本
val text = content.getOrNull(it)?.toString() ?: ""
//是否正在輸入的框
val focused = it == content.length
//繪制文本
itemScope(text, focused)
}
}
然后完成單個(gè)矩形框的繪制,使用Text將驗(yàn)證碼文本繪制出來就行味咳,由于沒發(fā)現(xiàn)使Text文本垂直居中的Modifier庇勃,所以套上了一個(gè)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
)
}
}
完整代碼
驗(yàn)證碼輸入框
/**
* @param text 文本內(nèi)容
* @param focused 是否高亮當(dāng)前輸入框
*/
@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 驗(yàn)證碼位數(shù)(框數(shù)量)
* @param horizontalMargin 水平間距
* @param inputCallback 輸入回調(diào)
*/
@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))
}
//獲取當(dāng)前框的文本
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 { }//清楚繪制內(nèi)容
.matchParentSize())//填充至父布局大小
}
}
使用方法
VerificationCodeField(5){text,focused->
SimpleVerificationCodeItem(text,focused)
}