1.概述
在之前的博客中,我已經(jīng)介紹了Compose 的基礎(chǔ)UI和布局組件,現(xiàn)在我們就利用這些基礎(chǔ)UI和布局組件去做一個(gè)實(shí)戰(zhàn)項(xiàng)目。Bloom是Google提供的一個(gè)假想產(chǎn)品,我們可以作為練手項(xiàng)目使用,這個(gè)產(chǎn)品的詳細(xì)UI設(shè)計(jì)稿大家可以自行去百度下,個(gè)人決定這里主要是熟練去使用Compose UI,不必要糾結(jié)設(shè)計(jì)稿,文末我會(huì)貼出項(xiàng)目的github地址,供讀者參考。
2.效果圖展示
2.1 亮色主題效果:
2.2 深色主題效果
3.項(xiàng)目結(jié)構(gòu)解析
項(xiàng)目的大致結(jié)構(gòu)就是一個(gè)簡(jiǎn)單的Android項(xiàng)目,如下圖所示:
在上圖中是這個(gè)項(xiàng)目的結(jié)構(gòu)圖,我們主要介紹的是ui下theme包類的幾個(gè)Kotlin配置類,當(dāng)我們創(chuàng)建一個(gè)新項(xiàng)目是,Compose會(huì)在項(xiàng)目中生產(chǎn)
ui/theme
目錄,包含四個(gè)文件,分別是Color.kt、Shape.kt、Theme.kt、Type.kt
;官方建議我沒(méi)將顏色、字體、形狀等配置信息放到這四個(gè)配置文件中,便于統(tǒng)一維護(hù)管理
3.1 顏色配置Color.kt
配置的顏色信息是一個(gè)四字節(jié)的Int整形數(shù)字,每個(gè)字節(jié)保存著ARGB
對(duì)應(yīng)的信息。例如Pink-100
對(duì)應(yīng)的值是0xFFF1F1
,這里表示的只是低位RGB
三種顏色對(duì)應(yīng)的信息,如果希望添加透明度,那么就在最高位添加一個(gè)字節(jié)表示透明度,比如希望透明度是100%
,那么就添加一個(gè)0xFF,最終的顏色值是0xFFFFF1F1
。0xFF
對(duì)應(yīng)的十進(jìn)制是255
,表示100%
的透明度,如果要表示85%
的透明度,則255x85%
對(duì)應(yīng)的16進(jìn)制是0xD8
,所以0xFFFFF1F1
對(duì)應(yīng)的透明度為85%的顏色值為0xD8FFF1F1
。
在本項(xiàng)目中用到的顏色值定義如下:
val white = Color(0xFFFFFFFF)
val white150 = Color(0x26FFFFFF)
val white850 = Color(0xD9FFFFFF)
val pink100 = Color(0xFFFFF1F1)
val pink900 = Color(0xFF3F2C2C)
val green300 = Color(0xFFB8C9B8)
val green900 = Color(0xFF2D3B2D)
3.2 形狀配置Shape.kt
如今的主流APP中我們都可以看到很多的UI控件都使用了圓角,圓角的大小在傳統(tǒng)的View開(kāi)發(fā)時(shí)通常都是在drawable中新建一個(gè)xml定義按鈕的圓角樣式,這樣很不方便,因?yàn)槿绻覀冎皇窍敫淖儓A角的大小時(shí),就需要我們?cè)俣x一個(gè)xml樣式,但是使用Shape.kt后就不存在這個(gè)問(wèn)題,因?yàn)閳A角大小的配置放到了一個(gè)統(tǒng)一的地方。使用的時(shí)候直接引用就行了
本項(xiàng)目中的圓角大小定義:
val Shapes = Shapes(
small = RoundedCornerShape(4.dp),
medium = RoundedCornerShape(4.dp),
large = RoundedCornerShape(0.dp)
)
3.3 主題配置Theme.kt
主題的配置相對(duì)要麻煩一些,由于篇幅原因,這里不多介紹,在后面會(huì)有專門的一篇博客對(duì)主題進(jìn)行介紹,這里我們就先按照我提供的主題配置上就行了。本項(xiàng)目的主題配置如下:
private val BloomDarkColorPalette = darkColors(
primary = white,
secondary = green300,
background = green900,
surface = white150,
onPrimary = white850,
onSecondary = green900,
onBackground = pink900,
onSurface = white850,
)
private val BloomLightColorPalette = lightColors(
primary = pink900,
secondary = pink900,
background = pink100,
surface = white850,
onPrimary = pink100,
onSecondary = pink100,
onBackground = pink900,
onSurface = white150
)
open class WelcomePageAssets(var background:Int,var illos:Int,var logo:Int)
//亮色主題資源
object LightWelcomeAssets : WelcomePageAssets(
background = R.drawable.ic_light_welcome_bg,
illos = R.drawable.ic_light_welcome_illos,
logo = R.drawable.ic_light_logo
)
// 暗色主提資源
object DarkWelcomeAssets : WelcomePageAssets(
background = R.drawable.ic_dark_welcome_bg,
illos = R.drawable.ic_dark_welcome_illos,
logo = R.drawable.ic_dark_logo
)
internal var LocalWelcomeAssets = staticCompositionLocalOf { LightWelcomeAssets as WelcomePageAssets }
val welcomeAssets
@Composable
@ReadOnlyComposable
get() = LocalWelcomeAssets.current
enum class BloomTheme{
LIGHT,DARK
}
@Composable
fun GoogleBloomTheme(theme:BloomTheme = BloomTheme.LIGHT,content:@Composable ()->Unit){
val welcomeAssets = if(theme == BloomTheme.DARK) DarkWelcomeAssets else LightWelcomeAssets
CompositionLocalProvider(
LocalWelcomeAssets provides welcomeAssets
) {
MaterialTheme(colors = if (theme == BloomTheme.DARK)
BloomDarkColorPalette else BloomLightColorPalette,
typography = bloomTypoGraphy,
shapes = shapes,
content = content,
)
}
}
3.4 字體配置 Type.kt
我們想用的字體可以在Type.kt中配置,如果要引入新字體,可以將下載下來(lái)的字體文件放到res/font目錄下,如果沒(méi)有這個(gè)目錄可以自己建一個(gè),然后使用如下的方式引入字體
val nunitoSansFamily = FontFamily(
Font(R.font.nunitosans_light, FontWeight.Light),
Font(R.font.nunitosans_semibold, FontWeight.SemiBold),
Font(R.font.nunitosans_bold, FontWeight.Bold)
)
本項(xiàng)目的字體配置
// Set of Material typography styles to start with
val Typography = Typography(
body1 = TextStyle(
fontFamily = FontFamily.Default,
fontWeight = FontWeight.Normal,
fontSize = 16.sp
)
)
val nunitoSansFamily = FontFamily(
Font(R.font.nunitosans_light, FontWeight.Light),
Font(R.font.nunitosans_semibold, FontWeight.SemiBold),
Font(R.font.nunitosans_bold, FontWeight.Bold)
)
val bloomTypoGraphy = Typography(
h1 = TextStyle(
fontSize = 18.sp,
fontFamily = nunitoSansFamily,
fontWeight = FontWeight.Bold
),
h2 = TextStyle(
fontSize = 14.sp,
letterSpacing = 0.15.sp,
fontFamily = nunitoSansFamily,
fontWeight = FontWeight.Bold
),
subtitle1 = TextStyle(
fontSize = 16.sp,
fontFamily = nunitoSansFamily,
fontWeight = FontWeight.Light
),
body1 = TextStyle(
fontSize = 14.sp,
fontFamily = nunitoSansFamily,
fontWeight = FontWeight.Light
),
body2 = TextStyle(
fontSize = 12.sp,
fontFamily = nunitoSansFamily,
fontWeight = FontWeight.Light
),
button = TextStyle(
fontSize = 14.sp,
letterSpacing = 1.sp,
fontFamily = nunitoSansFamily,
fontWeight = FontWeight.SemiBold,
color = white
),
caption = TextStyle(
fontSize = 12.sp,
fontFamily = nunitoSansFamily,
fontWeight = FontWeight.SemiBold
)
)
4.沉浸式狀態(tài)欄適配
所謂沉浸式主題欄適配就是指手機(jī)狀態(tài)欄的顏色和我們的應(yīng)用背景色相同,看起來(lái)感覺(jué)狀態(tài)欄和我們的頁(yè)面就像是一體的一樣,有的做法是給標(biāo)題欄設(shè)置一個(gè)透明的顏色,而本項(xiàng)目中使用的辦法是將標(biāo)題欄的顏色設(shè)置成和頁(yè)面的背景色相同就可以了。設(shè)置標(biāo)題欄的顏色需要用到一個(gè)庫(kù):
implementation "com.google.accompanist:accompanist-systemuicontroller:0.31.0-alpha"
引入這個(gè)庫(kù)后,使用下面的方法設(shè)置狀態(tài)欄的顏色:
@Composable
fun TransparentSystemBars(color: Color) {
val systemUiController = rememberSystemUiController()
val useDarkIcons = !isSystemInDarkTheme()
SideEffect {
systemUiController.setSystemBarsColor(
color = color,
darkIcons = useDarkIcons,
isNavigationBarContrastEnforced = false,
)
}
}
然后在對(duì)應(yīng)的Activity中設(shè)置好主題,代碼如下:
class MainActivity : ComponentActivity() {
private lateinit var theme: BloomTheme
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
actionBar?.apply { hide() }
setContent {
theme = if(isSystemInDarkTheme()){
BloomTheme.DARK
}else {
BloomTheme.LIGHT
}
GoogleBloomTheme(theme) {
val color = MaterialTheme.colors.background
TransparentSystemBars(color)
// 展示界面,例如本項(xiàng)目中展示歡迎頁(yè):WelcomePage()
}
}
}
}
如上面代碼所示,我們根據(jù)當(dāng)前的系統(tǒng)是否是深色主題判斷使用的主題樣式,然后把應(yīng)用的當(dāng)前的背景色傳給設(shè)置狀態(tài)欄顏色的方法,其他頁(yè)面也是相同的做法。
5.UI界面分解及實(shí)現(xiàn)
首先我們可以先看下歡迎頁(yè):
我們可以將這個(gè)頁(yè)面看成是背景加上內(nèi)容,然后我們對(duì)顯示的內(nèi)容劃分下,如下所示:
根據(jù)前面所學(xué)的知識(shí),我們可以使用一個(gè)Column組件搞定這個(gè)頁(yè)面的內(nèi)容布局。而背景和內(nèi)容的結(jié)合,我們可以使用Box組件,代碼如下:
5.1 歡迎頁(yè)背景+內(nèi)容
使用Box組件將內(nèi)容和背景融合到一起,內(nèi)容我們可以抽成一個(gè)組件繼續(xù)去劃分實(shí)現(xiàn)
@Composable
fun WelcomePage(){
Box(modifier = Modifier
.fillMaxSize()
.background(MaterialTheme.colors.background)
){
Image(
painter = rememberVectorPainter(
image = ImageVector.vectorResource(id = welcomeAssets.background)
),
contentDescription = "welcome page",
modifier = Modifier.fillMaxSize()
)
WelcomeContent()
}
}
5.2 歡迎頁(yè)內(nèi)容組件實(shí)現(xiàn)
內(nèi)容組件又包括了一張葉子樣式的圖片,標(biāo)題和兩個(gè)按鈕,我們可以分別抽成組件
@Composable
fun WelcomeContent(){
Column(modifier = Modifier.fillMaxSize()) {
Spacer(modifier = Modifier.height(72.dp))
LeafImage()
Spacer(modifier = Modifier.height(48.dp))
WelcomeTitle()
Spacer(modifier = Modifier.height(40.dp))
WelcomeButtons()
}
}
5.3 歡迎頁(yè)內(nèi)容的各個(gè)小組件實(shí)現(xiàn)
上面的WelcomeContent()函數(shù)將要顯示的內(nèi)容拆分成了三個(gè)更小的組件,實(shí)現(xiàn)如下所示:
@Composable
fun LeafImage(){
Image(painter = rememberVectorPainter(
image = ImageVector.vectorResource(id = welcomeAssets.illos)
),
contentDescription = "welcome leaf image",
modifier = Modifier
.wrapContentSize()
.padding(start = 88.dp))
}
@Composable
fun WelcomeTitle(){
Column(horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.fillMaxWidth()) {
Image(painter = rememberVectorPainter(
image = ImageVector.vectorResource(id = welcomeAssets.logo)),
contentDescription = "welcome logo",
modifier = Modifier
.wrapContentSize()
.height(32.dp))
Box(modifier = Modifier
.fillMaxWidth()
.height(32.dp),
contentAlignment = Alignment.BottomCenter){
Text(text = "Beautiful home garden solutions",
textAlign = TextAlign.Center,
style = MaterialTheme.typography.subtitle1,
color = MaterialTheme.colors.primary)
}
}
}
@Composable
fun WelcomeButtons(){
Column(horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.fillMaxWidth()) {
Button(onClick = { /*TODO*/ },
modifier = Modifier
.height(48.dp)
.padding(horizontal = 16.dp)
.fillMaxWidth()
.clip(MaterialTheme.shapes.medium),
colors = ButtonDefaults.buttonColors(backgroundColor = MaterialTheme.colors.secondary)
) {
Text(
text = "Create account",
style = MaterialTheme.typography.button,
color = MaterialTheme.colors.onSecondary
)
}
Spacer(modifier = Modifier.height(24.dp))
TextButton(onClick = { /*TODO*/ }) {
Text(
text = "Log in",
style = MaterialTheme.typography.button,
color = MaterialTheme.colors.primary )
}
}
}
至此,一個(gè)使用Compose實(shí)現(xiàn)的歡迎頁(yè)就完成了。是不是很簡(jiǎn)單,代碼也很少。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-491882.html
6.代碼地址
建議讀者將源碼下載下來(lái),跟著敲一遍,不懂的可以查官網(wǎng),百度下,主要是為了熟悉如何使用Compose的開(kāi)發(fā)。有問(wèn)題也可以在評(píng)論區(qū)一起交流。
源碼地址文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-491882.html
到了這里,關(guān)于Android Compose UI實(shí)戰(zhàn)練手----Google Bloom歡迎頁(yè)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!