Phone Jetpack compose 中的数字视觉转换
Phone number visual transformation in Jetpack compose
如何在 Jetpack Compose 中实现 phone 数字视觉转换?我已阅读此 article 卡号。
我想像这样格式化我的 phone 号码 xx xxx xx xx
您可以根据您需要的模式修改您提供的示例link中的一些参数。您需要考虑您想要的最大长度,每个部分之间需要多少 space。
例如,在您给定的 link 中:http://zenandroid.io/using-the-jetpack-composes-visualtransformation-to-create-a-credit-card-text-input/
- 他们在
AnnotatedString.Builder()
中每第 4 个字符后添加 space 您需要在 1、4、6 上使用它。
- 然后他们添加了 2 spaces 这就是为什么他们在
originalToTransformed
中添加 spaces 就像 2,4,6 但你需要 1,2,3 & transformedToOriginal
中的扣除相同
完整代码示例:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
AppTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colors.background
) {
Test()
}
}
}
}
}
@Composable
fun Test() {
var mobileNumber by rememberSaveable { mutableStateOf("") }
Column {
Row(modifier = Modifier.padding(all = 10.dp)) {
Text(
text = "Mobile number",
fontSize = 14.sp,
modifier = Modifier.weight(1f)
)
BasicTextField(
value = mobileNumber,
onValueChange = { mobileNumber = it },
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
visualTransformation = { mobileNumberFilter(it) }
)
}
Box(
modifier = Modifier
.height(1.dp)
.padding(start = 10.dp)
.fillMaxWidth()
.background(Color.Gray)
)
Spacer(modifier = Modifier.height(20.dp))
Text(text = "Actual value:\n$mobileNumber")
}
}
const val mask = "xx xxx xx xx"
fun mobileNumberFilter(text: AnnotatedString): TransformedText {
// change the length
val trimmed =
if (text.text.length >= 9) text.text.substring(0..8) else text.text
val annotatedString = AnnotatedString.Builder().run {
for (i in trimmed.indices) {
append(trimmed[i])
if (i == 1 || i == 4 || i == 6) {
append(" ")
}
}
pushStyle(SpanStyle(color = Color.LightGray))
append(mask.takeLast(mask.length - length))
toAnnotatedString()
}
val phoneNumberOffsetTranslator = object : OffsetMapping {
override fun originalToTransformed(offset: Int): Int {
if (offset <= 1) return offset
if (offset <= 4) return offset + 1
if (offset <= 6) return offset + 2
if (offset <= 9) return offset + 3
return 12
}
override fun transformedToOriginal(offset: Int): Int {
if (offset <= 1) return offset
if (offset <= 4) return offset - 1
if (offset <= 6) return offset - 2
if (offset <= 9) return offset - 3
return 9
}
}
return TransformedText(annotatedString, phoneNumberOffsetTranslator)
}
输出:
对于北美版本:
const val mask = "(xxx) xxx-xxxx"
fun mobileNumberFilter(text: AnnotatedString, formType: FormType):
TransformedText {
if (formType != FormType.SHIPPING_PHONE) {
return VisualTransformation.None.filter(text)
}
// change the length
val trimmed =
if (text.text.length >= 14) text.text.substring(0..13) else text.text
val annotatedString = AnnotatedString.Builder().run {
for (i in trimmed.indices) {
val trimmedPortion = trimmed[i]
if (i == 0) {
append("($trimmedPortion")
} else {
append(trimmedPortion)
}
if (i == 2) {
append(") ")
}
if (i == 5) {
append("-")
}
}
pushStyle(
SpanStyle(color = Color.LightGray)
)
try {
append(mask.takeLast(mask.length - length))
} catch (e: IllegalArgumentException) {
Timber.d(e.localizedMessage?.plus(" reached end of phone number"))
}
toAnnotatedString()
}
val translator = object : OffsetMapping {
override fun originalToTransformed(offset: Int): Int {
if (offset <= 1) return offset
if (offset <= 4) return offset + 1
if (offset <= 9) return offset + 2
return 14
}
override fun transformedToOriginal(offset: Int): Int {
if (offset <= 1) return offset
if (offset <= 4) return offset - 1
if (offset <= 9) return offset - 2
return 14
}
}
return TransformedText(annotatedString, translator)
}
要获得更简洁的版本,请参阅这篇中篇文章:
如何在 Jetpack Compose 中实现 phone 数字视觉转换?我已阅读此 article 卡号。
我想像这样格式化我的 phone 号码 xx xxx xx xx
您可以根据您需要的模式修改您提供的示例link中的一些参数。您需要考虑您想要的最大长度,每个部分之间需要多少 space。
例如,在您给定的 link 中:http://zenandroid.io/using-the-jetpack-composes-visualtransformation-to-create-a-credit-card-text-input/
- 他们在
AnnotatedString.Builder()
中每第 4 个字符后添加 space 您需要在 1、4、6 上使用它。 - 然后他们添加了 2 spaces 这就是为什么他们在
originalToTransformed
中添加 spaces 就像 2,4,6 但你需要 1,2,3 &transformedToOriginal
中的扣除相同
完整代码示例:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
AppTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colors.background
) {
Test()
}
}
}
}
}
@Composable
fun Test() {
var mobileNumber by rememberSaveable { mutableStateOf("") }
Column {
Row(modifier = Modifier.padding(all = 10.dp)) {
Text(
text = "Mobile number",
fontSize = 14.sp,
modifier = Modifier.weight(1f)
)
BasicTextField(
value = mobileNumber,
onValueChange = { mobileNumber = it },
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
visualTransformation = { mobileNumberFilter(it) }
)
}
Box(
modifier = Modifier
.height(1.dp)
.padding(start = 10.dp)
.fillMaxWidth()
.background(Color.Gray)
)
Spacer(modifier = Modifier.height(20.dp))
Text(text = "Actual value:\n$mobileNumber")
}
}
const val mask = "xx xxx xx xx"
fun mobileNumberFilter(text: AnnotatedString): TransformedText {
// change the length
val trimmed =
if (text.text.length >= 9) text.text.substring(0..8) else text.text
val annotatedString = AnnotatedString.Builder().run {
for (i in trimmed.indices) {
append(trimmed[i])
if (i == 1 || i == 4 || i == 6) {
append(" ")
}
}
pushStyle(SpanStyle(color = Color.LightGray))
append(mask.takeLast(mask.length - length))
toAnnotatedString()
}
val phoneNumberOffsetTranslator = object : OffsetMapping {
override fun originalToTransformed(offset: Int): Int {
if (offset <= 1) return offset
if (offset <= 4) return offset + 1
if (offset <= 6) return offset + 2
if (offset <= 9) return offset + 3
return 12
}
override fun transformedToOriginal(offset: Int): Int {
if (offset <= 1) return offset
if (offset <= 4) return offset - 1
if (offset <= 6) return offset - 2
if (offset <= 9) return offset - 3
return 9
}
}
return TransformedText(annotatedString, phoneNumberOffsetTranslator)
}
输出:
对于北美版本:
const val mask = "(xxx) xxx-xxxx"
fun mobileNumberFilter(text: AnnotatedString, formType: FormType):
TransformedText {
if (formType != FormType.SHIPPING_PHONE) {
return VisualTransformation.None.filter(text)
}
// change the length
val trimmed =
if (text.text.length >= 14) text.text.substring(0..13) else text.text
val annotatedString = AnnotatedString.Builder().run {
for (i in trimmed.indices) {
val trimmedPortion = trimmed[i]
if (i == 0) {
append("($trimmedPortion")
} else {
append(trimmedPortion)
}
if (i == 2) {
append(") ")
}
if (i == 5) {
append("-")
}
}
pushStyle(
SpanStyle(color = Color.LightGray)
)
try {
append(mask.takeLast(mask.length - length))
} catch (e: IllegalArgumentException) {
Timber.d(e.localizedMessage?.plus(" reached end of phone number"))
}
toAnnotatedString()
}
val translator = object : OffsetMapping {
override fun originalToTransformed(offset: Int): Int {
if (offset <= 1) return offset
if (offset <= 4) return offset + 1
if (offset <= 9) return offset + 2
return 14
}
override fun transformedToOriginal(offset: Int): Int {
if (offset <= 1) return offset
if (offset <= 4) return offset - 1
if (offset <= 9) return offset - 2
return 14
}
}
return TransformedText(annotatedString, translator)
}
要获得更简洁的版本,请参阅这篇中篇文章: