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("重试")
}
}
}
}
最佳实践建议
- 状态管理:对于物联网应用,建议使用ViewModel管理设备状态和数据流
- 实时更新:使用Flow或LiveData将设备数据传递到Compose界面
- 错误处理:为所有设备操作添加适当的错误处理和重试机制
- 性能优化:对于高频传感器数据,考虑降低UI更新频率或使用性能优化的图表库
- 主题一致性:遵循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解决方案。