柚子快報(bào)邀請(qǐng)碼778899分享:Android的Compose
柚子快報(bào)邀請(qǐng)碼778899分享:Android的Compose
Jetpack Compose 是用于構(gòu)建原生 Android 界面的新工具包,無需修改任何 XML 布局,也不需要使用布局編輯器。相反,只需調(diào)用可組合函數(shù)來定義所需的元素,Compose 編譯器即會(huì)完成后面的所有工作。
簡而言之,使用Compose,不再需要xml編寫頁面。
可組合函數(shù)(Composable function)
Compose是圍繞可組合函數(shù)構(gòu)建的,只需要描述應(yīng)用界面的外觀并提供數(shù)據(jù)依賴,而不必關(guān)注界面的構(gòu)建過程(如初始化元素、將其附加到父項(xiàng)等)。而創(chuàng)建Composable function,只需要添加注解@Composable到函數(shù)名稱前。
首先,我們構(gòu)建創(chuàng)建一個(gè)應(yīng)用:ComposeTutorial。在AS中選擇Empty Activity創(chuàng)建。
添加文本元素
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {//在此處定義布局
//此處的Text方法是由Compose界面庫定義的文本Composable function
Text("Hello world!")
}
}
}
setContent塊定義了activity的布局,在此處我們添加了Text即“Hello World!”。
自定義可組合函數(shù)
如果需要將一個(gè)函數(shù)轉(zhuǎn)換為Composable function,我們需要添加注解“@Composable”。
修改MainActivity:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MessageCard("Android")//使用我們自定義的Composable function
}
}
}
@Composable//添加注解,使該函數(shù)成為Composable function
fun MessageCard(name: String) {
Text(text = "Hello $name!")
}
在AS中預(yù)覽Composable function
借助@Preview注解,可以在AS中預(yù)覽Composable function,無需安裝到設(shè)備或虛擬器中。
唯一要求是該注解不能用于接收參數(shù)的函數(shù)中,因此在MainActivity新增如下函數(shù):
@Preview
@Composable
fun PreviewMessageCard() {
MessageCard("Android")
}
在重新構(gòu)建后,該函數(shù)沒有被調(diào)用,應(yīng)用本身不會(huì)改變,但是AS對(duì)于所有添加了@Preview注解的界面元素可以進(jìn)行預(yù)覽,點(diǎn)擊如下兩個(gè)按鈕之一即可:
布局(Layout)
在此處我們實(shí)現(xiàn)一個(gè)簡單的聊天界面,顯示發(fā)送者和消息內(nèi)容,點(diǎn)擊消息時(shí)可縮放。
添加多個(gè)文本
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
//向Composable function中傳入發(fā)送者名稱和消息內(nèi)容
MessageCard(Message("Android", "Jetpack Compose"))
}
}
}
//新建一個(gè)Message類,包含消息發(fā)送者和消息內(nèi)容
data class Message(val author: String, val body: String)
@Composable
fun MessageCard(msg: Message) {
Text(text = msg.author)
Text(text = msg.body)
}
@Preview
@Composable
fun PreviewMessageCard() {
MessageCard(
msg = Message("Lexi", "Hey, take a look at Jetpack Compose, it's great!")
)
}
這段代碼會(huì)在內(nèi)容視圖中創(chuàng)建兩個(gè)文本元素。不過,由于未提供有關(guān)如何排列這兩個(gè)文本元素的信息,因此它們會(huì)相互重疊,使文本無法閱讀。
使用Column、Row、Box
Column,直譯為“圓柱體、長列”。
使用該函數(shù)修改MessageCard,可以垂直排列元素,使其不再重疊文本。
@Composable
fun MessageCard(msg: Message) {
Column {
Text(text = msg.author)
Text(text = msg.body)
}
}
同樣的,可以使用Row函數(shù)水平排列元素,而使用Box函數(shù)可以堆疊元素。
添加圖片元素
使用Resource Manager從照片庫中導(dǎo)入圖片,修改MessageCard:
@Composable
fun MessageCard(msg: Message) {
//使用Row方法,水平排列圖片和消息
Row {
Image(
painter = painterResource(R.drawable.profile_picture),
contentDescription = "Contact profile picture",
)
Column {
Text(text = msg.author)
Text(text = msg.body)
}
}
}
配置布局(Modifier)
使用修飾符(Modifier)實(shí)現(xiàn)。
Compose中的每一個(gè)組件都具有Modifier屬性,通過他我們可以設(shè)置組件的大小、間距、外觀,甚至添加互動(dòng)事件,如點(diǎn)擊、觸摸事件。
@Composable
fun MessageCard(msg: Message) {
//在消息周圍添加8dp的距離
Row(modifier = Modifier.padding(all = 8.dp)) {
Image(
painter = painterResource(R.drawable.profile_picture),
contentDescription = "Contact profile picture",
modifier = Modifier
//設(shè)置圖片大小
.size(40.dp)
//將圖片修剪為圓形
.clip(CircleShape)
)
//在圖片和消息之間添加一個(gè)水平的空間(Spacer),間距為8dp
Spacer(modifier = Modifier.width(8.dp))
Column {
Text(text = msg.author)
// 在發(fā)送者和消息內(nèi)容之間添加一個(gè)垂直的空間
Spacer(modifier = Modifier.height(4.dp))
Text(text = msg.body)
}
}
}
Material Design
Compose 旨在支持 Material Design 原則。它的許多界面元素都原生支持 Material Design。
使用
Jetpack Compose 原生提供 Material Design 3 及其界面元素的實(shí)現(xiàn)。我們使用 Material Design 樣式改進(jìn)MessageCard可組合項(xiàng)的外觀。
在創(chuàng)建ComposeTutorial項(xiàng)目時(shí),會(huì)同時(shí)創(chuàng)建一個(gè)名為“ComposeTutorialTheme”的Material主題,和一個(gè)來自Material Design 3的“Surface”。我們將用到這兩位來封裝MessageCard函數(shù)。
Material Design是圍繞Color、Typography、Shape來構(gòu)建的,我們將逐一添加這些元素。
修改MainActivity:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
//使用ComposeTutorialTheme和Surface封裝MessageCard函數(shù)
ComposeTutorialTheme {
//將給定的組件或布局填滿父容器的界面
Surface(modifier = Modifier.fillMaxSize()) {
MessageCard(Message("Android", "Jetpack Compose"))
}
}
}
}
}
@Preview
@Composable
fun PreviewMessageCard() {
//在@Preview中也要封裝,沿用應(yīng)用主題中定義的樣式,保持統(tǒng)一
ComposeTutorialTheme {
Surface {
MessageCard(
msg = Message("Lexi", "Take a look at Jetpack Compose, it's great!")
)
}
}
}
顏色
@Composable
fun MessageCard(msg: Message) {
Row(modifier = Modifier.padding(all = 8.dp)) {
Image(
painter = painterResource(R.drawable.profile_picture),
contentDescription = null,
modifier = Modifier
.size(40.dp)
.clip(CircleShape)
//為圖像增加一個(gè)圓框
.border(1.5.dp, MaterialTheme.colorScheme.primary, CircleShape)
)
Spacer(modifier = Modifier.width(8.dp))
Column {
Text(
text = msg.author,
//通過MaterialTheme.colorScheme,使用已封裝主題中的顏色設(shè)置樣式
color = MaterialTheme.colorScheme.secondary
)
Spacer(modifier = Modifier.height(4.dp))
Text(text = msg.body)
}
}
}
Typography(排版)
MaterialTheme?中提供了 Material Typography 樣式,只需將其添加到?Text?可組合項(xiàng)中即可。
@Composable
fun MessageCard(msg: Message) {
Row(modifier = Modifier.padding(all = 8.dp)) {
Image(
painter = painterResource(R.drawable.profile_picture),
contentDescription = null,
modifier = Modifier
.size(40.dp)
.clip(CircleShape)
.border(1.5.dp, MaterialTheme.colorScheme.primary, CircleShape)
)
Spacer(modifier = Modifier.width(8.dp))
Column {
Text(
text = msg.author,
color = MaterialTheme.colorScheme.secondary,
style = MaterialTheme.typography.titleSmall
)
Spacer(modifier = Modifier.height(4.dp))
Text(
text = msg.body,
style = MaterialTheme.typography.bodyMedium
)
}
}
}
Shape(形狀)
@Composable
fun MessageCard(msg: Message) {
Row(modifier = Modifier.padding(all = 8.dp)) {
Image(
painter = painterResource(R.drawable.profile_picture),
contentDescription = null,
modifier = Modifier
.size(40.dp)
.clip(CircleShape)
.border(1.5.dp, MaterialTheme.colorScheme.primary, CircleShape)
)
Spacer(modifier = Modifier.width(8.dp))
Column {
Text(
text = msg.author,
color = MaterialTheme.colorScheme.secondary,
style = MaterialTheme.typography.titleSmall
)
Spacer(modifier = Modifier.height(4.dp))
//將消息詳情封裝在Surface中,此時(shí)可自定義消息詳情的大小、形狀等布局
Surface(shape = MaterialTheme.shapes.medium, shadowElevation = 1.dp) {
Text(
text = msg.body,
modifier = Modifier.padding(all = 4.dp),
style = MaterialTheme.typography.bodyMedium
)
}
}
}
}
啟用深色主題
又稱夜間模式。由于支持Material Design,Jetpack Compose默認(rèn)能夠處理深色主題。
使用Material Design顏色、文本和背景時(shí),系統(tǒng)會(huì)自動(dòng)適應(yīng)深色背景。
//可以在文件中以單獨(dú)函數(shù)的形式創(chuàng)建多個(gè)預(yù)覽,也可以向同一個(gè)函數(shù)中添加多個(gè)注解
@Preview(name = "Light Mode")
@Preview(
uiMode = Configuration.UI_MODE_NIGHT_YES,
showBackground = true,
name = "Dark Mode"
)
@Composable
fun PreviewMessageCard() {
ComposeTutorialTheme {
Surface {
MessageCard(
msg = Message("Lexi", "Hey, take a look at Jetpack Compose, it's great!")
)
}
}
}
列表和動(dòng)畫
創(chuàng)建消息列表(LazyColumn、LazyRow)
LazyColumn、LazyRow是Compose常見的兩個(gè)組件,他們的優(yōu)點(diǎn)是可以延遲加載。他們只會(huì)加載當(dāng)前可見的列表項(xiàng),并在滾動(dòng)時(shí)動(dòng)態(tài)回收其他項(xiàng),這使得他們適用于展示大量數(shù)據(jù)或無限滾動(dòng)的列表。
在使用中,會(huì)包含一個(gè)items子項(xiàng)。他接受LIst作為參數(shù),并且其lambda會(huì)接收到參數(shù)。系統(tǒng)會(huì)針對(duì)提供的List的每個(gè)項(xiàng)調(diào)用此lambda。
@Composable
fun Conversation(messages: List
LazyColumn {
//items子項(xiàng)
items(messages) { message ->
MessageCard(message)
}
}
}
@Preview
@Composable
fun PreviewConversation() {
ComposeTutorialTheme {
Conversation(SampleData.conversationSample)
}
}
在展開消息時(shí)顯示動(dòng)畫效果
為了存儲(chǔ)某條消息是否已展開,我們使用remember和mutableStateOf函數(shù)。
可組合函數(shù)可以使用remember將本地狀態(tài)存儲(chǔ)到內(nèi)存中,并跟蹤傳遞給mutableStateOf的值的變化。而mutableStateOf函數(shù)可以在可組合函數(shù)內(nèi)部創(chuàng)建一個(gè)可變的狀態(tài),并將其與UI組件進(jìn)行綁定。當(dāng)狀態(tài)值發(fā)生變化時(shí),Compose會(huì)自動(dòng)重繪相關(guān)的組件。
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
ComposeTutorialTheme {
Conversation(SampleData.conversationSample)
}
}
}
}
@Composable
fun MessageCard(msg: Message) {
Row(modifier = Modifier.padding(all = 8.dp)) {
Image(
painter = painterResource(R.drawable.profile_picture),
contentDescription = null,
modifier = Modifier
.size(40.dp)
.clip(CircleShape)
.border(1.5.dp, MaterialTheme.colorScheme.primary, CircleShape)
)
Spacer(modifier = Modifier.width(8.dp))
// 在此變量中,跟蹤當(dāng)前消息是否展開
var isExpanded by remember { mutableStateOf(false) }
// 當(dāng)點(diǎn)擊該消息時(shí),改變展開狀態(tài)
Column(modifier = Modifier.clickable { isExpanded = !isExpanded }) {
Text(
text = msg.author,
color = MaterialTheme.colorScheme.secondary,
style = MaterialTheme.typography.titleSmall
)
Spacer(modifier = Modifier.height(4.dp))
Surface(
shape = MaterialTheme.shapes.medium,
shadowElevation = 1.dp,
) {
Text(
text = msg.body,
modifier = Modifier.padding(all = 4.dp),
// 若展開,全部顯示;不展開,最大顯示一行
maxLines = if (isExpanded) Int.MAX_VALUE else 1,
style = MaterialTheme.typography.bodyMedium
)
}
}
}
}
注:需要添加以下導(dǎo)入內(nèi)容才能正確使用 Kotlin 的委托屬性語法(by?關(guān)鍵字):import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
使用by關(guān)鍵字是避免每次都訪問value屬性的好方法。
同時(shí)需要注意的是,我們應(yīng)該只在可組合函數(shù)的作用域之外改變狀態(tài)。這是因?yàn)榭山M合項(xiàng)可以頻繁運(yùn)行、且以任何順序執(zhí)行。???????此處我們可以在clickable中修改isExpanded的值,是因?yàn)閏lickable不是可組合函數(shù)。
除了remember關(guān)鍵字,我們還可以使用rememberSaveable,它與前者類似,但存儲(chǔ)的值可以在重新創(chuàng)建activity和進(jìn)程后保存下來。需要注意的是,rememberSaveable適用于UI狀態(tài),如購物車的商品數(shù)量或選定的標(biāo)簽頁,但不適用于過渡動(dòng)畫狀態(tài)等。
同時(shí)我們可以加入顏色,在消息縮放時(shí)改變消息的顏色。但不能只是簡單的改變消息的背景顏色,我們應(yīng)當(dāng)加入動(dòng)畫,使得變化時(shí)逐步更改。
相同的,在點(diǎn)擊縮放時(shí),我們也可以加上動(dòng)畫,使得縮放更加順滑。
@Composable
fun MessageCard(msg: Message) {
Row(modifier = Modifier.padding(all = 8.dp)) {
Image(
painter = painterResource(R.drawable.profile_picture),
contentDescription = null,
modifier = Modifier
.size(40.dp)
.clip(CircleShape)
.border(1.5.dp, MaterialTheme.colorScheme.secondary, CircleShape)
)
Spacer(modifier = Modifier.width(8.dp))
var isExpanded by remember { mutableStateOf(false) }
// 該變量會(huì)逐步更新顏色,animateColorAsState函數(shù)實(shí)現(xiàn)顏色之間的過渡動(dòng)畫效果
val surfaceColor by animateColorAsState(
if (isExpanded) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.surface,
)
Column(modifier = Modifier.clickable { isExpanded = !isExpanded }) {
Text(
text = msg.author,
color = MaterialTheme.colorScheme.secondary,
style = MaterialTheme.typography.titleSmall
)
Spacer(modifier = Modifier.height(4.dp))
Surface(
shape = MaterialTheme.shapes.medium,
shadowElevation = 1.dp,
color = surfaceColor,
//加入animateContentSize,給縮放加入動(dòng)畫,更加順滑
modifier = Modifier.animateContentSize().padding(1.dp)
) {
Text(
text = msg.body,
modifier = Modifier.padding(all = 4.dp),
maxLines = if (isExpanded) Int.MAX_VALUE else 1,
style = MaterialTheme.typography.bodyMedium
)
}
}
}
}
柚子快報(bào)邀請(qǐng)碼778899分享:Android的Compose
推薦文章
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場。
轉(zhuǎn)載請(qǐng)注明,如有侵權(quán),聯(lián)系刪除。