Android 原生+Compose自定义数字键盘
Compose 库引用
implementation("androidx.compose.material:material:1.6.3")
创建自定义View
- 自定义
KBoardView继承FrameLayout - 创建
ComposeView添加到KBoardView - 在
ComposeView中绘制验证框和键盘 - 上边框用
Card实现,下边键盘用LazyVerticalGrid实现 - 添加成功回调和错误反馈
- 将自定义View加载到layout布局中
效果
代码实现
package com.nio.keyboard
import android.content.Context
import android.util.AttributeSet
import android.widget.FrameLayout
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Card
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Clear
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
/**
* @author Administrator
* @date 2024/3/13 0013 16:37
* @description: KBoardView
*/
class KBoardView : FrameLayout {
interface OnResultListener {
fun onConfirm(vad: String)
}
fun setOnResultListener(onResultListener: OnResultListener) {
o = onResultListener;
}
private var o: OnResultListener? = null
private var err: String? = null
fun tt(error: String) {
err = error
}
constructor(context: Context) : super(context) {
init(context)
}
private fun init(context: Context) {
val v = ComposeView(context)
val f = LayoutParams(
LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT
)
addView(v, f)
v.setContent {
var text1 by remember {
mutableStateOf("")
}
var text2 by remember {
mutableStateOf("")
}
var text3 by remember {
mutableStateOf("")
}
var text4 by remember {
mutableStateOf("")
}
var text5 by remember {
mutableStateOf("")
}
var text6 by remember {
mutableStateOf("")
}
Column {
Box(
modifier = Modifier
.height(24.dp)
.fillMaxWidth(),
contentAlignment = Alignment.Center
) {
if (err?.isNotEmpty() == true) {
Text(
text = err!!,
color = Color.Red
)
}
}
Row(
Modifier
.fillMaxWidth()
.padding(horizontal = 24.dp)
) {
repeat(6) {
val text = when (it) {
0 -> text1
1 -> text2
2 -> text3
3 -> text4
4 -> text5
5 -> text6
else -> ""
}
Card(
Modifier
.size(40.dp),
shape = RoundedCornerShape(4.dp),
border = BorderStroke(
1.dp,
if (text.isNullOrEmpty()) Color.LightGray else Color.Transparent
),
elevation = if (text.isNullOrEmpty()) 0.dp else 16.dp
) {
Box(
modifier = Modifier
.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Text(
text,
Modifier
.wrapContentSize(),
textAlign = TextAlign.Center,
color = Color.Black,
fontWeight = FontWeight.SemiBold
)
}
}
if (it != 6) {
Spacer(modifier = Modifier.width(12.dp))
}
}
}
Spacer(modifier = Modifier.weight(1f, true))
LazyVerticalGrid(
columns = GridCells.Fixed(3),
verticalArrangement = Arrangement.spacedBy(8.dp),
horizontalArrangement = Arrangement.spacedBy(8.dp),
contentPadding = PaddingValues(8.dp),
modifier = Modifier.background(Color(0xFFf8f8f8))
) {
val nums = arrayOf(7, 8, 9, 4, 5, 6,1,2,3, -1, 0, -2)
repeat(12) {
item {
if (nums[it] != -1) {
Box(
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.background(
if (nums[it] == -2) Color.Transparent else Color.White,
RoundedCornerShape(4.dp)
)
.clickable {
if (nums[it] == -2) {//delete
if (text6.isNotEmpty()) {
text6 = ""
} else if (text5.isNotEmpty()) {
text5 = ""
} else if (text4.isNotEmpty()) {
text4 = ""
} else if (text3.isNotEmpty()) {
text3 = ""
} else if (text2.isNotEmpty()) {
text2 = ""
} else if (text1.isNotEmpty()) {
text1 = ""
}
err = ""
} else {//add
if (text1.isNullOrEmpty()) {
text1 = nums[it].toString()
} else if (text2.isNullOrEmpty()) {
text2 = nums[it].toString()
} else if (text3.isNullOrEmpty()) {
text3 = nums[it].toString()
} else if (text4.isNullOrEmpty()) {
text4 = nums[it].toString()
} else if (text5.isNullOrEmpty()) {
text5 = nums[it].toString()
} else if (text6.isNullOrEmpty()) {
text6 = nums[it].toString()
if (o != null) {
o!!.onConfirm("$text1$text2$text3$text4$text5$text6")
}
}
}
},
contentAlignment = Alignment.Center
) {
if (nums[it] == -2) {
Image(
imageVector = Icons.Default.Clear,
contentDescription = "delete"
)
} else {
Text(
text = "${nums[it]}",
textAlign = TextAlign.Center,
fontWeight = FontWeight.Bold
)
}
}
}
}
}
}
}
}
}
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
init(context)
}
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
context,
attrs,
defStyleAttr
) {
init(context)
}
constructor(
context: Context,
attrs: AttributeSet?,
defStyleAttr: Int,
defStyleRes: Int
) : super(context, attrs, defStyleAttr, defStyleRes) {
init(context)
}
}
布局应用
<com.nio.keyboard.KBoardView
android:id="@+id/kBoardView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>