本文同步发表于我的微信公众号,在微信搜索
OpenCV or Android
即可关注。
前言
最近Android官方发起了Jetpack Compose的推广活动:Jetpack Compose
开发者挑战赛。活动时间一个月,每周一题,广大开发者根据官方需求,Clone官方模板工程并使用Jetpack Compose
技术结题后按要求提交,即可参与活动。上周完成了第一题,今天第二周的题目已经出来了,感兴趣的同学可以参与下。
环境
- 活动地址:https://developer.android.google.cn/dev-challenge
- 官方教程:https://developer.android.google.cn/jetpack/compose/documentation
- Github模板:https://github.com/android/android-dev-challenge-compose
- Android Studio (Canary build):https://developer.android.com/studio/preview
学习任何技术,首先拜读官文,无一例外。
第一周
题目:小狗领养应用
要求:包含显示小狗列表的概览画面,以及显示每只小狗具体情况的详细信息画面。
知识点:
- 基础控件:Column、Modifier、Card、Box、Text、Icon、Image、IconButton、Spacer等
- 控件修饰:Modifier
- 可变状态:mutableStateOf
定义数据
// 狗狗实体
data class Dog(val name: String, val avatar: Int, val desc: String)
// 狗狗列表
object DogPool {
val Dogs = listOf(
Dog(getRandomString(6), getRandomAvatar(), getRandomString(100)),
Dog(getRandomString(6), getRandomAvatar(), getRandomString(100)),
Dog(getRandomString(6), getRandomAvatar(), getRandomString(100)),
Dog(getRandomString(6), getRandomAvatar(), getRandomString(100)),
Dog(getRandomString(6), getRandomAvatar(), getRandomString(100)),
Dog(getRandomString(6), getRandomAvatar(), getRandomString(100)),
)
}
// 狗狗头像素材
val avatars = listOf(
R.drawable.dog_one,
R.drawable.dog_two,
R.drawable.dog_three,
R.drawable.dog_four,
R.drawable.dog_five,
R.drawable.dog_six
)
// 随机产生狗狗头像
fun getRandomAvatar(): Int {
return avatars[Random.nextInt(0, 5)]
}
// 随机生成固定长度字符串
fun getRandomString(length: Int): String {
val allowedChars = "ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz"
return (1..length)
.map { allowedChars.random() }
.joinToString("")
}
列表界面
使用Column
展示一个纵向列表,使用Modifier
调整布局元素的各种属性。
Column(modifier = Modifier.verticalScroll(rememberScrollState())) {
Spacer(modifier = Modifier.size(16.dp))
DogPool.Dogs.forEach {
Box(Modifier.padding(8.dp)) {
DogView(
dog = it,
modifier = Modifier
.fillMaxWidth()
.clickable { selectedDog = it }
)
}
}
}
列表项
@Composable
fun DogView(dog: Dog, modifier: Modifier = Modifier) {
Card(modifier, shape = RoundedCornerShape(26.dp)) {
Box {
Image(
painterResource(dog.avatar),
null,
modifier = Modifier.fillMaxWidth(),
contentScale = ContentScale.FillWidth
)
Box(
modifier = Modifier
.align(Alignment.BottomStart)
.background(
Brush.verticalGradient(
listOf(
Color.Transparent,
MaterialTheme.colors.onSurface
)
)
)
.fillMaxWidth()
.padding(26.dp)
) {
Text(
text = dog.name,
style = MaterialTheme.typography.h5,
color = MaterialTheme.colors.surface
)
}
}
}
}
详情界面
@Composable
fun DogDetails(dog: Dog) {
val context = LocalContext.current as? Activity
val scrollState = rememberScrollState()
// Calculate the offset of the background image to make it scroll with a parallax effect
val imageOffset = (-scrollState.value * 0.2f).dp
// Calculate the alpha used in the background of the back arrow
val iconBackgroundAlpha =
((scrollState.value / START_TOP_PADDING.toFloat()) * 0.2f).coerceAtMost(0.2f)
Box {
Image(
painter = painterResource(id = dog.avatar),
contentDescription = null,
contentScale = ContentScale.FillWidth,
modifier = Modifier
.offset(y = imageOffset)
.height(200.dp)
.fillMaxWidth()
)
Column(
Modifier
.verticalScroll(scrollState)
.padding(top = START_TOP_PADDING.dp)
.background(
MaterialTheme.colors.surface,
RoundedCornerShape(topStart = 3.dp, topEnd = 20.dp)
)
.fillMaxHeight()
.fillMaxWidth()
.padding(all = 32.dp)
) {
Text("Hello I Am", style = MaterialTheme.typography.h6)
Spacer(Modifier.size(10.dp))
Text(text = dog.name, style = MaterialTheme.typography.h3)
Spacer(Modifier.size(16.dp))
Spacer(modifier = Modifier.size(16.dp))
Text(text = dog.desc)
}
IconButton(
onClick = { context?.onBackPressed() },
modifier = Modifier
.padding(8.dp)
.background(Color.Black.copy(alpha = iconBackgroundAlpha), shape = CircleShape)
) {
Icon(
painter = painterResource(id = R.drawable.ic_arrow_back),
contentDescription = null,
modifier = Modifier
.size(32.dp),
tint = Color.White
)
}
}
}
代码检查
./gradlew app:spotlessApply
针对Wildcard import
错误,进行如下配置后删除对应以*
号形式引入的包,重新执行引入操作。