在 Jetpack Compose 中实现 iOS 风格输入框

要在 Android Compose 中模仿 iOS 风格的输入框,我们需要关注几个关键特点:简洁的边框、圆角设计、特定的交互效果等。以下是完整的实现方案:

1. 基础 iOS 风格输入框

kotlin 复制代码
@Composable
fun IosStyleTextField(
    value: String,
    onValueChange: (String) -> Unit,
    modifier: Modifier = Modifier,
    label: String? = null,
    placeholder: String? = null
) {
    Column(modifier = modifier) {
        label?.let {
            Text(
                text = it,
                style = MaterialTheme.typography.bodyMedium,
                color = Color.Gray,
                modifier = Modifier.padding(bottom = 4.dp)
            )
        }
        
        Box(
            modifier = Modifier
                .fillMaxWidth()
                .background(
                    color = Color.White,
                    shape = RoundedCornerShape(10.dp)
                )
                .border(
                    width = 1.dp,
                    color = Color(0xFFC7C7CC),
                    shape = RoundedCornerShape(10.dp)
                )
                .padding(horizontal = 16.dp, vertical = 12.dp)
        ) {
            BasicTextField(
                value = value,
                onValueChange = onValueChange,
                modifier = Modifier.fillMaxWidth(),
                textStyle = MaterialTheme.typography.bodyMedium.copy(
                    color = Color.Black
                ),
                singleLine = true,
                decorationBox = { innerTextField ->
                    if (value.isEmpty() && placeholder != null) {
                        Text(
                            text = placeholder,
                            style = MaterialTheme.typography.bodyMedium.copy(
                                color = Color(0xFFC7C7CC)
                            )
                        )
                    }
                    innerTextField()
                }
            )
        }
    }
}

// 使用示例
var text by remember { mutableStateOf("") }
IosStyleTextField(
    value = text,
    onValueChange = { text = it },
    label = "用户名",
    placeholder = "请输入用户名",
    modifier = Modifier.padding(16.dp)
)

2. 带清除按钮的 iOS 风格输入框

kotlin 复制代码
@Composable
fun IosStyleTextFieldWithClear(
    value: String,
    onValueChange: (String) -> Unit,
    modifier: Modifier = Modifier,
    label: String? = null,
    placeholder: String? = null
) {
    Column(modifier = modifier) {
        label?.let {
            Text(
                text = it,
                style = MaterialTheme.typography.bodyMedium,
                color = Color.Gray,
                modifier = Modifier.padding(bottom = 4.dp)
            )
        }
        
        Box(
            modifier = Modifier
                .fillMaxWidth()
                .background(
                    color = Color.White,
                    shape = RoundedCornerShape(10.dp)
                )
                .border(
                    width = 1.dp,
                    color = if (value.isNotEmpty()) Color(0xFF007AFF) else Color(0xFFC7C7CC),
                    shape = RoundedCornerShape(10.dp)
                )
                .padding(horizontal = 16.dp, vertical = 12.dp)
        ) {
            Row(
                verticalAlignment = Alignment.CenterVertically,
                modifier = Modifier.fillMaxWidth()
            ) {
                BasicTextField(
                    value = value,
                    onValueChange = onValueChange,
                    modifier = Modifier.weight(1f),
                    textStyle = MaterialTheme.typography.bodyMedium.copy(
                        color = Color.Black
                    ),
                    singleLine = true,
                    decorationBox = { innerTextField ->
                        if (value.isEmpty() && placeholder != null) {
                            Text(
                                text = placeholder,
                                style = MaterialTheme.typography.bodyMedium.copy(
                                    color = Color(0xFFC7C7CC))
                            )
                        }
                        innerTextField()
                    }
                )
                
                if (value.isNotEmpty()) {
                    IconButton(
                        onClick = { onValueChange("") },
                        modifier = Modifier.size(20.dp)
                    ) {
                        Icon(
                            imageVector = Icons.Default.Close,
                            contentDescription = "清除",
                            tint = Color(0xFFC7C7CC),
                            modifier = Modifier.size(16.dp)
                        )
                    }
                }
            }
        }
    }
}

3. 搜索框样式

kotlin 复制代码
@Composable
fun IosStyleSearchField(
    value: String,
    onValueChange: (String) -> Unit,
    modifier: Modifier = Modifier,
    placeholder: String = "搜索"
) {
    Box(
        modifier = modifier
            .fillMaxWidth()
            .height(36.dp)
            .background(
                color = Color(0xFFF2F2F7),
                shape = RoundedCornerShape(10.dp)
            )
            .padding(horizontal = 8.dp),
        contentAlignment = Alignment.CenterStart
    ) {
        Row(
            verticalAlignment = Alignment.CenterVertically,
            modifier = Modifier.fillMaxWidth()
        ) {
            Icon(
                imageVector = Icons.Default.Search,
                contentDescription = "搜索",
                tint = Color(0xFF8E8E93),
                modifier = Modifier.size(16.dp)
                    .padding(end = 4.dp)
            )
            
            BasicTextField(
                value = value,
                onValueChange = onValueChange,
                modifier = Modifier.weight(1f),
                textStyle = MaterialTheme.typography.bodyMedium.copy(
                    color = Color.Black,
                    fontSize = 14.sp
                ),
                singleLine = true,
                decorationBox = { innerTextField ->
                    if (value.isEmpty()) {
                        Text(
                            text = placeholder,
                            style = MaterialTheme.typography.bodyMedium.copy(
                                color = Color(0xFF8E8E93),
                                fontSize = 14.sp
                            )
                        )
                    }
                    innerTextField()
                }
            )
            
            if (value.isNotEmpty()) {
                IconButton(
                    onClick = { onValueChange("") },
                    modifier = Modifier.size(20.dp)
                ) {
                    Icon(
                        imageVector = Icons.Default.Close,
                        contentDescription = "清除",
                        tint = Color(0xFF8E8E93),
                        modifier = Modifier.size(16.dp)
                    )
                }
            }
        }
    }
}

4. 带分段的 iOS 风格表单

kotlin 复制代码
@Composable
fun IosStyleForm(
    items: List<Pair<String, @Composable () -> Unit>>,
    modifier: Modifier = Modifier
) {
    Column(
        modifier = modifier
            .background(Color.White)
            .clip(RoundedCornerShape(10.dp))
    ) {
        items.forEachIndexed { index, (title, content) ->
            Column {
                if (index > 0) {
                    Divider(
                        color = Color(0xFFC6C6C8),
                        thickness = 0.5.dp,
                        modifier = Modifier.padding(horizontal = 16.dp)
                    )
                }
                
                Row(
                    modifier = Modifier
                        .fillMaxWidth()
                        .padding(horizontal = 16.dp, vertical = 12.dp),
                    verticalAlignment = Alignment.CenterVertically,
                    horizontalArrangement = Arrangement.SpaceBetween
                ) {
                    Text(
                        text = title,
                        style = MaterialTheme.typography.bodyMedium.copy(
                            color = Color.Black
                        ),
                        modifier = Modifier.weight(1f)
                    )
                    
                    Box(modifier = Modifier.weight(1f)) {
                        content()
                    }
                }
            }
        }
    }
}

// 使用示例
var username by remember { mutableStateOf("") }
var password by remember { mutableStateOf("") }

IosStyleForm(
    items = listOf(
        "账号" to {
            BasicTextField(
                value = username,
                onValueChange = { username = it },
                modifier = Modifier.fillMaxWidth(),
                textStyle = MaterialTheme.typography.bodyMedium.copy(
                    textAlign = TextAlign.End
                )
            )
        },
        "密码" to {
            BasicTextField(
                value = password,
                onValueChange = { password = it },
                modifier = Modifier.fillMaxWidth(),
                textStyle = MaterialTheme.typography.bodyMedium.copy(
                    textAlign = TextAlign.End
                ),
                visualTransformation = PasswordVisualTransformation()
            )
        }
    ),
    modifier = Modifier.padding(16.dp)
)

5. 动画效果增强

kotlin 复制代码
@Composable
fun AnimatedIosTextField(
    value: String,
    onValueChange: (String) -> Unit,
    modifier: Modifier = Modifier,
    label: String,
    placeholder: String
) {
    val animatedBorderColor by animateColorAsState(
        targetValue = if (value.isNotEmpty()) Color(0xFF007AFF) else Color(0xFFC7C7CC),
        label = "borderColorAnimation"
    )
    
    Column(modifier = modifier) {
        Text(
            text = label,
            style = MaterialTheme.typography.bodyMedium,
            color = Color.Gray,
            modifier = Modifier.padding(bottom = 4.dp)
        )
        
        Box(
            modifier = Modifier
                .fillMaxWidth()
                .background(
                    color = Color.White,
                    shape = RoundedCornerShape(10.dp)
                )
                .border(
                    width = 1.dp,
                    color = animatedBorderColor,
                    shape = RoundedCornerShape(10.dp)
                )
                .padding(horizontal = 16.dp, vertical = 12.dp)
        ) {
            BasicTextField(
                value = value,
                onValueChange = onValueChange,
                modifier = Modifier.fillMaxWidth(),
                textStyle = MaterialTheme.typography.bodyMedium.copy(
                    color = Color.Black
                ),
                singleLine = true,
                decorationBox = { innerTextField ->
                    Box {
                        if (value.isEmpty()) {
                            Text(
                                text = placeholder,
                                style = MaterialTheme.typography.bodyMedium.copy(
                                    color = Color(0xFFC7C7CC))
                            )
                        }
                        innerTextField()
                    }
                }
            )
        }
    }
}

关键 iOS 风格特点实现

  1. 圆角设计

    kotlin 复制代码
    shape = RoundedCornerShape(10.dp)
  2. 边框颜色

    kotlin 复制代码
    borderColor = if (focused) Color(0xFF007AFF) else Color(0xFFC7C7CC)
  3. 占位符样式

    kotlin 复制代码
    color = Color(0xFFC7C7CC)
  4. 清除按钮

    kotlin 复制代码
    Icon(Icons.Default.Close, contentDescription = "清除")
  5. 分段列表样式

    kotlin 复制代码
    Divider(color = Color(0xFFC6C6C8), thickness = 0.5.dp)

这些组件可以根据你的具体需求进一步定制,调整颜色、尺寸和动画效果,以达到更接近 iOS 设计风格的效果。

相关推荐
文人sec13 小时前
MySQL主库出问题了,从库怎么办?备库为什么会延迟好几个小时?
android·数据库·mysql
hai_android13 小时前
不用 AIDL,手把手教你手写 Binder 代理类
android·kotlin
mmsx14 小时前
osmdroid 地图实战 03|地图的"分层世界":离线方案、图层模型与 Overlay 体系
android·前端
张文是假的啊15 小时前
IOC依赖注入问题:@Primary 和 @Qualifier的使用
android
换元不配限16 小时前
ConstraintLayout核心用法详解(三):引导线、屏障、组和占位
android·placeholder·barrier·约束布局·guideline
心平气和量大福大17 小时前
android studio(AS)工具-调试-统计总行数
android·ide·android studio
你的坚定18 小时前
SurfaceFlinger合成一帧的完整流程
android
爱笑鱼20 小时前
Android 系统启动机制(七):进入 SystemServer.main() 以后,system_server 还是一个空进程吗?
android·linux
好安静20 小时前
SurfaceFlinger 合成一帧的完整流程
android
alexhilton20 小时前
架构测试为何需要双视图
android·kotlin·android jetpack