Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> ระบบ >> Android

เชี่ยวชาญการจัดสไตล์ Jetpack Compose: คู่มือการทำ Theme สำหรับแอป Android

บทความนี้จะเรียนรู้การจัดสไตล์และทำ theme ให้แอปพลิเคชันใน Jetpack Compose

Compose เป็น UI framework ใหม่สำหรับ Android (รองรับ Desktop และ Web กำลังพัฒนา) แทนระบบ View แบบ XML เก่า

ขณะเขียนอยู่ใน beta release แต่ส่วนนี้คาดว่าไม่เปลี่ยนแปลงมากสำหรับ stable release

หัวข้อครอบคลุม:

  • สรุปวิธีเก่าแบบ XML
  • ย้ายจาก colors, themes, typography (font) แบบ XML ไป Kotlin Compose
  • ตั้งค่า light และ dark themes ในไม่กี่บรรทัด
  • ใช้ข้อมูลสไตล์ Kotlin ใหม่ใน composables
  • จัดสไตล์ Text Composables โดยเฉพาะ

ก่อนเริ่ม ต้องเข้าใจว่า composable คืออะไร ไม่จะอธิบายที่นี่ เพราะอธิบายไว้ในบทความอื่นแล้ว

ดูวิดีโอสรุปสั้นๆ

วิธีเก่าจัดสไตล์ Android Apps ด้วย XML Resources

ชอบแบ่งปันแรงจูงใจและประวัติเบื้องหลัง หากไม่สนใจ ข้ามไปส่วนปฏิบัติได้เลย

Android Resources

ระบบ Android app resources น่าชื่นชม แต่ทุก design decision มีข้อดีและข้อเสีย

ความท้าทายใหญ่คือ localized resources คือการสร้างแอปที่:

  • แสดงข้อความและกราฟิกหลายภาษาและอักษร
  • ดูสัดส่วนเหมาะสมกับ form factors หลากหลาย (dimensions, densities ฯลฯ)

Resource system ให้ที่สำหรับนักพัฒนาให้ localized resources ที่ platform เลือกใช้ตอน compile time ประหยัด boilerplate code

Feature หรือ Flaw?

แม้จะไม่อยากจัดการ boilerplate สำหรับ string resources เอง แต่ก็ไม่ชอบเขียน XML

มีเพียงไม่กี่สิ่งที่ชอบทำใน XML มากกว่า Kotlin หรือ Swift ที่ทันสมัยและขèvent

เหตุผลทางเทคนิค: XML resources ไม่ใช่ ideal เสมอไป

เพื่อรวม XML-based resources เข้า JVM-based app code ต้องมี layers of translation (compilation) และ platform bridges (APIs) สร้างความยากลำบากให้ทั้ง platform และ app developers

ปัญหาสองประการที่พบ:

  • ต้องการเข้าถึง resource ที่ไม่ต้องการ tight coupling กับ platform APIs
  • ต้องเขียน boilerplate code มากแค่เปลี่ยนลักษณะ View (override resource styles/themes)

Root problem คือ tight coupling กับ View system และ Android resource system (ซึ่ง coupled กันเอง)

Platform developers ต้อง build บน codebase เก่าและใหญ่ พร้อมรองรับ Android OS เก่า งานที่ขอบคุณไม่ได้

ผลกระทบต่อ app developers คือ boilerplate code มาก, workarounds แบบแฮ็ก สำหรับสิ่งที่ควรเป็น one-liners API หลักคือ Context ซึ่งไม่ควร leak memory

เข้าสู่ Jetpack Compose.

ตั้งค่า Themes, Colors, และ Fonts ด้วย Jetpack Compose

หลังทบทวนระบบเก่า มาสำรวจวิธีสวยง่ายและเรียบง่ายกว่า เนื่องจากทำงานใน Kotlin หมายความว่า:

เราและ platform developers ไม่ถูกผูกมัดด้วย translation (compilation) และ API bridges (Android R class และ Context) ระหว่าง XML และ JVM

หมายถึง boilerplate code น้อยลงมาก และ control มากขึ้นตอน runtime

สำหรับส่วนปฏิบัติ แนะนำทำตามลำดับที่อธิบาย โครงสร้างตามลำดับที่ผมเขียนโค้ดในแอปใหม่

แทนที่ Colors.xml Resources ด้วย Kotlin Compose

หากยังไม่เลือก color scheme แนะนำใช้ทรัพยากรจาก Material Design website:

  • Color palettes
  • Color tool

หากวางแผนรองรับ light/dark themes เลือก color scheme ที่รองรับข้อความสีขาวและสีดำ

เชี่ยวชาญการจัดสไตล์ Jetpack Compose: คู่มือการทำ Theme สำหรับแอป Android
ตัวอย่าง light และ dark color schemes

สร้างไฟล์ Color.kt (ชื่อไม่สำคัญ) เติมด้วย immutable values:

import androidx.compose.ui.graphics.Color val primaryGreen = Color(0XFF00bc00) val primaryCharcoal = Color(0xFF2b2b2b) val accentAmber = Color(0xFFffe400) val textColorLight = Color(0xDCFFFFFF) val textColorDark = Color(0xFFf3f3f3) val gridLineColorLight = Color.Black //...

ใช้ค่า predefined เช่น Color.Black หรือ ARGB Hex ของตัวเอง

ARGB Hex คืออะไร? "0XFF00bc00" แปลว่า:

  • 0x บอก compiler ว่าเป็นเลขฐานสิบหก
  • FF หรือ DC แทน Transparency/Alpha ใน Hex
  • คู่ตัวอักษร 6 ตัวที่เหลือแทน Red, Green, Blue

เพิ่ม Fonts และแทนที่ attribute fontFamily

Typography (fonts) จัดการง่าย Kotlin default arguments มีประโยชน์

สร้างไฟล์ Type.kt สร้าง class Typography:

val typography = Typography( body1 = TextStyle( fontFamily = FontFamily.Default, fontWeight = FontWeight.Normal, fontSize = 16.sp ), button = TextStyle( fontFamily = FontFamily.Default, fontWeight = FontWeight.Bold, fontSize = 32.sp ), caption = TextStyle( fontFamily = FontFamily.Default, fontWeight = FontWeight.Normal, fontSize = 12.sp ) ) //...

และ TextStyle classes:

//... val mainTitle = TextStyle( fontFamily = FontFamily.Default, fontWeight = FontWeight.Light, fontSize = 48.sp, textAlign = TextAlign.Center ) fun dropdownText(color: Color) = TextStyle( fontFamily = FontFamily.Default, fontWeight = FontWeight.Normal, fontSize = 32.sp, textAlign = TextAlign.Center, color = color ) //...

ให้ public functions หรือ values (ไม่แนะนำ var) ขึ้นอยู่กับ preference และ requirements

สร้าง App Theme ใน Jetpack Compose

สิ่งสุดท้ายก่อนใช้ theme ใน composables คือ MaterialTheme @Composable ผมมีพร้อม light/dark color palettes ในไฟล์ GraphSudokuTheme:

import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.material.MaterialTheme import androidx.compose.material.darkColors import androidx.compose.material.lightColors import androidx.compose.runtime.Composable import androidx.compose.ui.graphics.Color private val LightColorPalette = lightColors( primary = primaryGreen, secondary = textColorLight, surface = lightGrey, primaryVariant = gridLineColorLight, onPrimary = accentAmber, onSurface = accentAmber ) private val DarkColorPalette = darkColors( // main background color primary = primaryCharcoal, // used for text color secondary = textColorDark, // background of sudoku board surface = lightGreyAlpha, // grid lines of sudoku board primaryVariant = gridLineColorLight, onPrimary = accentAmber, onSurface = accentAmber ) @Composable fun GraphSudokuTheme( darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit ) { MaterialTheme( colors = if (darkTheme) DarkColorPalette else LightColorPalette, typography = typography, shapes = shapes, content = content ) } 

เนื่องจากคุณคุ้นเคย composable แล้ว (เตือนไว้) สิ่งใหม่คือ darkTheme: Boolean = isSystemInDarkTheme()

isSystemInDarkTheme() สอบถามอุปกรณ์ Android ที่รองรับ เกี่ยวกับความชอบ light/dark theme ของผู้ใช้

คืนค่า boolean ใช้ใน Ternary Assignment เช่น colors = if (darkTheme) DarkColorPalette else LightColorPalette

แค่นี้ก็จบ Colors, Fonts, และสอง Themes ในไม่กี่นาที

ใช้ Theme ใน Compose

ถึงเวลาใช้ Theme ในแอป ในแอปนี้มี 2 หน้าจอหลัก ใช้ Activity เป็น container สำหรับ composables:

class NewGameActivity : AppCompatActivity(), NewGameContainer { //... override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) //... setContent { GraphSudokuTheme { NewGameScreen( onEventHandler = logic::onEvent, viewModel ) } } //... }

ที่เรียก setContent {} แนะนำให้วาง Theme composable ทันที ทำให้ style information cascade/inherit ไปยัง composables 巢ที่ซ้อนกัน

เกือบเสร็จแล้ว!

Override Styles และ Themes

พยายามใส่สีที่ต้องการใน light/dark palettes ตอนเรียก MaterialTheme.colors.<Color> ระบบจะจัดการ conditional logic เลือก palette ให้อัตโนมัติ:

@Composable fun NewGameContent( onEventHandler: (NewGameEvent) -> Unit, viewModel: NewGameViewModel ) { Surface( Modifier .wrapContentHeight() .fillMaxWidth() ) { ConstraintLayout(Modifier.background(MaterialTheme.colors.primary)) { //... } //... } } 

แต่บางครั้งเขียน conditional logic เองดีกว่า... หรือแค่ขี้เกียจ Compose ให้ configurations มากมายเป็น properties:

@Composable fun DoneIcon(onEventHandler: (NewGameEvent) -> Unit) { Icon( imageVector = Icons.Filled.Done, tint = if (MaterialTheme.colors.isLight) textColorLight else textColorDark, contentDescription = null, modifier = Modifier .clickable( //... ) ) }

MaterialTheme.Colors.isLight คืนค่า boolean บ่งบอก mode ใช้ Ternary Assignment อีกครั้ง

จัดสไตล์ Text Composable

ตั้งค่า argument style ให้เท่ากับ text style ของคุณ (จาก MaterialTheme หรือ Type.kt):

Text( text = stat.toTime(), style = statsLabel.copy( color = if (isZero) Color.White else MaterialTheme.colors.onPrimary, fontWeight = FontWeight.Normal ), modifier = Modifier .wrapContentSize() .padding(end = 2.dp, bottom = 4.dp), textAlign = TextAlign.End )

TextStyle มี copy function พร้อมใช้ หากต้องการ override

เสร็จแล้ว! ตอนนี้คุณรู้จักจัดสไตล์และทำ theme แอปด้วย Jetpack Compose ขอบคุณที่อ่าน :)

Social

หาผมได้ที่ Instagram และ Twitter

บทช่วยสอนและคอร์สของผม

https://youtube.com/wiseass     https://www.freecodecamp.org/news/author/ryan-michael-kay/ https://skl.sh/35IdKsj (introduction to Android with Android Studio)