Jetpack Compose 是用于構建原生 Android 界面的新工具包。Jetpack Compose 使用更少的代碼、強大的工具和直觀的 Kotlin API 簡化并加快了 Android 上的界面開發。
在本教程中,您將使用聲明性的函數構建一個簡單的界面組件。您無需修改任何 XML 布局,也不需要直接創建界面微件,而只需要調用 Jetpack Compose 函數來聲明您想要的元素,Compose 編譯器即會完成后面的所有工作。
1.0 API Surface 功能完整,但可能包含錯誤
之前,簡單用兩篇文章認識了下 Compose 使用,接下來拆分知識點學習。
1. 可組合函數
Jetpack Compose 是圍繞可組合函數構建的。這些函數可讓您以編程方式定義應用界面,只需描述應用界面的形狀和數據依賴關系,而不必關注界面的構建過程。如需創建可組合函數,只需將 @Composable 注釋添加到函數名稱中即可。
添加文本元素 Text("Hello world!")
首先,按照 Jetpack Compose 設置說明操作,使用 Empty Compose Activity 模板創建一個應用。默認模板已包含一些 Compose 元素,但我們下面要逐步進行構建。首先,刪除“Greeting”和“Default Preview”函數,然后從 MainActivity
中刪除 setContent
塊,將該 Activity 留空。編譯并運行您的空白應用。
現在,向空白的 Activity 中添加文本元素??梢酝ㄟ^定義內容塊并調用 Text()
函數來實現此目的。
setContent 塊定義了 Activity 的布局。我們不使用 XML 文件來定義布局內容,而是調用可組合函數。Jetpack Compose 使用自定義 Kotlin 編譯器插件將這些可組合函數轉換為應用的界面元素。例如,Compose 界面庫定義了 Text()
函數;您可以調用該函數在應用中聲明文本元素。
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Text("Hello world!")
}
}
}
定義可組合函數
可組合函數只能在其他可組合函數的范圍內調用。要使函數成為可組合函數,請添加 @Composable 注釋。如需嘗試此操作,請定義一個 Greeting() 函數并向其傳遞一個名稱,然后該函數就會使用該名稱配置文本元素。
在 Android Studio 中預覽函數
當前的 Canary 版 Android Studio 允許您在 IDE 中預覽可組合函數,而無需將應用下載到 Android 設備或模擬器中。主要限制在于,可組合函數不能接受任何參數。因此,您無法直接預覽 Greeting()
函數,而是需要創建另一個名為 PreviewGreeting()
的函數,由該函數使用適當的參數調用 Greeting()
。請在 @Composable
上方添加 @Preview
注釋。
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Greeting("Android")
}
}
}
@Composable
fun Greeting(name: String) {
Text (text = "Hello $name!")
}
@Preview
@Composable
fun PreviewGreeting() {
Greeting("Android")
}
重新構建您的項目。由于新的 previewGreeting() 函數未在任何位置受到調用,因此應用本身不會更改,但 Android Studio 會添加一個預覽窗口。此窗口會顯示由標有 @Preview 注釋的可組合函數創建的界面元素的預覽。任何時候,如需更新預覽,請點擊預覽窗口頂部的刷新按鈕。
2. 布局
從一些文本開始, 會出現重疊現象
返回到您的 Activity,用新的 NewsStory() 函數替換 Greeting() 函數。在本教程的其余部分,您將修改該 NewsStory() 函數,并且不會再更改 Activity 代碼。
最佳做法是單獨創建不會被應用調用的預覽函數;專門的預覽函數可以提高性能,并且有利于以后更輕松地設置多個預覽。因此,請創建一個默認預覽函數,該函數的唯一用途就是調用 NewsStory() 函數。隨著您按照本教程對 NewsStory() 進行更改,預覽內容會反映您所做的更改。
這段代碼會在內容視圖中創建三個文本元素。但是,由于我們未提供有關如何排列這三個文本元素的信息,因此它們會相互重疊,使文本無法閱讀。
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
NewsStory()
}
}
}
@Composable
fun NewsStory() {
Text("A day in Shark Fin Cove")
Text("Davenport, California")
Text("December 2018")
}
@Preview
@Composable
fun DefaultPreview() {
NewsStory()
}
使用 Column,解決布局問題
Column 函數可讓您垂直堆疊元素。向 NewsStory() 函數中添加一個 Column。
默認設置會直接將所有子項逐個堆疊起來,中間不留間距。Column 本身位于內容視圖的左上角。
@Composable
fun NewsStory() {
Column {
Text("A day in Shark Fin Cove")
Text("Davenport, California")
Text("December 2018")
}
}
向 Column 中添加樣式設置
通過將參數傳遞給 Column 調用,可以配置 Column 的尺寸和位置,以及 Column 的子項的排列方式。
該設置具有以下含義:
modifier:可供您配置布局。本例中使用了一個 Modifier.padding 修飾符,將 Column 內嵌在周圍的視圖中。
@Composable
fun NewsStory() {
Column(
modifier = Modifier.padding(16.dp)
) {
Text("A day in Shark Fin Cove")
Text("Davenport, California")
Text("December 2018")
}
}
添加圖片
我們想在文本上面添加圖片。使用資源管理器將這張名為 header
的照片添加到應用的可繪制資源。
現在,修改您的 NewsStory()
函數。您將添加對 Image()
的調用,以將圖片放入 Column
?!癴oundation”軟件包中提供了這些可組合項,您可能需要添加該軟件包。請參閱 Jetpack Compose 設置說明。圖片的比例會有問題,但沒關系,您可以在下一步中糾正此問題。
@Composable
fun NewsStory() {
Column(
modifier = Modifier.padding(16.dp)
) {
Image(
painter = painterResource(R.drawable.header),
contentDescription = null
)
Text("A day in Shark Fin Cove")
Text("Davenport, California")
Text("December 2018")
}
}
圖片已添加到布局中,但其尺寸尚未調整為適當大小。如需設置圖片樣式,請將尺寸 Modifier 傳遞給對 Image() 的調用。
height(180.dp):指定圖片的高度。
fillMaxWidth():指定圖片的寬度應足以填充所屬布局。
您還需要向 Image() 傳遞一個 contentScale 參數:
contentScale = ContentScale.Crop:指定圖片應填充 Column 的整個寬度,并根據需要剪裁為適當的高度。
@Composable
fun NewsStory() {
Column(
modifier = Modifier.padding(16.dp)
) {
Image(
painter = painterResource(R.drawable.header),
contentDescription = null,
modifier = Modifier
.height(180.dp)
.fillMaxWidth(),
contentScale = ContentScale.Crop
)
Text("A day in Shark Fin Cove")
Text("Davenport, California")
Text("December 2018")
}
}
添加 Spacer,將圖片與標題分開。
@Composable
fun NewsStory() {
Column(
modifier = Modifier.padding(16.dp)
) {
Image(
painter = painterResource(R.drawable.header),
contentDescription = null,
modifier = Modifier
.height(180.dp)
.fillMaxWidth(),
contentScale = ContentScale.Crop
)
Spacer(Modifier.height(16.dp))
Text("A day in Shark Fin Cove")
Text("Davenport, California")
Text("December 2018")
}
}
3. Material Design
Compose 旨在支持 Material Design 原則。它的許多界面元素都原生支持 Material Design。使用 Material 微件來設置應用的樣式。
采用形狀
Material Design 系統的關鍵要素之一就是 Shape。使用 clip() 函數對圖片的四角進行圓角化處理。
Shape 不可見,但圖片已被剪裁以匹配 Shape,因此現在呈現輕微的圓角。
設置文本樣式
借助 Compose,您可以輕松遵循 Material Design 原則。將 MaterialTheme 應用到您創建的組件。
差別可能不太明顯,但文本現在采用了 MaterialTheme 的默認文本樣式。接下來,對每個文本元素應用特定的段落樣式。
但有時,一篇文章的標題很長,我們不希望過長的標題影響應用的外觀。嘗試更改第一個文本元素。
配置文本元素,將長度上限設置為 2 行。如果文本很短,不超過此限制,則此設置沒有影響;但如果文本過長,顯示的文本就會被自動截短。
@Composable
fun NewsStory() {
MaterialTheme {
val typography = MaterialTheme.typography
Column(
modifier = Modifier.padding(16.dp)
) {
Image(
painter = painterResource(R.drawable.header),
contentDescription = null,
modifier = Modifier
.height(180.dp)
.fillMaxWidth()
.clip(shape = RoundedCornerShape(4.dp)),
contentScale = ContentScale.Crop
)
Spacer(Modifier.height(16.dp))
Text(
"A day wandering through the sandhills " +
"in Shark Fin Cove, and a few of the " +
"sights I saw",
style = typography.h6,
maxLines = 2,
overflow = TextOverflow.Ellipsis)
Text("Davenport, California",
style = typography.body2)
Text("December 2018",
style = typography.body2)
}
}
}