Android Compose 物联网(IoT)UI 组件库封装指南

Android Compose 物联网封装组件

在物联网(IoT)应用开发中,使用Jetpack Compose可以创建现代化、响应式的用户界面。以下是一些针对物联网场景的Compose封装组件思路和实现方法:

常用物联网组件封装

1. 设备状态指示器

kotlin 复制代码
@Composable
fun DeviceStatusIndicator(
    isOnline: Boolean,
    batteryLevel: Int? = null,
    signalStrength: Int? = null,
    modifier: Modifier = Modifier
) {
    Row(
        modifier = modifier,
        verticalAlignment = Alignment.CenterVertically,
        horizontalArrangement = Arrangement.spacedBy(4.dp)
    ) {
        // 在线状态
        Icon(
            imageVector = if (isOnline) Icons.Filled.CheckCircle else Icons.Filled.Error,
            contentDescription = null,
            tint = if (isOnline) Color.Green else Color.Red,
            modifier = Modifier.size(16.dp)
        
        // 电池状态
        batteryLevel?.let { level ->
            BatteryIndicator(level = level)
        }
        
        // 信号强度
        signalStrength?.let { strength ->
            SignalStrengthIndicator(strength = strength)
        }
    }
}

@Composable
private fun BatteryIndicator(level: Int) {
    Box(
        modifier = Modifier
            .size(20.dp, 12.dp)
            .border(1.dp, Color.White, RoundedCornerShape(2.dp))
            .padding(1.dp)
    ) {
        Box(
            modifier = Modifier
                .fillMaxWidth(level / 100f)
                .fillMaxHeight()
                .background(
                    color = when {
                        level < 20 -> Color.Red
                        level < 50 -> Color.Yellow
                        else -> Color.Green
                    },
                    shape = RoundedCornerShape(1.dp)
                )
        )
    }
}

@Composable
private fun SignalStrengthIndicator(strength: Int) {
    val bars = when {
        strength > 75 -> 4
        strength > 50 -> 3
        strength > 25 -> 2
        else -> 1
    }
    
    Row(
        verticalAlignment = Alignment.Bottom,
        horizontalArrangement = Arrangement.spacedBy(2.dp)
    ) {
        repeat(4) { index ->
            val height = (index + 1) * 4.dp
            val color = if (index < bars) Color.Green else Color.Gray.copy(alpha = 0.3f)
            Box(
                modifier = Modifier
                    .width(3.dp)
                    .height(height)
                    .background(color, RoundedCornerShape(2.dp))
            )
        }
    }
}

2. 传感器数据图表

kotlin 复制代码
@Composable
fun SensorDataChart(
    dataPoints: List<Float>,
    modifier: Modifier = Modifier,
    lineColor: Color = Color.Blue,
    fillColor: Color = lineColor.copy(alpha = 0.2f)
) {
    Canvas(modifier = modifier) {
        if (dataPoints.size < 2) return@Canvas
        
        val maxValue = dataPoints.maxOrNull() ?: 0f
        val minValue = dataPoints.minOrNull() ?: 0f
        val range = maxValue - minValue
        val stepX = size.width / (dataPoints.size - 1)
        
        // 创建路径
        val path = Path().apply {
            moveTo(0f, size.height - (dataPoints[0] - minValue) / range * size.height)
            dataPoints.forEachIndexed { index, value ->
                if (index > 0) {
                    val x = index * stepX
                    val y = size.height - (value - minValue) / range * size.height
                    lineTo(x, y)
                }
            }
        }
        
        // 填充路径
        val fillPath = path.copy()
        fillPath.lineTo(size.width, size.height)
        fillPath.lineTo(0f, size.height)
        fillPath.close()
        
        // 绘制
        drawPath(fillPath, fillColor)
        drawPath(path, lineColor, style = Stroke(width = 2.dp.toPx()))
    }
}

3. 设备控制开关

kotlin 复制代码
@Composable
fun DeviceToggleSwitch(
    isOn: Boolean,
    onToggle: (Boolean) -> Unit,
    modifier: Modifier = Modifier,
    enabled: Boolean = true,
    onColor: Color = Color(0xFF4CAF50),
    offColor: Color = Color(0xFF9E9E9E),
    thumbColor: Color = Color.White
) {
    val animationProgress = animateFloatAsState(
        targetValue = if (isOn) 1f else 0f,
        animationSpec = tween(durationMillis = 200)
    )
    
    Box(
        modifier = modifier
            .width(48.dp)
            .height(24.dp)
            .clip(RoundedCornerShape(12.dp))
            .background(
                color = if (enabled) {
                    lerp(offColor, onColor, animationProgress.value)
                } else {
                    offColor.copy(alpha = 0.5f)
                }
            )
            .clickable(enabled = enabled) { onToggle(!isOn) },
        contentAlignment = Alignment.CenterStart
    ) {
        Box(
            modifier = Modifier
                .offset(x = animationProgress.value * 24.dp)
                .size(20.dp)
                .clip(CircleShape)
                .background(thumbColor)
                .padding(2.dp)
        )
    }
}

4. 环境数据显示卡

kotlin 复制代码
@Composable
fun EnvironmentDataCard(
    temperature: Float?,
    humidity: Float?,
    airQuality: Int?,
    modifier: Modifier = Modifier
) {
    Card(
        modifier = modifier,
        elevation = CardDefaults.cardElevation(defaultElevation = 4.dp)
    ) {
        Column(
            modifier = Modifier.padding(16.dp),
            verticalArrangement = Arrangement.spacedBy(8.dp)
        ) {
            Text("环境数据", style = MaterialTheme.typography.titleMedium)
            
            temperature?.let {
                EnvironmentDataItem(
                    icon = Icons.Filled.Thermostat,
                    label = "温度",
                    value = "${it}°C",
                    color = when {
                        it > 30 -> Color.Red
                        it < 10 -> Color.Blue
                        else -> Color.Green
                    }
                )
            }
            
            humidity?.let {
                EnvironmentDataItem(
                    icon = Icons.Filled.WaterDrop,
                    label = "湿度",
                    value = "${it}%",
                    color = when {
                        it > 80 -> Color.Blue
                        it < 30 -> Color.Red
                        else -> Color.Green
                    }
                )
            }
            
            airQuality?.let {
                EnvironmentDataItem(
                    icon = Icons.Filled.Air,
                    label = "空气质量",
                    value = when {
                        it < 50 -> "优"
                        it < 100 -> "良"
                        it < 150 -> "轻度污染"
                        it < 200 -> "中度污染"
                        else -> "重度污染"
                    },
                    color = when {
                        it < 50 -> Color.Green
                        it < 100 -> Color(0xFFCDDC39)
                        it < 150 -> Color(0xFFFF9800)
                        it < 200 -> Color(0xFFF44336)
                        else -> Color(0xFF9C27B0)
                    }
                )
            }
        }
    }
}

@Composable
private fun EnvironmentDataItem(
    icon: ImageVector,
    label: String,
    value: String,
    color: Color,
    modifier: Modifier = Modifier
) {
    Row(
        modifier = modifier,
        verticalAlignment = Alignment.CenterVertically,
        horizontalArrangement = Arrangement.spacedBy(8.dp)
    ) {
        Icon(
            imageVector = icon,
            contentDescription = null,
            tint = color,
            modifier = Modifier.size(20.dp)
        )
        Text(text = label, style = MaterialTheme.typography.bodyMedium)
        Spacer(modifier = Modifier.weight(1f))
        Text(
            text = value,
            style = MaterialTheme.typography.bodyLarge.copy(fontWeight = FontWeight.Bold),
            color = color
        )
    }
}

物联网特定功能组件

1. 设备发现列表

kotlin 复制代码
@Composable
fun DeviceDiscoveryList(
    devices: List<DiscoveredDevice>,
    onDeviceSelected: (DiscoveredDevice) -> Unit,
    modifier: Modifier = Modifier,
    isDiscovering: Boolean = false
) {
    Column(modifier = modifier) {
        if (isDiscovering) {
            LinearProgressIndicator(
                modifier = Modifier.fillMaxWidth()
            )
            Spacer(modifier = Modifier.height(8.dp))
        }
        
        LazyColumn {
            items(devices) { device ->
                DeviceDiscoveryItem(
                    device = device,
                    onClick = { onDeviceSelected(device) },
                    modifier = Modifier.fillMaxWidth()
                )
            }
        }
    }
}

@Composable
fun DeviceDiscoveryItem(
    device: DiscoveredDevice,
    onClick: () -> Unit,
    modifier: Modifier = Modifier
) {
    Card(
        modifier = modifier.padding(8.dp),
        onClick = onClick
    ) {
        Row(
            modifier = Modifier.padding(16.dp),
            verticalAlignment = Alignment.CenterVertically,
            horizontalArrangement = Arrangement.spacedBy(16.dp)
        ) {
            Icon(
                imageVector = when (device.type) {
                    DeviceType.THERMOSTAT -> Icons.Filled.Thermostat
                    DeviceType.LIGHT -> Icons.Filled.Lightbulb
                    DeviceType.SENSOR -> Icons.Filled.Sensors
                    else -> Icons.Filled.DevicesOther
                },
                contentDescription = null,
                modifier = Modifier.size(32.dp)
            
            Column(modifier = Modifier.weight(1f)) {
                Text(
                    text = device.name,
                    style = MaterialTheme.typography.titleMedium
                )
                Text(
                    text = device.address,
                    style = MaterialTheme.typography.bodySmall,
                    color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.6f)
                )
            }
            
            Icon(
                imageVector = Icons.Filled.ChevronRight,
                contentDescription = "连接",
                tint = MaterialTheme.colorScheme.primary
            )
        }
    }
}

2. 连接状态指示器

kotlin 复制代码
@Composable
fun ConnectionStatusIndicator(
    connectionState: ConnectionState,
    onRetry: () -> Unit,
    modifier: Modifier = Modifier
) {
    val (text, icon, color) = when (connectionState) {
        ConnectionState.CONNECTED -> Triple("已连接", Icons.Filled.CheckCircle, Color.Green)
        ConnectionState.CONNECTING -> Triple("连接中...", Icons.Filled.Refresh, Color(0xFFFFA000))
        ConnectionState.DISCONNECTED -> Triple("已断开", Icons.Filled.Error, Color.Red)
        ConnectionState.ERROR -> Triple("连接错误", Icons.Filled.Warning, Color.Red)
    }
    
    Row(
        modifier = modifier,
        verticalAlignment = Alignment.CenterVertically,
        horizontalArrangement = Arrangement.spacedBy(8.dp)
    ) {
        Icon(
            imageVector = icon,
            contentDescription = null,
            tint = color,
            modifier = Modifier.size(20.dp)
        )
        Text(text = text, color = color)
        
        if (connectionState == ConnectionState.ERROR || connectionState == ConnectionState.DISCONNECTED) {
            TextButton(onClick = onRetry) {
                Text("重试")
            }
        }
    }
}

最佳实践建议

  1. 状态管理:对于物联网应用,建议使用ViewModel管理设备状态和数据流
  2. 实时更新:使用Flow或LiveData将设备数据传递到Compose界面
  3. 错误处理:为所有设备操作添加适当的错误处理和重试机制
  4. 性能优化:对于高频传感器数据,考虑降低UI更新频率或使用性能优化的图表库
  5. 主题一致性:遵循Material Design指南,确保界面一致性

示例ViewModel

kotlin 复制代码
class IoTDeviceViewModel : ViewModel() {
    private val _connectionState = mutableStateOf(ConnectionState.DISCONNECTED)
    val connectionState: State<ConnectionState> = _connectionState
    
    private val _temperature = mutableStateOf<Float?>(null)
    val temperature: State<Float?> = _temperature
    
    private val _humidity = mutableStateOf<Float?>(null)
    val humidity: State<Float?> = _humidity
    
    private val deviceManager = IoTDeviceManager()
    
    init {
        viewModelScope.launch {
            deviceManager.connectionState.collect { state ->
                _connectionState.value = state
            }
        }
        
        viewModelScope.launch {
            deviceManager.temperatureFlow.collect { temp ->
                _temperature.value = temp
            }
        }
        
        viewModelScope.launch {
            deviceManager.humidityFlow.collect { hum ->
                _humidity.value = hum
            }
        }
    }
    
    fun connectDevice(deviceId: String) {
        viewModelScope.launch {
            try {
                deviceManager.connect(deviceId)
            } catch (e: Exception) {
                _connectionState.value = ConnectionState.ERROR
            }
        }
    }
    
    fun disconnectDevice() {
        deviceManager.disconnect()
    }
}

enum class ConnectionState {
    CONNECTED, CONNECTING, DISCONNECTED, ERROR
}

这些组件可以根据具体的物联网应用需求进行扩展和定制,为物联网应用开发提供高效、美观的UI解决方案。

相关推荐
三少爷的鞋3 分钟前
架构避坑:为什么 UseCase 不该启动协程,也不该切线程?
android
Mr -老鬼15 分钟前
Android studio 最新Gradle 8.13版本“坑点”解析与避坑指南
android·ide·android studio
xiaolizi5674898 小时前
安卓远程安卓(通过frp与adb远程)完全免费
android·远程工作
阿杰100019 小时前
ADB(Android Debug Bridge)是 Android SDK 核心调试工具,通过电脑与 Android 设备(手机、平板、嵌入式设备等)建立通信,对设备进行控制、文件传输、命令等操作。
android·adb
梨落秋霜9 小时前
Python入门篇【文件处理】
android·java·python
遥不可及zzz11 小时前
Android 接入UMP
android
Coder_Boy_13 小时前
基于SpringAI的在线考试系统设计总案-知识点管理模块详细设计
android·java·javascript
冬奇Lab14 小时前
【Kotlin系列03】控制流与函数:从if表达式到Lambda的进化之路
android·kotlin·编程语言
冬奇Lab14 小时前
稳定性性能系列之十二——Android渲染性能深度优化:SurfaceFlinger与GPU
android·性能优化·debug
冬奇Lab15 小时前
稳定性性能系列之十一——Android内存优化与OOM问题深度解决
android·性能优化