Android 原生+Compose自定义数字键盘

507 阅读2分钟

Android 原生+Compose自定义数字键盘

Compose 库引用

implementation("androidx.compose.material:material:1.6.3")

创建自定义View

  1. 自定义KBoardView继承FrameLayout
  2. 创建ComposeView添加到KBoardView
  3. ComposeView中绘制验证框和键盘
  4. 上边框用Card实现,下边键盘用LazyVerticalGrid实现
  5. 添加成功回调和错误反馈
  6. 将自定义View加载到layout布局中

效果

Screen_recording_20240322_102219 00_00_00-00_00_30.gif

代码实现

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"/>