Jetpack Compose

Jetpack Compose:聲明式UI框架

(Composition over inheritance) 組合優於繼承

1. 什麼是Compose,有什麼優勢?

Jetpack Compose 是一個現代工具包,旨在簡化UI開發。它結合了反應式編程模型和Kotlin編程語言的簡潔性和易用性。它是完全聲明性的,Compose的口號就是消滅xml,在擼過代碼之後總結總體上UI的結構和Flutter一致,只有在語法上存在部分差異,因爲我是基於dev2的版本體驗的,所以在頁面的體驗上並不是很流暢,
而且Compose是沒有view複用的,可能也是較早期的版本可用的資源也不是很多
在使用上Compose可以讓你更專心的處理業務,因起特性聲明UI組件和業務都在class中,較現在的xml模式可以省去很多findViewbyId等一系列綁定的操作
在更新UI上Compose也有類似Flutter的Provide一樣的更新機制,當基礎數據更改時,框架會自動調用這些功能,從而更新視圖層次結構
Compose在UI上改動是非常大的不是採用了傳統UI的多層繼承結構,而是多個View組合成一個View
更新數據只要在使用的實體上面加註解@Model在更新實體的同時會通知UI進行修改

2. 使用

我是基於Android Studio 3.5.1 / build:gralde 3.5.1 / gradle 5.4.1 / compse 0.1.0-dev02 / kotlin 1.3.60-eap-76 版本進行開發的
基本核心庫 (其中androidx.ui爲Compose.UI庫)
androidx.compose:compose-runtime
androidx.ui:ui-framework
androidx.ui:ui-layout
androidx.ui:ui-material
androidx.ui:ui-tooling
androidx.appcompat:appcompat
androidx.activity:activity-ktx
androidx.core:core-ktx
com.pinterest:ktlint
Android studio 4.0以上要打開開關 (Compose對4.0以下版本部分功能不支持)
buildFeatures {
compose true
}

3. 基本UI和使用

yyyyy
yyyyy
VerticalScroller - 縱向滑動
HorizontalScroller - 橫向滑動
Column - 縱向佈局
Row - 橫向佈局
MaterialTheme - 主題
Surface - 背景色
FlexColumn - 權重佈局
TopAppBar - 標題欄
DrawImage - 圖片
Clip - 圓角
Container - 容器
Text - 文本
Divider - 線
HeightSpacer - 高度填充
WidthSpacer - 寬度填充
TabRow - 導航欄
Tab - 導航標題
Button - 按鈕
Checkbox - 選項框
Card - 卡片佈局
Ripple - 水波紋
repeat - 循環
VectorImageButton - Vector圖片按鈕

yyyyy

代碼

import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.Composable
import androidx.compose.Model
import androidx.compose.unaryPlus
import androidx.ui.core.*
import androidx.ui.foundation.DrawImage
import androidx.ui.foundation.HorizontalScroller
import androidx.ui.foundation.VerticalScroller
import androidx.ui.foundation.shape.corner.RoundedCornerShape
import androidx.ui.graphics.Color
import androidx.ui.layout.*
import androidx.ui.material.*
import androidx.ui.material.ripple.Ripple
import androidx.ui.material.surface.Card
import androidx.ui.material.surface.Surface
import androidx.ui.res.imageResource
import androidx.ui.text.TextStyle
import androidx.ui.text.style.TextOverflow
import androidx.ui.tooling.preview.Preview
import com.example.jetnews.R

/**
 * @fileName: YTestActivity
 * @date: 2019/11/21 18:12
 * @auther: YuanShuai
 * @tag: class//
 * @describe:
 **/
class YTestActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MyApp {
                layout()
            }
        }
    }


    @Composable  //ComposeUI
    fun layout(
        nums: List<String> = listOf("Hello Compose !", "Two Container !"),
        counterState: NumState = NumState()
    ) {
        //縱向滑動佈局
        VerticalScroller {
            //縱向佈局
            Column {
                //循環添加
                for (num in nums) {
                    Greeting(num, counterState)
                }
            }
        }
    }

    @Composable   //ComposeUI
    fun MyApp(children: @Composable() () -> Unit) {
        //Material主題
        MaterialTheme {
            //自定義主題
            //CustomTheme {
            //背景色
            Surface(color = Color(0xffffffff)) {
                //權重佈局
                FlexColumn {
                    inflexible {
                        //標題欄
                        TopAppBar(
                            title = { Text("AppBar") },
                            navigationIcon = {
                                //Vector圖片按鈕
                                VectorImageButton(R.drawable.ic_back) {
                                    Toast.makeText(this@YTestActivity, "back", Toast.LENGTH_SHORT)
                                        .show()
                                }
                            }
                        )
                    }
                    flexible(flex = 1f) {
                        children()
                    }
                }
            }
        }
    }


    @Preview("Test Preview") //瀏覽視圖
    @Composable   //ComposeUI
    private fun Greeting(
        text: String,
        counterState: NumState
    ) {
        val image = +imageResource(R.drawable.duia_bg)
        val image2 = +imageResource(R.drawable.duia)
        //縱向佈局
        Column(
            crossAxisSize = LayoutSize.Wrap,
            modifier = Spacing(10.dp)
        ) {
            //容器
            Container(expanded = true, height = 220.dp) {
                //圓角
                Clip(shape = RoundedCornerShape(8.dp)) {
                    //圖片
                    DrawImage(image)
                    Container(expanded = true, height = 100.dp, width = 100.dp) {
                        DrawImage(image2)
                    }
                }
            }
            //高度填充
            HeightSpacer(10.dp)
            //文本
            Text(text, style = (+themeTextStyle { h6 }).withOpacity(0.8f))
            HeightSpacer(10.dp)
            //分割線
            Divider(color = Color(0x33333333))
            HeightSpacer(10.dp)
            Container(expanded = true) {
                //文本
                Text(
                    "Kotlin Compose !",
                    style = (+themeTextStyle { body2 }).withOpacity(0.47f)
                )
            }
            HeightSpacer(10.dp)
            Divider(color = Color(0x23330033))
            HeightSpacer(10.dp)
            Container(expanded = true, alignment = Alignment.CenterRight) {
                Text(
                    "Alignment !",
                    style = TextStyle(color = Color(0xFF936112), fontSize = 18.sp)
                )
            }
            HeightSpacer(10.dp)
            Divider(color = Color(0x23330033))
            HeightSpacer(10.dp)
            Text("設置文本行數////設置文本行數////設置文本行數////設置文本行數////設置文本行數////設置文本行數////設置文本行數" +
                    "////設置文本行數////設置文本行數////設置文本行數////設置文本行數////設置文本行數////設置文本行數////設置文本行數" +
                    "////設置文本行數////設置文本行數//",
                maxLines = 2,
                overflow = TextOverflow.Ellipsis,
                style = +themeTextStyle { body2 })
            HeightSpacer(10.dp)
            Divider(color = Color(0x23330033))
            HeightSpacer(10.dp)
            //橫向佈局
            Row(crossAxisAlignment = CrossAxisAlignment.Center) {
                Surface(color = Color.Blue) {
                    Clip(shape = RoundedCornerShape(8.dp)) {
                        Text(
                            "背景色",
                            modifier = Spacing(20.dp),
                            style = TextStyle(color = Color(0xFFFFFFFF), fontSize = 20.sp)
                        )
                    }
                }
                //寬度填充
                WidthSpacer(10.dp)
                Counter(counterState)
                WidthSpacer(10.dp)
                Form(true)
                Form(false)
            }
            HeightSpacer(10.dp)
            Divider(color = Color(0x23330033))
            HeightSpacer(10.dp)
            Row(modifier = ExpandedWidth, crossAxisAlignment = CrossAxisAlignment.Center) {
                textView(Flexible(1f), Color.Magenta, "權重-1")
                textView(Flexible(2f), Color.DarkGray, "權重-2")
                textView(Flexible(5f), Color.Red, "權重-5")
            }
            HeightSpacer(10.dp)
            Divider(color = Color(0x23330033))
            HeightSpacer(10.dp)
            //橫向滑動佈局
            HorizontalScroller {
                Row {
                    //循環5次
                    repeat(5) {
                        //卡片佈局
                        Card(shape = RoundedCornerShape(10.dp)) {
                            //水波紋
                            Ripple(bounded = true) {
                                Surface(color = Color.LightGray) {
                                    Container(width = 150.dp, height = 150.dp) {
                                        Column {
                                            Container(height = 110.dp, expanded = true) {
                                                DrawImage(image)
                                            }
                                            Text(
                                                text = "TitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitleTitle",
                                                style = (+themeTextStyle { subtitle1 }).withOpacity(
                                                    0.87f
                                                ),
                                                maxLines = 2,
                                                overflow = TextOverflow.Ellipsis
                                            )
                                        }
                                    }
                                }
                            }
                        }
                        WidthSpacer(16.dp)
                    }
                }
            }
            HeightSpacer(10.dp)
            //導航欄
            TabRow(items = listOf("導", "航", "欄"), selectedIndex = 0) { index, text ->
                //標題
                Tab(text = text, selected = 0 == index) {
                    Toast.makeText(this@YTestActivity, "index=$index", Toast.LENGTH_SHORT).show()
                }
            }
        }
    }

    @Composable  //ComposeUI
    fun textView(flex: Modifier, color: Color, text: String) {
        Column(modifier = flex) {
            Surface(color = color) {
                Text(
                    text,
                    style = TextStyle(color = Color(0xFFFFFFFF), fontSize = 20.sp)
                )
            }
        }
    }

    /**
     * 按鈕點擊
     */
    @Composable   //ComposeUI
    fun Counter(state: NumState) {
        //按鈕
        Button(
            text = "已經點了${state.count}次了",
            onClick = {
                state.count++
            },
            style = ContainedButtonStyle(color = if (state.count > 0) Color.Green else +themeColor { primary })
        )
    }

    /**
     * 選擇框
     */
    @Composable
    fun Form(state: Boolean) {
        var formState = FormState(state)
        //選擇框
        Checkbox(
            checked = formState.optionChecked,
            onCheckedChange = { newState -> formState.optionChecked = newState }
        )
    }


    @Model //@Model修飾的實體修改的同時會通知UI自動更新
    class FormState(var optionChecked: Boolean)

    @Model
    class NumState(var count: Int = 0)


    val green = Color(0xFF1EB90)
    val grey = Color(0xFF26282F)

    private val themeColros = MaterialColors(
        primary = green,
        surface = grey,
        onSurface = Color.White
    )

    /**
     * 自定義主題
     */
    @Composable
    fun CustomTheme(children: @Composable() () -> Unit) {
        MaterialTheme(colors = themeColros) {
            val textStyle = TextStyle(color = Color.Red)
            CurrentTextStyleProvider(value = textStyle) {
                children()
            }
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章