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解决方案。

相关推荐
Ya-Jun9 小时前
性能优化实践:启动优化方案
android·flutter·ios·性能优化
百锦再10 小时前
Android Studio中OpenCV应用详解:图像处理、颜色对比与OCR识别
android·java·图像处理·opencv·kotlin·app·android studio
冬田里的一把火312 小时前
[Android]任务列表中有两个相机图标
android
麓殇⊙14 小时前
MySQL--索引入门
android·数据库·mysql
学习中的农民工15 小时前
Android ndk 编译opencv后部分接口std::__ndk1与项目std::__1不匹配
android·c++·opencv
贫道绝缘子15 小时前
【Android】四大组件之BroadcastReceiver
android
lucky_tom1 天前
【android Framework 探究】pixel 5 内核编译
android
NO Exception?1 天前
完美解决 mobile-ffmpeg Not overwriting - exiting
android·ffmpeg·pcm
0wioiw01 天前
安卓基础(点击项目)
android·windows