原創|Android Jetpack Compose 最全上手指南

在今年的Google/IO大會上,亮相了一個全新的 Android 原生 UI 開發框架-Jetpack Compose, 與蘋果的SwiftIUI同樣,Jetpack Compose是一個聲明式的UI框架,隨着了今年安卓和蘋果兩大移動平臺相繼推出本身的UI開發框架Jetpack Compose 和SwiftIUI,標誌着移動操做系統正式全面擁抱聲明式 UI 開發模式。java

1、聲明式 UI 的前世此生

其實聲明式 UI 並非什麼新技術,早在 2006 年,微軟就已經發布了其新一代界面開發框架 WPF,其採用了 XAML 標記語言,支持雙向數據綁定、可複用模板等特性。android

2010 年,由諾基亞領導的 Qt 團隊也正式發佈了其下一代界面解決方案 Qt Quick,一樣也是聲明式,甚至 Qt Quick 起初的名字就是 Qt Declarative。QML 語言一樣支持數據綁定、模塊化等特性,此外還支持內置 JavaScript,開發者只用 QML 就能夠開發出簡單的帶交互的原型應用。git

聲明式 UI 框架近年來飛速發展,而且被 Web 開發帶向高潮。React 更是爲聲明式 UI 奠基了堅實基礎並一直引領其將來的發展。隨後 Flutter 的發佈也將聲明式 UI 的思想成功帶到移動端開發領域...github

聲明式UI的意思就是,描述你想要一個什麼樣的UI界面,狀態變化時,界面按照先前描述的從新「渲染」便可獲得狀態絕對正確的界面,而不用像命令同樣,告訴程序一步一步該幹什麼,維護各類狀態。扯遠了,這個並非今天文章的重點,稍微瞭解一下就好,其餘的就不在本文延伸。關於聲明式的更多介紹,建議看看這篇文章:zhuanlan.zhihu.com/p/68275232編程

咱們回到本文的重點Jetpack Compose。微信

2、Jetpack Compose 介紹

Jetpack Compose 是一個用於構建原生Android UI 的現代化工具包,它基於聲明式的編程模型,所以你能夠簡單地描述UI的外觀,而Compose則負責其他的工做-當狀態發生改變時,你的UI將自動更新。因爲Compose基於Kotlin構建,所以能夠與Java編程語言徹底互操做,而且能夠直接訪問全部Android和Jetpack API。它與現有的UI工具包也是徹底兼容的,所以你能夠混合原來的View和如今新的View,而且從一開始就使用Material和動畫進行設計。app

3、Jetpack Compose 環境準備和Hello World

每當咱們學習一門新的語言,咱們都是從一個hello world開始,今天咱們也從一個hello world來開始Jetpack Compose 吧! 要想得到Jetpack Compose 的最佳體驗,咱們須要下載最新版本的Android Studio 預覽版本(即Android Studio 4.0)。由於Android Studio 4.0 添加了對Jetpack Compose 的支持,如新的Compose 模版和Compose 及時預覽。框架

Android Studio 4.0.png

使用Jetpack Compose 來開始你的開發工做有2種方式:jvm

  • 將Jetpack Compose 添加到現有項目
  • 建立一個支持Jetpack Compose的新應用

接下來分別介紹一下這兩種方式。maven

1. 將Jetpack Compose 添加到現有項目

若是你想在現有的項目中使用Jetpack Compose,你須要配置一些必須的設置和依賴:

(1)gradle 配置

在app目錄下的build.gradle 中將app支持的最低API 版本設置爲21或更高,同時開啓Jetpack Compose enable開關,代碼以下:

android {
    defaultConfig {
        ...
        minSdkVersion 21
    }

    buildFeatures {
        // Enables Jetpack Compose for this module
        compose true
    }
    ...

    // Set both the Java and Kotlin compilers to target Java 8.

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    kotlinOptions {
        jvmTarget = "1.8"
    }
}
複製代碼

(2) 使用試驗版Kotlin-Gradle 插件

Jetpack Compose 須要試驗版的Kotlin-Gradle插件,在根目錄下的build.gradle添加以下代碼:

buildscript {
    repositories {
        google()
        jcenter()
        // To download the required version of the Kotlin-Gradle plugin,
        // add the following repository.
        maven { url 'https://dl.bintray.com/kotlin/kotlin-eap' }
    ...
    dependencies {
        classpath 'com.android.tools.build:gradle:4.0.0-alpha01'
        classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.60-eap-25'
    }
}

allprojects {
    repositories {
        google()
        jcenter()
        maven { url 'https://dl.bintray.com/kotlin/kotlin-eap' }
    }
}
複製代碼

(3) 添加Jetpack Compose工具包依賴項

在app目錄下的build.gradle添加Jetpack Compose 工具包依賴項,代碼以下:

dependencies {
    // You also need to include the following Compose toolkit dependencies.
    implementation 'androidx.ui:ui-tooling:0.1.0-dev02'
    implementation 'androidx.ui:ui-layout:0.1.0-dev02'
    implementation 'androidx.ui:ui-material:0.1.0-dev02'
    ...
}
複製代碼

ok,到這兒準備工做就完畢,就能夠開始寫代碼了,可是前面說了,還有一種方式接入Jetpack Compose ,咱們來一塊兒看看。

2. 建立一個支持Jetpack Compose的新應用

比起在現有應用中接入Jetpack Compose ,建立一個支持Jetpack Compose 的新項目則簡單了許多,由於Android Studio 4.0 提供了一個新的Compose 模版,只要選擇這個模版建立應用,則全部上面的那些配置項都自動幫咱們完成了。

建立一個支持Jetpack Compose 的應用,以下幾個步驟就能夠了:

    1. 若是你在Android Studio的歡迎窗口,點擊Start a new Android Studio project,若是你已經打開了Android Studio 項目,則在頂部菜單欄選擇File > New > New Project
    1. Select a Project Template 窗口,選擇Empty Compose Activity而且點擊下一步
    1. Configure your project 窗口,作以下幾步:
    • a. 設置項目名稱, 包名保存位置
    • b. 注意,在語言下來菜單中,Kotlin 是惟一一個可選項,由於Jetpack Compose 只能用Kotlin來寫的才能運行。
    • c. Minimum API level 下拉菜單中,選擇21或者更高
    1. 點擊Finish

如今,你就可使用Jetpack Compose 來編寫你的應用了。

3. Hello wold

MainActivity.kt中添加以下代碼:

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
             Text("Hello, Android技術雜貨鋪")
        }
    }
}
複製代碼

hello.png

Jetpack Compose是圍繞composable函數來構建的。這些函數使你能夠經過描述應用程序的形狀和數據依賴,以編程方式定義應用程序的UI,而不是着眼於UI的構建過程。要建立composable函數,只須要在函數名前面加上一個@composable註解便可, 上面的Text就是一個composable函數。

4. 定義一個composable函數

一個composable函數只能在另外一個composable函數的做用域裏北調用,要使一個函數變爲composable函數,只需在函數名前加上@composable註解,咱們把上面的代碼中,setContent中的部分移到外面,抽取到一個composable函數中,而後傳遞一個參數nametext元素。

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            Greeting("Android技術雜貨鋪")
        }
    }
}

@Composable
fun Greeting(name: String) {
    Text(text = "Hello $name!")
}
複製代碼

4、佈局

UI元素是分層級的,元素包含在其餘元素中。在Jetpack Compose中,你能夠經過從其餘composable函數中調composable函數來構建UI層次結構。

UI.png

在Android的xml佈局中,若是要顯示一個垂直結構的佈局,最長用的就是LinearLayout, 設置android:orientation 值爲vertical, 子元素就會垂直排列,那麼,在Jetpack Compose 中,如何來實現垂直佈局呢?先添加幾個Text來看一下。

1. 添加多個Text

在上面的例子中,咱們添加了一個Text顯示文本,如今咱們添加三個文本,代碼以下:

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            NewsStory()
        }
    }
}

@Composable
fun NewsStory() {
    Text("我超❤️JetPack Compose的!")
    Text("Android技術雜貨鋪")
    Text("依然范特西")
}
複製代碼

image.png

從上圖能夠看到,咱們添加了3個文本,可是,因爲咱們尚未提供有關如何排列它們的任何信息,所以三個文本元素相互重疊繪製,使得文本不可讀。

2. 使用Column

要使重疊繪製的Text文本可以垂直排列,咱們就須要使用到Column函數,寫過flutter的同窗看起來是否是很眼熟?是的,跟flutter裏面的Column Widget 名字和功能徹底同樣,甚至連他們的屬性都一摸同樣。

@Composable
fun NewsStory() {
    Column { // 添加Column,使佈局垂直排列
        Text("我超❤️JetPack Compose的!")
        Text("Android技術雜貨鋪")
        Text("依然范特西")
    }
}
複製代碼

效果以下:

Column.png

能夠看到,前面重疊的佈局,如今已經垂直排列了,可是,默認狀況下,從左上角開始,一個接一個的排列,沒有任何間距。接下來,咱們給Column 設置一些樣式。

3. 給Column添加樣式

在調用Column()時,能夠傳遞參數給Column()來配置Column的大小、位置以及設置子元素的排列方式。

@Composable
fun NewsStory() {
    Column (
        crossAxisSize = LayoutSize.Expand,
        modifier = Spacing(16.dp)
    ){ // 添加Column,使佈局垂直排列
        Text("我超❤️JetPack Compose的!")
        Text("Android技術雜貨鋪")
        Text("依然范特西")
    }
}
複製代碼

image.png

如上圖所示,咱們填充了padding,其餘效果幾乎一摸同樣, 上面代碼中的設置屬性解釋以下:

  • crossAxisSize: 指定Column組件(注:Compose中,全部的組件都是composable函數,文中的組件都是指代composable函數)在水平方向的大小,設置 crossAxisSizeLayoutSize.Expand即表示Column寬度應爲其父組件容許的最大寬度,至關於傳統佈局中的match_parant ,還有一個值爲LayoutSize.Wrap,看名字就知道,包裹內容,至關於傳統佈局中的wrap_content

  • modifier:使你能夠進行其餘格式更改。在這種狀況下,咱們將應用一個Spacing修改器,該設置將Cloumn與周圍的視圖產生間距。

4. 如何顯示一張圖片?

在原來的安卓原生布局中,顯示圖片有相應的控件ImageView,設置本地圖片地址或者Bitmap就能展現,在Jetpack Compose 中該如何顯示圖片呢?

header.png

咱們先下載這張圖片到本地,添加到資源管理器中,命名爲header.png, 咱們更改一下上面的NewsStory ()方法,先從資源文件夾獲取圖片image,而後經過DrawImage()將圖片繪製出來:

@Composable
fun NewsStory() {
    // 獲取圖片
    val image = +imageResource(R.mipmap.header)
    Column (
        crossAxisSize = LayoutSize.Expand,
        modifier = Spacing(16.dp)
    ){ // 添加Column,使佈局垂直排列
        // 顯示圖片
        DrawImage(image)
        
        Text("我超❤️JetPack Compose的!")
        Text("Android技術雜貨鋪")
        Text("依然范特西")
    }
}
複製代碼

image.png

能夠看到,圖片不會按正確的比列顯示,接下來,咱們來修復它。

圖片已添加到佈局中,但會展開以填充整個視圖,並和文本是拼疊排列,文字顯示在上層。要設置圖形樣式,請將其放入Container(又一個和flutter中同樣的控件)

  • Container: 一個通用的內容對象,用於保存和安排其餘UI元素。而後,你能夠將大小和位置的設置應用於容器。
@Composable
fun NewsStory() {
    // 獲取圖片
    val image = +imageResource(R.mipmap.header)
    Column (
        crossAxisSize = LayoutSize.Expand,
        modifier = Spacing(16.dp)
    ){ // 添加Column,使佈局垂直排列
        // 放在容器中,設置大小
        Container(expanded = true, height = 180.dp) {
            // 顯示圖片
            DrawImage(image)
        }
        Text("我超❤️JetPack Compose的!")
        Text("Android技術雜貨鋪")
        Text("依然范特西")
    }
}
複製代碼

image.png

  • expanded : 指定Container的大小,默認是false(Container的大小是子組件的大小,至關於wrap_content),若是將它設置爲true,就指定Container的大小爲父控件所容許的最大size, 至關於match_parent

  • height : 設置Container容器的高度,height屬性的優先級高於expanded,所以會覆蓋expanded,如上面的例子,設置height180dp,也就是容器寬爲父控件寬度,高爲180dp

5. 添加間距Spacer

咱們看到,圖片和文本之間沒有間距,傳統佈局中,咱們能夠添加Margin屬性,設置間距,在Jetpack Compose 中,咱們可使用HeightSpacer()WidthSpacer() 來設置垂直和水平間距

HeightSpacer(height = 20.dp) //設置垂直間距20dp
 WidthSpacer(width = 20.dp) // 設置水平間距20dp
複製代碼

在上面的例子中,咱們來爲圖片和文本之間添加20dp的間距:

@Composable
fun NewsStory() {
    // 獲取圖片
    val image = +imageResource(R.mipmap.header)
    Column (
        crossAxisSize = LayoutSize.Expand,
        modifier = Spacing(16.dp)
    ){ // 添加Column,使佈局垂直排列
        // 放在容器中,設置大小
        Container(expanded = true, height = 180.dp) {
            // 顯示圖片
            DrawImage(image)
        }

        HeightSpacer(height = 20.dp) // 添加垂直方向間距20dp

        Text("我超❤️JetPack Compose的!")
        Text("Android技術雜貨鋪")
        Text("依然范特西")
    }
}
複製代碼

image.png

5、使用Material design 設計

Compose 旨在支持Material Design 設計原則,許多組件都實現了Material Design 設計,能夠開箱即用,在這一節中,將使用一些Material小組件來對app進行樣式設置

1. 添加Shape樣式

Shape是Material Design 系統中的支柱之一,咱們來用clip函數對圖片進行圓角裁剪。

@Composable
fun NewsStory() {
    // 獲取圖片
    val image = +imageResource(R.mipmap.header)
    Column (
        crossAxisSize = LayoutSize.Expand,
        modifier = Spacing(16.dp)
    ){ // 添加Column,使佈局垂直排列
        // 放在容器中,設置大小
        Container(expanded = true, height = 180.dp) {
            Clip(shape = RoundedCornerShape(10.dp)) {
                // 顯示圖片
                DrawImage(image)
            }
           
        }

        HeightSpacer(height = 20.dp) // 添加垂直方向間距20dp

        Text("我超❤️JetPack Compose的!")
        Text("Android技術雜貨鋪")
        Text("依然范特西")
    }
}
複製代碼

形狀是不可見的,可是咱們的圖片已經被裁剪了成了設置的形狀樣式,所以如上圖,圖片已經有圓角了。

2. 給Text 添加一些樣式

經過Compose,能夠輕鬆利用Material Design原則。將MaterialTheme()應用於建立的組件

@Composable
fun NewsStory() {
    // 獲取圖片
    val image = +imageResource(R.mipmap.header)
    // 使用Material Design 設計
    MaterialTheme() {
        Column (
            crossAxisSize = LayoutSize.Expand,
            modifier = Spacing(16.dp)
        ){ // 添加Column,使佈局垂直排列
            // 放在容器中,設置大小
            Container(expanded = true, height = 180.dp) {
                Clip(shape = RoundedCornerShape(10.dp)) {
                    // 顯示圖片
                    DrawImage(image)
                }

            }

            HeightSpacer(height = 20.dp) // 添加垂直方向間距20dp

            Text("我超❤️JetPack Compose的!")
            Text("Android技術雜貨鋪")
            Text("依然范特西")
        }  
    }
}
複製代碼

如上面的代碼,添加了MaterialTheme後,從新運行,效果沒有任何變化,文本如今使用了MaterialTheme的默認文本樣式。接下來,咱們將特定的段落樣式應用於每一個文本元素。

@Composable
fun NewsStory() {
    // 獲取圖片
    val image = +imageResource(R.mipmap.header)
    // 使用Material Design 設計
    MaterialTheme() {
        Column (
            crossAxisSize = LayoutSize.Expand,
            modifier = Spacing(16.dp)
        ){ // 添加Column,使佈局垂直排列
            // 放在容器中,設置大小
            Container(expanded = true, height = 180.dp) {
                Clip(shape = RoundedCornerShape(10.dp)) {
                    // 顯示圖片
                    DrawImage(image)
                }

            }

            HeightSpacer(height = 20.dp) // 添加垂直方向間距20dp

            Text("我超❤️JetPack Compose的!", style = +themeTextStyle { h5 }) // 注意添加了style
            Text("Android技術雜貨鋪", style = +themeTextStyle { body1 }) // 注意添加了style
            Text("依然范特西", style = +themeTextStyle { body2 }) // 注意添加了style
        }
    }
}
複製代碼

如今看看,咱們的文本樣式已經有變化了,標題有6中樣式 h1-h6,其實HTML中的樣式很像,內容文本有body1body22中樣式。

Material 調色版使用了一些基本顏色,若是要強調文本,能夠調整文本的不透明度:

Text("我超❤️JetPack Compose的!", style = (+themeTextStyle { h5 }).withOpacity(0.87f))
  Text("Android技術雜貨鋪", style = (+themeTextStyle { body1 }).withOpacity(0.87f))
  Text("依然范特西", style = (+themeTextStyle { body2 }).withOpacity(0.6f))
複製代碼

有些時候,標題很長,可是咱們又不想長標題換行從而影響咱們的app UI ,所以,咱們能夠設置文本的最大顯示行數,超過部分就截斷。

如本例所示,咱們設置顯示最大行數爲2,多於的部分截斷處理:

Text("我超❤️JetPack Compose的!寫起來簡單,複用性又強,能夠抽取不少組件來複用,不用管理複雜的狀態變動!",
                maxLines = 2, overflow = TextOverflow.Ellipsis,
                style = (+themeTextStyle { h5 }).withOpacity(0.87f))
複製代碼

能夠看到,設置了 maxLinesoverflow 以後,超出部分就截斷處理了,不會影響到整個佈局樣式。

6、Compose 佈局實時預覽

從Android Studio 4.0 開始,提供了在IDE中預覽composable函數的功能,不用像之前那樣,要先下載一個模擬器,而後將app狀態模擬器上,運行app才能看到效果。

可是有一個限制,那就是composable函數不能有參數

知足下面兩個條件:

  • 函數沒有參數
  • 在函數前面添加@Preview註解

預覽效果圖以下:

當佈局改變了以後,頂部會出現一個導航條,顯示預覽已通過期,點擊build&Refresh就能夠刷新預覽

這真的是一個很是棒的功能,像其餘聲明式佈局,如React 、flutter 是沒有這個功能的,佈局了以後,要從新運行才能看到效果,雖然能夠熱啓動,可是仍是沒有這個預覽來得直接。

還有一個很是牛逼的地方是,compose 的預覽能夠同時預覽多個composable函數。

效果以下:

7、總結

Jetpack Compse 目前仍是試驗版,因此確定還存在不少問題,還不能如今將其用於商業項目中,可是這並不能妨礙咱們學習和體驗它,聲明式 UI 框架近年來飛速發展,React 爲聲明式 UI 奠基了堅實基礎並。 Flutter 的發佈將聲明式 UI 的思想成功帶到移動端開發領域,Apple和Google 分別前後發佈了本身的聲明式UI框架SwiftUI 和 Jetpack Compose , 之後,原生UI佈局,聲明式可能將會是主流。

以上就是本文的全部內容,但願它對你有用!

若是你喜歡個人文章,就關注下個人公衆號 Android技術雜貨鋪 、 簡書 或者Github! 微信公衆號:Android技術雜貨鋪

簡書:www.jianshu.com/u/35167a70a…

GitHub:github.com/pinguo-zhou…

公衆號.png
相關文章
相關標籤/搜索