Un ejemplo para ilustrar cómo Jetpack Compose puede reducir el código empresarial en un 80 % en comparación con la vista tradicional

Si hay un requisito de la siguiente manera:

inserte la descripción de la imagen aquí

Después de nuestra observación, podemos obtener los siguientes puntos de demanda:

  • Una lista que puede desplazarse infinitamente
  • Diferentes tipos de artículos
  • El artículo tiene forma de hexágono.
  • El artículo tiene partes superpuestas horizontal y verticalmente

1. Utilice el desarrollo de View tradicional

Si usamos el desarrollo de View tradicional, es natural pensar que podemos usarlo RecyclerViewpara lograrlo, pero hay dos puntos difíciles:

  1. Los artículos superpuestos causarán RecyclerViewproblemas con el mecanismo de reciclaje y los artículos no se pueden reciclar correctamente
  2. Para el elemento hexagonal, no hay un componente nativo correspondiente que se pueda usar directamente

En primer lugar, para el primer punto, necesitamos personalizar RecyclerViewel uso de LayoutManager:

inserte la descripción de la imagen aquí

Pero esto es realmente un poco complicado y difícil (para la mayoría de los desarrolladores comunes, ignórelo), porque necesitamos entender completamente LayoutManagercómo funciona la estrategia de reciclaje antes de que podamos comenzar a modificar el código; de lo contrario, es posible crearlo nosotros mismos. un error en la rueda del coche, entonces la pérdida supera la ganancia.

En segundo lugar, para el elemento hexagonal, debemos 自定义View+Canvas绘制implementar:

inserte la descripción de la imagen aquí

Pero hacerlo tendrá ciertas restricciones en la escalabilidad, porque usamos la herencia de FrameLayout para lograr, si hay otras necesidades en el futuro, es posible que necesitemos modificar constantemente esta vista personalizada.

Después de resolver los dos puntos complicados anteriores, finalmente podemos escribir código para resolver este requisito, pero aún necesitamos crear muchos archivos de preparación relacionados, como adaptador, archivos de diseño xml...

En resumen, si usa el desarrollo de View tradicional, para usarlo RecyclerViewpara lograr este requisito, necesitamos escribir muchas cosas desordenadas:

inserte la descripción de la imagen aquí

2. Desarrolla con Jetpack Compose

Si usamos Jetpack Compose para desarrollar este requisito, será muy simple, el trabajo más grande que debemos hacer puede ser crear un hexágono Shapepara Modifier.clip()el método a usar:

inserte la descripción de la imagen aquí

Necesitamos personalizar un hexágono HexagonShape(la implementación se dará más adelante en este artículo), y luego podemos escribir el código comercial directamente. Podemos usar para LazyColumnimplementar la lista de desplazamiento. Para la función de superposición e intercalado de Item, recuerde que LazyColumnhay un verticalArrangementatributo? Podemos hacer esto Arrangement.spacedBy()estableciendo un dpvalor negativo para esta propiedad:

inserte la descripción de la imagen aquí

LazyListPara elementos de varios tipos, de hecho, la sintaxis DSL de los componentes de la serie en Jetpack Compose itempuede admitir naturalmente la configuración de elementos de varios tipos, por ejemplo:

inserte la descripción de la imagen aquí

Por supuesto, también podemos optar por itemsmostrar la especificación directamente en esta función DSL contentTypepara distinguir la visualización de diferentes componentes Composable:

LazyColumn(...) {
    
    
    items(list, contentType = {
    
     it.type }) {
    
     item ->
        if (item.type == 1) {
    
    
            // 一种类型的Composable组件
            ......
        } else {
    
    
            // 另一种类型的Composable组件 
             ......
        }
    }
}

Para obtener más información sobre LazyListel uso de componentes de serie, consulte mi otro artículo: Listas en Jetpack Compose .

En resumen, si usa Jetpack Compose para desarrollar este requisito, en comparación con el desarrollo de View, el trabajo realizado es muy poco:

inserte la descripción de la imagen aquí

Usar Jetpack Compose para desarrollar también tiene las siguientes ventajas:

  • En comparación con el desarrollo de View, se reduce una gran cantidad de código (se puede reducir al menos el 50% del código comercial)
  • Complejidad de código reducida en comparación con el desarrollo de View
  • Legibilidad y mantenibilidad muy mejoradas

3. Código fuente de implementación de Jetpack Compose

El siguiente es el código de ejemplo completo para lograr los requisitos anteriores:

@Composable
fun HexagonItemList() {
    
    
    LazyColumn(
        verticalArrangement = Arrangement.spacedBy((-100).dp),
        contentPadding = PaddingValues(20.dp)
    ) {
    
    
        items(4) {
    
     Hexagon(it) }
        item {
    
     RecommendedText() }
        items(50) {
    
     Hexagon(it) }
    }
}

@Composable
fun Hexagon(index: Int) {
    
    
    val arrangement = if (index % 2 == 0) Arrangement.Start else Arrangement.End
    Row(
        modifier = Modifier.fillMaxWidth(),
        horizontalArrangement = arrangement,
    ) {
    
    
        Box(
            modifier = Modifier
                .fillMaxWidth(0.55f)
                .height(200.dp)
                .clip(HexagonShape)
                .background(OrangeColor),
            contentAlignment = Alignment.Center
        ) {
    
    
            Text(text = "Item $index", fontSize = 15.sp)
        }
    }
}
@Composable
fun RecommendedText() {
    
    
    Column(
        modifier = Modifier.height(300.dp).fillMaxWidth(),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center
    ) {
    
    
        Text(text = "Recommended items", fontSize = 20.sp, fontWeight = FontWeight.Bold)
        Text(text = "Based on your interests")
    }
}

val OrangeColor = Color(255,197,2)
val HexagonShape = Polygon(6, 0f)

/**
 * 根据边数sides创建指定多边形的Shape, 可以用于Modifier.clip()方法中
 */
class Polygon(private val sides: Int, private val rotation: Float = 0f) : Shape {
    
    
    override fun createOutline(
        size: Size,
        layoutDirection: LayoutDirection,
        density: Density
    ): Outline {
    
    
        return Outline.Generic(
            Path().apply {
    
    
                val radius = if (size.width > size.height) size.width / 2f else size.height / 2f
                val angle = 2.0 * Math.PI / sides
                val cx = size.width / 2f
                val cy = size.height / 2f
                val r = rotation * (Math.PI / 180)
                moveTo(
                    cx + (radius * cos(0.0 + r).toFloat()),
                    cy + (radius * sin(0.0 + r).toFloat())
                )
                for (i in 1 until sides) {
    
    
                    lineTo(
                        cx + (radius * cos(angle * i + r).toFloat()),
                        cy + (radius * sin(angle * i + r).toFloat())
                    )
                }
                close()
            }
        )
    }
}

El efecto de ejecución real es el siguiente:

inserte la descripción de la imagen aquí

Los estudiantes cuidadosos pueden haber descubierto que los hexágonos en el diagrama esquemático de los requisitos mencionados al principio tienen esquinas redondeadas. Desafortunadamente, la herencia directa anterior para Shapecrear métodos personalizados no puede especificar las esquinas redondeadas de los polígonos. Sin embargo, hay más de una forma de crear polígonos en Compose. Por ejemplo, podemos elegir usarlo Modifier.drawBehind{ }para Canvasdibujar un hexágono. En este momento, podemos especificar las propiedades relacionadas con las esquinas redondeadas:

/**
 * 绘制带圆角的六边形,关键点是设置绘制的style的pathEffect,通过PathEffect.cornerPathEffect指定圆角半径
 */
fun DrawScope.drawHexagon(color: Color, cornerRadius: Float = 0f, fill: Boolean = true) {
    
    
    val canvasWidth = size.width
    val canvasHeight = size.height
    val cx = canvasWidth / 2
    val cy = canvasHeight / 2
    val radius = (canvasHeight - 20.dp.toPx()) / 2
    val path = createPolygonPath(cx, cy, 6, radius)
    if (fill) {
    
    
        // 这种方式绘制可以填充整个多边形的内容区域
        drawIntoCanvas {
    
     canvas ->
            canvas.drawOutline(
                outline = Outline.Generic(path),
                paint = Paint().apply {
    
    
                    this.color = color
                    pathEffect = PathEffect.cornerPathEffect(cornerRadius)
                }
            )
        }
    } else {
    
    
        // 但是也可以通过两遍绘制来实现填充的效果
//        drawPath(
//            color = color,
//            path = path,
//            style = Fill
//        )
        // 这种方式只会绘制边框
        drawPath(
            color = color,
            path = path,
            style = Stroke(
                width = 4.dp.toPx(),
                pathEffect = PathEffect.cornerPathEffect(cornerRadius)
            )
        )
    }
}
/**
 * 根据边数sides创建多边形
 */
fun createPolygonPath(cx: Float, cy: Float, sides: Int, radius: Float): Path {
    
    
    val angle = 2.0 * Math.PI / sides
    return Path().apply {
    
    
        moveTo(
            cx + (radius * cos(0.0)).toFloat(),
            cy + (radius * sin(0.0)).toFloat()
        )
        for (i in 1 until sides) {
    
    
            lineTo(
                cx + (radius * cos(angle * i)).toFloat(),
                cy + (radius * sin(angle * i)).toFloat()
            )
        }
        close()
    }
}

Esto se drawHexagondefinirá como DrawScopeuna función de extensión de , de modo que Canvasse pueda llamar en cualquier lugar donde se pueda usar la API.

Luego puede Hexagonaplicar esta función en el componente para dibujar el hexágono:

@Composable
fun Hexagon(index: Int) {
    
    
    val arrangement = if (index % 2 == 0) Arrangement.Start else Arrangement.End
    Row(
        modifier = Modifier.fillMaxWidth(),
        horizontalArrangement = arrangement,
    ) {
    
    
        Box(
            modifier = Modifier
                .fillMaxWidth(0.55f)
                .height(200.dp)
                .drawBehind {
    
     drawHexagon(OrangeColor, 30f) },
            contentAlignment = Alignment.Center
        ) {
    
    
            Text(text = "Item $index", fontSize = 15.sp)
        }
    }
}

Por supuesto, también puede drawBehind { drawHexagon(OrangeColor, 30f) }definir esta oración como una Modifierfunción de extensión aquí.

El método de llamada es el mismo que antes, y la indirección se puede ajustar ligeramente:

@Composable
fun HexagonItemList() {
    
    
    LazyColumn(
        verticalArrangement = Arrangement.spacedBy((-115).dp),
        contentPadding = PaddingValues(30.dp)
    ) {
    
    
        items(4) {
    
     Hexagon(it) }
        item {
    
     RecommendedText() }
        items(50) {
    
     Hexagon(it) }
    }
}

Efecto de funcionamiento real:

inserte la descripción de la imagen aquí

Puedes ver que el hexágono ahora tiene esquinas redondeadas, tal como en la imagen al principio. Y la forma definida de esta manera se puede aplicar en casi cualquier componente Composable Modifier, lo que es mucho más cómodo que escribir una Vista personalizada en la Vista tradicional.

Para obtener más información sobre el dibujo de Canvas, consulte mi artículo anterior: Canvas en Jetpack Compose .

Resumir

En comparación con el desarrollo de View tradicional, Jetpack Compose es realmente delicioso Puede cumplir con los requisitos comerciales más complejos con menos código, más legible y mejor mantenible. Si eres un veterano en el desarrollo de Android, creo que tendrás una comprensión más profunda de la diferencia entre los dos expresados ​​en este artículo. Entonces, ¡es hora de cambiar la escopeta por un cañón! Envíe esto a los encargados de tomar decisiones sobre el desarrollo de su equipo.

Si está interesado en obtener más contenido sobre Jetpack Compose, consulte mi otro artículo sobre este aspecto: Resumen de aprendizaje de Jetpack Compose .


参考:Diseño divertido con diseños Lazy: Consejo de la comunidad - MAD Skills

Supongo que te gusta

Origin blog.csdn.net/lyabc123456/article/details/129934290
Recomendado
Clasificación