Android Jetpack Compose: una interfaz de chat sencilla

prefacio

En la actualidad, la interfaz de usuario declarativa se ha convertido en la tendencia del desarrollo front-end. Además del desarrollo cruzado inicial de React, Flutter, etc. y el soporte web, las plataformas Android e IOS posteriores también han lanzado el desarrollo declarativo. Android se desarrolla a través de Las potentes funciones de lenguaje de Jetpack Compose y Kotlin eliminan por completo el uso imperativo de archivos XML para el diseño de la interfaz de usuario.

efecto de vídeo

Android Jetpack: una interfaz de chat sencilla

introducir

Antes del análisis de código, presente varios diseños comunes

Fila

horizontalSimilar a la disposición de LinearLayout en Android , es consistente con Flutter's Row.
El modificador básicamente realiza la mayor parte del trabajo de configuración de un componente. Implementa una serie de funciones de extensión internamente y realiza thenllamadas en cadena a través de funciones. verticalAlignmentEl atributo es la alineación vertical y horizontalArrangementla alineación horizontal .

Row(
        modifier = Modifier.padding(all = 10.dp),
        verticalAlignment = Alignment.CenterVertically,
        horizontalArrangement = Arrangement.Start
        )  {
         //some sub views
        }

Columna

Excepto por la disposición de Columna y Fila, el resto es más o menos igual, similar a la verticaldisposición de LinearLayout

Column(
            modifier = Modifier.weight(1f),
            horizontalAlignment = Alignment.End
        ){
         //some sub views
        }

Texto

Cuadro de texto, similar a Android TextView, textel atributo es el contenido del texto, colorel atributo es el color del texto, styleel atributo es el estilo del texto, puede configurar el tamaño del texto, si está en negrita, el estilo, etc., el sistema tiene muchos estilos incorporados, y el textAlignatributo es la alineación del texto

Text(
                text = msg.author,
                color = MaterialTheme.colorScheme.secondary,
                style = MaterialTheme.typography.bodySmall,
                textAlign = TextAlign.Right
            )

Imagen

Equivalente a Android ImageView, painterpuede configurar directamente la dirección de la imagen (dibujable) a través de PainterResource, y modifierpodemos modificar directamente los atributos de la imagen, como esquinas redondeadas, bordes y tamaño a través de atributos, por lo que no es necesario crear un archivo xml para configurar

Image(
            painter = painterResource(id = msg.img),
            contentDescription = "",
            modifier = Modifier
                .size(40.dp)
                .clickable { CircleShape }
                .border(1.dp, MaterialTheme.colorScheme.secondary, CircleShape)

        )

interfaz de chat

Al LazyColumnimplementar una lista vertical, los datos son datos fijos y los subíndices se ubican en los extremos izquierdo y derecho del diseño, y luego el texto predeterminado muestra una línea. Después de hacer clic en la línea de texto, el contenido del texto se expandirá. y su color de fondo será cambiado. Esta demostración adaptada de la versión oficial

Efecto

diseño izquierdo

Solo al agregar @Composableanotaciones se puede usar la interfaz de usuario declarativa. La interfaz de usuario declarativa adopta una estructura de árbol. En este ejemplo, Fila es el nodo raíz del árbol y tiene dos nodos secundarios, a saber, y (se omite el marcador de posición de espacio en el medio Image) Column, y luego ColumnIt también tiene dos nodos secundarios, a saber, Surfacey Text, que Surfacetiene otro Textnodo secundario.

Supervise si se hace clic en una fila y luego realice la modificación de fondo principalmente a través de lo siguiente, que es equivalente al modo observador, controle isExpandedel campo y luego cambie, es similar al observador inmediatamente. La explicación oficial es la siguiente:

重组:可组合函数可以使用 remember 将本地状态存储在内存中,并跟踪传递给 mutableStateOf 的值的变化。
该值更新时,系统会自动重新绘制使用此状态的可组合项(及其子项)
通过使用 Compose 的状态 API(如 remember 和 mutableStateOf),系统会在状态发生任何变化时自动更新界面。
//监听isExpanded字段
var isExpanded by remember { mutableStateOf(false) }

//收缩和扩展对应俩种颜色,由isExpanded字段决定
        val surfaceColor by animateColorAsState(
            targetValue = if (isExpanded)
                Color.Cyan
            else
                MaterialTheme.colorScheme.surface
        )

Finalmente, modifier = Modifier .clickable { isExpanded = !isExpanded }agréguelo Cada clic cambiará su valor y luego obtendrá el nodo del valor para volver a dibujar y actualizar

@Composable
fun MessageLeft(msg : Message){
    Row(
        modifier = Modifier.padding(all = 10.dp),
        verticalAlignment = Alignment.CenterVertically,
        horizontalArrangement = Arrangement.Start) {
        //图像
        Image(
            painter = painterResource(id = msg.img),
            contentDescription = "",
            modifier = Modifier
                .size(40.dp)//图像大小
                .clip(CircleShape)
                .border(1.dp, MaterialTheme.colorScheme.secondary, CircleShape)

        )

        //左右间隔
        Spacer(modifier = Modifier.width(10.dp))

        //重组:可组合函数可以使用 remember 将本地状态存储在内存中,并跟踪传递给 mutableStateOf 的值的变化。
        // 该值更新时,系统会自动重新绘制使用此状态的可组合项(及其子项)
        //通过使用 Compose 的状态 API(如 remember 和 mutableStateOf),系统会在状态发生任何变化时自动更新界面。
        var isExpanded by remember { mutableStateOf(false) }

        val surfaceColor by animateColorAsState(
            targetValue = if (isExpanded)
                Color.Cyan
            else
                MaterialTheme.colorScheme.surface
        )

        Column() {
            Text(
                text = msg.author,
                color = MaterialTheme.colorScheme.secondary,
                style = MaterialTheme.typography.bodySmall
            )

            //上下间隔
            Spacer(modifier = Modifier.height(10.dp))

            Surface(
                shape = RectangleShape,
                shadowElevation = 1.dp,
                tonalElevation = 1.dp,
                color = surfaceColor,
                modifier = Modifier
                    .animateContentSize()
                    .padding(1.dp)
            ) {
                Text(
                    text = msg.content,
                    modifier = Modifier
                        .clickable { isExpanded = !isExpanded }
                        .padding(all = 4.dp),
                    maxLines = if (isExpanded) Int.MAX_VALUE else 1,
                    style = MaterialTheme.typography.bodyMedium,
                    overflow = TextOverflow.Ellipsis
                )
            }

        }
    }
}

diseño correcto

El lado derecho es similar al lado izquierdo, la diferencia es que se cambia horizontalArrangementla disposición para que quede del lado derecho, y luego se agrega un atributo de peso al texto modifier = Modifier.weight(1f),para evitar que la línea tenga demasiado contenido y exprimir el imagen derecha fuera de la pantalla

@Composable
fun MessageRight(msg: Message){
    Row(
        modifier = Modifier
            .padding(10.dp)
            .fillMaxWidth(),
        verticalAlignment = Alignment.CenterVertically,
        horizontalArrangement = Arrangement.End) {
        //给左边文字一个权重,避免文字过多,让右边图像无法显示
        Column(
            modifier = Modifier.weight(1f),
            horizontalAlignment = Alignment.End
        ) {
            Text(
                text = msg.author,
                color = MaterialTheme.colorScheme.secondary,
                style = MaterialTheme.typography.bodySmall,
                textAlign = TextAlign.Right
            )

            Spacer(modifier = Modifier.height(10.dp))

            var isExpanded by remember { mutableStateOf(false) }
            val surfaceColor by animateColorAsState(
                targetValue = if (isExpanded)
                    Color.Green
                else
                    MaterialTheme.colorScheme.surface
            )

            Surface(
                shape = RectangleShape,
                shadowElevation = 1.dp,
                tonalElevation = 1.dp,
                color = surfaceColor,
                modifier = Modifier
                    .animateContentSize()
                    .padding(1.dp)
            ) {
                Text(
                    text = msg.content,
                    modifier = Modifier
                        .clickable { isExpanded = !isExpanded }
                        .padding(all = 4.dp),
                    maxLines = if (isExpanded) Int.MAX_VALUE else 1,
                    style = MaterialTheme.typography.bodyMedium,
                    overflow = TextOverflow.Ellipsis

                )
            }
        }
        Spacer(modifier = Modifier.width(10.dp))
        Image(
            painter = painterResource(id = msg.img),
            contentDescription = "",
            modifier = Modifier
                .size(40.dp)
                .clickable { CircleShape }
                .border(1.dp, MaterialTheme.colorScheme.secondary, CircleShape)

        )
    }
}

insertar datos

¿Es equivalente a Android XML RecyclerView, es muy simple, no es necesario escribir Adaptery subelementar archivos XMl y muchas interfaces o algo así?

@Composable
fun ShowMessage(msgList: List<Message>){
    //竖向列表
    LazyColumn{
        itemsIndexed(items = msgList){
            index, item ->
            if (index %2 == 0)
                MessageLeft(msg = item)
            else
                MessageRight(msg = item)
        }
    }
}

Resumir

Es posible que la interfaz de usuario declarativa de Jetpack Compose no se use al principio, pero después de acostumbrarse, despegará directamente, mejorando en gran medida la eficiencia del desarrollo y reduciendo el tiempo de desarrollo, y la mayoría de los front-end usan la interfaz de usuario declarativa. Flutter, los dos son básicamente similares en términos de interfaz de usuario, excepto que Flutter se divide en tres partes , y , a través Widgetdel anidamiento , y juzga si el nodo es modificado por y , para juzgar si necesita ser redibujado. Finalmente, les sugiero a los desarrolladores de Android que lo usen. Android Jetpack Compose ha estado disponible durante casi un año y es gradualmente estable.WidgetElementRenderObjectruntimetypekey

Supongo que te gusta

Origin blog.csdn.net/News53231323/article/details/128097830
Recomendado
Clasificación