Android Jetpack Compose快速上手
一、Jetpack Compose簡介
Jetpack Compose是Google推出的一個用於構建原生Android 介面的工具包,旨在幫助開發者更快、更輕鬆地在Android 平臺上構建原生客戶端應用。同時,作為全新的宣告式的UI框架,Jetpack Compose可以使用宣告式Kotlin API取代Android 傳統的xml佈局。
那什麼是宣告式呢?要搞清楚這個問題,我們需要佈局開發中的另外一個概念:命令式。事實上,傳統的使用xml佈局方式就是命令式。在傳統的命令式開發流程中,我們首先需要使用xml來建立佈局,然後再通過findViewById方法獲取控制元件,最後再繫結資料。而在宣告式開發中,我們可以直接呼叫compose的庫元件進行渲染,比如:
@Composable
fun ShowText(content: String){
Text(text = content)
}
事實上,除了Jetpack Compose,Flutter、React Native和Swift-UI 等框架都是宣告式的,可以說,前端的大部分的頁面渲染都可以使用宣告式來完成。
二、快速上手
2.1 環境搭建
工欲善其事,必先利其器。目前,Android Studio對Jetpack Compose 已經有了很好的支援,我們只需要下載最新版的Android Studio即可。
安裝完成之後,我們可以下載託管在github上的 Jetpack Compose 示例應用來體驗Jetpack Compose的魅力。
2.2 建立Jetpack Compose應用
為了幫助開發者快速地上手Jetpack Compose,Android Studio提供了支援Jetpack Compose 的新專案模板。我們只需要開啟 Android Studio,然後在選單欄中依次選擇 【File】->【New】->【New Project】 ->【Empty Compose Activity】。
然後,點選【Next】按鈕,填寫 Name、Package name 和 Save location等引數即可完成Jetpack Compose專案的建立。工程建立完成之後,Jetpack Compose專案會預設新增如下一些依賴。
dependencies {
implementation("androidx.compose.ui:ui:1.2.1")
// Tooling support (Previews, etc.)
implementation("androidx.compose.ui:ui-tooling:1.2.1")
// Foundation (Border, Background, Box, Image, Scroll, shapes, animations, etc.)
implementation("androidx.compose.foundation:foundation:1.2.1")
// Material Design
implementation("androidx.compose.material:material:1.2.1")
// Material design icons
implementation("androidx.compose.material:material-icons-core:1.2.1")
implementation("androidx.compose.material:material-icons-extended:1.2.1")
// Integration with observables
implementation("androidx.compose.runtime:runtime-livedata:1.2.1")
implementation("androidx.compose.runtime:runtime-rxjava2:1.2.1")
// UI Tests
androidTestImplementation("androidx.compose.ui:ui-test-junit4:1.2.1")
}
2.3 原有專案新增Jetpack Compose
當然,使用Android Studio提供的Jetpack Compose 模板來建立專案是最簡單的,如果對於老的Android專案,我們需要怎麼處理呢?
首先,開啟專案的build.gralde檔案,確保Kotlin的版本是1.4.30以上的版本。
plugins {
...
id 'org.jetbrains.kotlin.android' version '1.5.30' apply false
}
然後,開啟app/build.gralde檔案,新增或修改如下一些配置:
``` android {
// 1、確保最低sdk版本為21或者更高
defaultConfig {
...
minSdkVersion 21
}
buildFeatures {
// 2、開啟 jetpack compose 支援
compose true
}
...
// 3、設定java 和 kotlin 編譯器版本為java8或者更高的版本
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
// 4、新增kotlin編譯器擴充套件版本
composeOptions {
kotlinCompilerExtensionVersion '1.3.0'
}
} ```
然後,新增Jetpack Compose 開發需要的一些依賴庫。
dependencies {
// Integration with activities
implementation 'androidx.activity:activity-compose:1.5.1'
// Compose Material Design
implementation 'androidx.compose.material:material:1.2.1'
// Animations
implementation 'androidx.compose.animation:animation:1.2.1'
// Tooling support (Previews, etc.)
implementation 'androidx.compose.ui:ui-tooling:1.2.1'
// Integration with ViewModels
implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.5.1'
// UI Tests
androidTestImplementation 'androidx.compose.ui:ui-test-junit4:1.2.1'
}
2.4 遷移到 Compose
對於傳統的xml佈局,我們如何將其遷移到 Jetpack Compose。加入,我們在 XML 佈局中有如下一段程式碼。
```
<...>
```
為了將其遷移到 Compose,我們可以將 TextView 替換為保留了相同佈局引數和 id 的 ComposeView,如下所示。
```
<...>
```
然後,在使用了該XML佈局的Activity或Fragment中獲取ComposeView,然後呼叫setContent方法並向其中新增Compose內容。
```
class MyActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// ...
val greeting = findViewById
@Composable private fun Greeting() { Text( text = stringResource(R.string.greeting), style = MaterialTheme.typography.h5, modifier = Modifier .fillMaxWidth() .padding(horizontal = dimensionResource(R.dimen.margin_small)) .wrapContentWidth(Alignment.CenterHorizontally) ) } ```
三、Compose工具
事實上,為了支援Jetpack Compose 的快速開發,Android Studio引入了許多專用於Jetpack Compose 的新功能。它支援使用程式碼優先方法,同時提高了開發者的工作效率,因為開發者不必在設計介面或程式碼編輯器之間二選一。
而基於View的介面與Jetpack Compose之間的一個基本區別在於,Compose不依賴View來呈現其可組合項。同時,Android Studio 為Jetpack Compose提供了擴充套件功能,使其不必像 Android View 一樣開啟模擬器或連線到裝置即可預覽,從而加快了開發者實現其介面設計的迭代過程。
同時,為了實現如需為 Jetpack Compose 的預覽功能,需要我們在應用 build.gradle 檔案中新增以下依賴項:
debugImplementation "androidx.compose.ui:ui-tooling:1.2.1"
implementation "androidx.compose.ui:ui-tooling-preview:1.2.1"
3.1 預覽模式
3.1.1 可組合項預覽
首先,我們開啟新建的Jetpack Compose專案,MainActivity.kt的程式碼如下:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
ComposeDemosTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colors.background
) {
Greeting("Android")
}
}
}
}
}
@Composable
fun Greeting(name: String) {
Text(text = "Hello $name!")
}
@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
ComposeDemosTheme {
Greeting("Android")
}
}
在上面的程式碼中,setContent()不再是以前的傳遞一個View或者是layout,而是一個組合函式,也就是一個Compose元件。而帶有@Composable的Kotlin函式就是就是一個Compose元件,一般為了跟普通函式區分,因此上面的Greeting和DefaultPreview 都是一個Compose元件。
最後,點選拆分(設計/程式碼)檢視,開啟顯示預覽的右側面板就可以看到效果。
@Preview接受引數來支援Android Studio呈現的方式,我們可以在程式碼中手動新增這些引數,也可以點選 @Preview 旁邊的邊線圖示來顯示配置選擇器,以便選擇和更改這些配置引數。
除此之外,Android Studio 提供了一些功能來擴充套件可組合項預覽。我們可以通過讀取 LocalInspectionMode CompositionLocal來確認可組合項是否正在預覽中呈現。如果可組合項在預覽中呈現,LocalInspectionMode.current 的結果為 true。
if (LocalInspectionMode.current) {
//呈現在預覽介面
Text("Hello preview user!")
} else {
//在App中呈現
Text("Hello $name!")
}
3.1.2 互動模式
互動模式,可以實現在裝置上互動的方式和預覽互動,互動模式被隔離在沙盒環境中,在該模式下,我們可以在預覽中點選元素並輸入使用者輸入;預覽甚至播放動畫。預覽互動模式可以直接在Android Studio中執行,由於並未執行模擬器,所以存在一些使用限制:
- 無法訪問網路
- 無法訪問檔案
- 有些 Context API 不一定完全可用
使用互動模式時,只需要編寫好程式碼,然後點選【Start interactive mode】開啟,如下圖。
3.1.3 部署預覽
我們可以使用 @Preview 來部署應用到模擬器或實體裝置上。點選 @Preview 註解旁邊或預覽頂部的 Deploy to Device 圖示 ,Android Studio 會將該 @Preview 部署到連線的裝置或模擬器上。
3.1.4 Multipreview
使用 Multipreview註解時,我們可以定義一個註解類,該類本身可配置多個採用不同配置的 Preview註解。將此註解新增到一個可組合函式後,系統會自動同時呈現所有不同的預覽。例如,我們可以定義一個同時支援預覽多個裝置、字型大小或主題的註解類。
比如,我們首先定義一個可以改變字型的FontScalePreviews類。
@Preview(
name = "small font",
group = "font scales",
fontScale = 0.5f
)
@Preview(
name = "large font",
group = "font scales",
fontScale = 1.5f
)
annotation class FontScalePreviews
然後,在字型中使用這個預覽可組合項使用此自定義註解。
@FontScalePreviews
@Composable
fun HelloWorldPreview() {
Text("Hello World")
}
最終的效果如下圖。
當然,我們也可以將多個 MultiPreview 註解和普通 preview 註解結合進行使用,從而建立一個更完整的預覽集。結合使用 MultiPreview 註解並不意味著所有不同的組合都會得以呈現。實際上,每個 MultiPreview 註解會獨立執行,並且僅會呈現自己的變體。
@Preview(
name = "dark theme",
group = "themes",
uiMode = UI_MODE_NIGHT_YES
)
@FontScalePreviews
@DevicePreviews
annotation class CombinedPreviews
@CombinedPreviews
@Composable
fun HelloWorldPreview() {
MyTheme { Surface { Text("Hello world") } }
}
通過右鍵點選呈現的每個預覽,即可將其作為影象來複制。
預設情況下,我們的可組合項是以透明背景來顯示的。如果需要新增背景,那麼需要用到showBackground 和 backgroundColor 兩個引數,比如:
@Preview(showBackground = true, backgroundColor = 0xFF00FF00)
@Composable
fun WithGreenBackground() {
Text("Hello World")
}
如需手動設定尺寸,可以新增 heightDp 和 widthDp 引數。
@Preview(widthDp = 50, heightDp = 50)
@Composable
fun SquareComposablePreview() {
Box(Modifier.background(Color.Yellow)) {
Text("Hello World")
}
}
有時候,我們需要對狀態列和操作欄進行一些修改,那麼可以使用showSystemUi引數。
@Preview(showSystemUi = true)
@Composable
fun DecoratedComposablePreview() {
Text("Hello World")
}
當然,我們也可以使用@PreviewParameter註解來新增引數,用來將示例資料傳遞給某個可組合項預覽函式。
@Preview
@Composable
fun UserProfilePreview(
@PreviewParameter(UserPreviewParameterProvider::class) user: User
) {
UserProfile(user)
}
然後,建立一個可實現 PreviewParameterProvider 並以序列形式返回示例資料的類。
class UserPreviewParameterProvider : PreviewParameterProvider<User> {
override val values = sequenceOf(
User("Elise"),
User("Frank"),
User("Julia")
)
}
接著,序列中的每個資料元素都會呈現一個預覽。
當需要為多個預覽使用相同的提供程式類時。如有必要,可通過設定 limit 引數來限制呈現的預覽數量,比如。
@Preview
@Composable
fun UserProfilePreview(
@PreviewParameter(UserPreviewParameterProvider::class, limit = 2) user: User
) {
UserProfile(user)
}
3.2 編輯器
為了提高使用 Jetpack Compose 時的工作效率,Android Studio在編輯器區域提供了一些功能,如實時模板、邊線圖示、顏色選擇器等。
3.2.1 實時模板
Android Studio 提供了Compose 相關的實時模板,開發者可以通過輸入相應的模板縮寫來輸入程式碼段,以實現快速插入。
- comp:用於設定 @Composable 函式
- prev:用於建立 @Preview 可組合函式
- paddp:用於以 dp 為單位新增 padding 修飾符
- weight:用於新增 weight 修飾符
- W、WR、WC:用於通過 Box、Row 或 Column 容器設定當前可組合項的呈現效果
3.2.2 邊線圖示
邊線圖示是邊欄中可見的上下文操作,位於行號旁邊。Android Studio 引入了多個 Jetpack Compose 專用邊線圖示,以便開發者更輕鬆地使用。比如,可以直接通過邊線圖示將 @Preview 部署到模擬器或實體裝置上。
而對於顏色選擇器來說,我們可以點選顏色,然後更改選中的眼神,如下所示。
為了方便對影象進行選擇,Android Studio也支援圖形選擇器,可以通過影象資源選擇器更改選擇圖片,如下所示:
3.3 迭代開發
作為移動開發者,移動應用介面開發並不是一次性開發完所有的內容的。Android Studio 通過提供不需要完整 build 即可檢查、修改值和驗證最終結果的工具,支援使用 Jetpack Compose 進行逐步開發。
3.3.1 實時修改字面量
Android Studio 可以實時更新在預覽、模擬器和實體裝置中的可組合項中使用的一些常量字面量,如Int、String、Color、Dp、Boolean等。
通過“Live Edit of Literals”介面指示器啟用字面量修飾功能,無需進行編譯即可檢視觸發實時更新的常量字面量。
3.3.2 實時編輯
我們可以開啟 Android Studio Electric Eel 的 Canary 版本,然後使用實時編輯功能加快 Compose 開發過程。相較於實時編輯字面量功能,“實時編輯”是具備更強大功能的版本。開發者可以自動將程式碼更改部署到模擬器或裝置上,從而實時檢視可組合項更新後的效果。
3.3.3 Apply Changes
Apply Changes 支援更新程式碼和資源,並且不需要在模擬器或實體裝置上重新執行程式碼。每當開發者新增、修改或刪除可組合項時,只需要點選一下此按鈕,即可更新應用,而不必重新部署。
3.4 佈局檢查器
通過佈局檢查器,開發者可以在模擬器或實體裝置上檢查正在執行的應用中的 Compose 佈局。
如需跟蹤重組,需要在檢視選項中啟用【Show Recomposition Counts】。
啟用後,佈局檢查器會在左側顯示重組次數,在右側顯示跳過重組的次數。
3.5 動畫
Android Studio 允許開發者從動畫預覽中檢查動畫,我們可以在組合項預覽中描述了動畫效果,檢查每個動畫值在給定時間點的確切值,並且可以暫停、迴圈播放、快進或放慢動畫,以便在動畫過渡過程中除錯動畫。
當然,我們也可以使用動畫預覽以圖形方式呈現動畫曲線,這對於確保正確編排動畫值非常有用。
四、Kotlin與Jetpack Compose配合使用
Jetpack Compose使用Kotlin構建而成,在某些情況下,Kotlin 提供了一些特殊的慣用語,可以幫助開發者編寫良好的 Compose 程式碼。如果使用另一種程式語言,那麼很可能會錯失 Compose 的一些優勢。
4.1 預設引數
編寫 Kotlin 函式時,我們可以指定函式引數的預設值;如果呼叫方未明確傳遞相應的值,系統就會使用這些預設值。在 Kotlin 中,編寫一個函式並指定引數的預設值的方式和Java是類似的。
fun drawSquare(
sideLength: Int,
thickness: Int = 2,
edgeColor: Color = Color.Black
) { ... }
當然,上面的程式碼也可以簡寫成下面的方式,Kotlin的編譯器也是可以識別的。
drawSquare(sideLength = 30, thickness = 5, edgeColor = Color.Red)
4.2 高階函式和 lambda 表示式
所謂高階函式,指的是接收其他函式作為引數的函式,Kotlin也是支援高階函式的。例如,Button 可組合函式提供了一個 onClick lambda 引數。
Button(
// ...
onClick = myClickFunction
)
高階函式與 lambda 表示式是自然配對的。如果您只需要使用該函式一次,則不必在其他位置進行定義以將其傳遞給高階函式,而只需使用 lambda 表示式在該位置定義該函式即可。
Button(
// ...
onClick = {
// do something
// do something else
}
) { /* ... */ }
4.3 委託屬性
Kotlin支援委託屬性,這些屬性可以像欄位一樣被呼叫,但它們的值是通過對錶達式動態確定的。
``` class DelegatingClass { var name: String by nameGetterFunction() }
val myDC = DelegatingClass() println("The name property is: " + myDC.name) ```
當執行 println() 函式時,系統會呼叫 nameGetterFunction() 以返回字串的值。同時,使用狀態支援的屬性時,這些委託屬性特別有用。
var showDialog by remember { mutableStateOf(false) }
// Updating the var automatically triggers a state change
showDialog = true
4.4 協程
在 Kotlin 中,協程在語言級別提供了非同步程式設計的支援。協程可以掛起執行,而不會阻塞執行緒。自適應介面本質上是非同步的,而 Jetpack Compose 會在 API 級別引入協程而非使用回撥來解決此問題。
Jetpack Compose 提供了可在介面層中安全使用協程的 API,rememberCoroutineScope 函式會返回一個 CoroutineScope,可以用它在事件處理指令碼中建立協程並呼叫 Compose Suspend API。
val composableScope = rememberCoroutineScope()
Button(
// ...
onClick = {
composableScope.launch {
scrollState.animateScrollTo(0) // This is a suspend function
viewModel.loadData()
}
}
) { /* ... */ }
預設情況下,協程會依序執行程式碼塊。正在執行且呼叫掛起函式的協程會掛起其執行,直到掛起函式返回,即使掛起函式將執行移至其他 CoroutineDispatcher,也是如此。若要同時執行程式碼,則需要建立新的協程。在上述示例中,如需在滾動到螢幕頂部的同時從 viewModel 載入資料,則需要兩個協程。
val composableScope = rememberCoroutineScope()
Button(
onClick = {
composableScope.launch {
scrollState.animateScrollTo(0)
}
composableScope.launch {
viewModel.loadData()
}
}
) { /* ... */ }
協程可幫助您更輕鬆地合併非同步 API。在以下示例中,我們會將 pointerInput 修飾符與動畫 API 結合,以便在使用者點按螢幕時在元素的位置呈現動畫效果。
@Composable
fun MoveBoxWhereTapped() {
// Creates an `Animatable` to animate Offset and `remember` it.
val animatedOffset = remember {
Animatable(Offset(0f, 0f), Offset.VectorConverter)
}
Box(
// The pointerInput modifier takes a suspend block of code
Modifier.fillMaxSize().pointerInput(Unit) {
// Create a new CoroutineScope to be able to create new
// coroutines inside a suspend function
coroutineScope {
while (true) {
// Wait for the user to tap on the screen
val offset = awaitPointerEventScope {
awaitFirstDown().position
}
// Launch a new coroutine to asynchronously animate to where
// the user tapped on the screen
launch {
// Animate to the pressed position
animatedOffset.animateTo(offset)
}
}
}
}
) {
Text("Tap anywhere", Modifier.align(Alignment.Center))
Box(
Modifier
.offset {
// Use the animated offset as the offset of this Box
IntOffset(
animatedOffset.value.x.roundToInt(),
animatedOffset.value.y.roundToInt()
)
}
.size(40.dp)
.background(Color(0xff3c1361), CircleShape)
)
}
}
- Spring Boot 快速接入 ChatGPT
- 基於OpenAI API構建圖片生成器
- 超詳細的ChatGPT註冊教程來了
- Android桌面圖示快捷方式
- 推薦20個開源的前端低程式碼專案
- 輕量級的搜尋引擎MeiliSearch
- Android Jetpack Compose快速上手
- Android 13 正式版釋出
- 最新版React Native環境搭建
- 騰訊開源垃圾清理軟體檸檬 Lemon
- RxDogTag:自動標記RxJava原始訂閱點
- 2021,位元組最值得關注的10個開源專案
- Google Colab 線上機器學習平臺使用教程
- 前端如何開始深度學習,那不妨試試JAX
- 高仿京東Android App,整合React-Native熱更功能
- 一文讀懂Kotlin的資料流
- Android動態更換應用圖示
- HTTP 3規範正式釋出
- 基於Linphone開發Android音視訊通話
- 走進WWDC 2022蘋果開發者大會