android -------- Jetpack Compose基础使用
Posted 切切歆语
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了android -------- Jetpack Compose基础使用相关的知识,希望对你有一定的参考价值。
前面学习了一哈 Jetpack Compose 这玩意,分享一哈 Compose 中布局的目标 布局系统的 Jetpack Compose 实现有两个主要目标:一是实现高性能,二是让开发者能够轻松编写自定义布局。 在 Compose 中,通过避免多次测量布局子级可实现高性能。
图1:
class MainActivity : ComponentActivity()
override fun onCreate(savedInstanceState: Bundle?)
super.onCreate(savedInstanceState)
setContent
JetComeposeTheme
Surface(color = MaterialTheme.colors.background)
//Greeting("android1")
Test()
// UserCard()
@Composable
fun Greeting(name: String)
Text(text = "Hello $name!")
@Preview(showBackground = true)
@Composable
fun DefaultPreview()
JetComeposeTheme
Greeting("Android")
@Composable
fun GreetingColor(name: String)
Surface(color = Color.Yellow)
Text(text = "Hello $name !")
@Composable
fun Test()
Column(modifier = Modifier.padding(16.dp))
Image(
painter = painterResource(id = R.drawable.header),
contentDescription = null,
modifier = Modifier
.height(180.dp)
.fillMaxWidth()
.clip(shape = RoundedCornerShape(4.dp)),
contentScale = ContentScale.Crop
)
Spacer(modifier = 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(
"Compose Test",
style = typography.body2
)
Text("zhangqie 2021", style = typography.body2)
Spacer(modifier = Modifier.height(18.dp))
Row(verticalAlignment = Alignment.CenterVertically)
Image(
painter = painterResource(id = R.mipmap.logo_round),
contentDescription = "头像",
modifier = Modifier
.requiredSize(65.dp)
.height(56.dp)
)
Spacer(modifier = Modifier.width(15.dp))
Column
Text(text = "我是名字")
Text(text = "我是简介")
图2:
class Demo2 : AppCompatActivity()
override fun onCreate(savedInstanceState: Bundle?)
super.onCreate(savedInstanceState)
setContent
AnimationCodelabTheme
Home()
private enum class TabPage
Home, Work
@Composable
fun Home()
// String resources.
val allTasks = stringArrayResource(R.array.tasks)
val allTopics = stringArrayResource(R.array.topics).toList()
// The currently selected tab.
var tabPage by remember mutableStateOf(TabPage.Home)
// True if the whether data is currently loading.
var weatherLoading by remember mutableStateOf(false)
// Holds all the tasks currently shown on the task list.
val tasks = remember mutableStateListOf(*allTasks)
// Holds the topic that is currently expanded to show its body.
var expandedTopic by remember mutableStateOf<String?>(null)
// True if the message about the edit feature is shown.
var editMessageShown by remember mutableStateOf(false)
// Simulates loading weather data. This takes 3 seconds.
suspend fun loadWeather()
if (!weatherLoading)
weatherLoading = true
delay(3000L)
weatherLoading = false
// Shows the message about edit feature.
suspend fun showEditMessage()
if (!editMessageShown)
editMessageShown = true
delay(3000L)
editMessageShown = false
// Load the weather at the initial composition.
LaunchedEffect(Unit)
loadWeather()
val lazyListState = rememberLazyListState()
// The background color. The value is changed by the current tab.
// TODO 1: Animate this color change.
val backgroundColor = if (tabPage == TabPage.Home) Purple100 else Green300
// The coroutine scope for event handlers calling suspend functions.
val coroutineScope = rememberCoroutineScope()
Scaffold(
topBar =
HomeTabBar(
backgroundColor = backgroundColor,
tabPage = tabPage,
onTabSelected = tabPage = it
)
,
backgroundColor = backgroundColor,
floatingActionButton =
HomeFloatingActionButton(
extended = lazyListState.isScrollingUp(),
onClick =
coroutineScope.launch
showEditMessage()
)
)
LazyColumn(
contentPadding = PaddingValues(horizontal = 16.dp, vertical = 32.dp),
state = lazyListState
)
// Weather
item Header(title = stringResource(R.string.weather))
item Spacer(modifier = Modifier.height(16.dp))
item
Surface(
modifier = Modifier.fillMaxWidth(),
elevation = 2.dp
)
if (weatherLoading)
LoadingRow()
else
WeatherRow(onRefresh =
coroutineScope.launch
loadWeather()
)
item Spacer(modifier = Modifier.height(32.dp))
// Topics
item Header(title = stringResource(R.string.topics))
item Spacer(modifier = Modifier.height(16.dp))
items(allTopics) topic ->
TopicRow(
topic = topic,
expanded = expandedTopic == topic,
onClick =
expandedTopic = if (expandedTopic == topic) null else topic
)
item Spacer(modifier = Modifier.height(32.dp))
// Tasks
item Header(title = stringResource(R.string.tasks))
item Spacer(modifier = Modifier.height(16.dp))
if (tasks.isEmpty())
item
TextButton(onClick = tasks.clear(); tasks.addAll(allTasks) )
Text(stringResource(R.string.add_tasks))
items(count = tasks.size) i ->
val task = tasks.getOrNull(i)
if (task != null)
key(task)
TaskRow(
task = task,
onRemove = tasks.remove(task)
)
EditMessage(editMessageShown)
/**
* Shows the floating action button.
*
* @param extended Whether the tab should be shown in its expanded state.
*/
// AnimatedVisibility is currently an experimental API in Compose Animation.
@OptIn(ExperimentalAnimationApi::class)
@Composable
private fun HomeFloatingActionButton(
extended: Boolean,
onClick: () -> Unit
)
// Use `FloatingActionButton` rather than `ExtendedFloatingActionButton` for full control on
// how it should animate.
FloatingActionButton(onClick = onClick)
Row(
modifier = Modifier.padding(horizontal = 16.dp)
)
Icon(
imageVector = Icons.Default.Edit,
contentDescription = null
)
// Toggle the visibility of the content with animation.
// TODO 2-1: Animate this visibility change.
if (extended)
Text(
text = stringResource(R.string.edit),
modifier = Modifier
.padding(start = 8.dp, top = 3.dp)
)
/**
* Shows a message that the edit feature is not available.
*/
@OptIn(ExperimentalAnimationApi::class)
@Composable
private fun EditMessage(shown: Boolean)
AnimatedVisibility(
visible = shown
)
Surface(
modifier = Modifier.fillMaxWidth(),
color = MaterialTheme.colors.secondary,
elevation = 4.dp
)
Text(
text = stringResource(R.string.edit_message),
modifier = Modifier.padding(16.dp)
)
/**
* Returns whether the lazy list is currently scrolling up.
*/
@Composable
private fun LazyListState.isScrollingUp(): Boolean
var previousIndex by remember(this) mutableStateOf(firstVisibleItemIndex)
var previousScrollOffset by remember(this) mutableStateOf(firstVisibleItemScrollOffset)
return remember(this)
derivedStateOf
if (previousIndex != firstVisibleItemIndex)
previousIndex > firstVisibleItemIndex
else
previousScrollOffset >= firstVisibleItemScrollOffset
.also
previousIndex = firstVisibleItemIndex
previousScrollOffset = firstVisibleItemScrollOffset
.value
/**
* Shows the header label.
*
* @param title The title to be shown.
*/
@Composable
private fun Header(
title: String
)
Text(
text = title,
modifier = Modifier.semantics heading() ,
style = MaterialTheme.typography.h5
)
/**
* Shows a row for one topic.
*
* @param topic The topic title.
* @param expanded Whether the row should be shown expanded with the topic body.
* @param onClick Called when the row is clicked.
*/
@Composable
private fun TopicRow(topic: String, expanded: Boolean, onClick: () -> Unit)
TopicRowSpacer(visible = expanded)
Surface(
modifier = Modifier
.fillMaxWidth()
.clickable(onClick = onClick),
elevation = 2.dp
)
// TODO 3: Animate the size change of the content.
Column(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
)
Row
Icon(
imageVector = Icons.Default.Info,
contentDescription = null
)
Spacer(modifier = Modifier.width(16.dp))
Text(
text = topic,
style = MaterialTheme.typography.body1
)
if (expanded)
Spacer(modifier = Modifier.height(8.dp))
Text(
text = stringResource(R.string.lorem_ipsum),
textAlign = TextAlign.Justify
)
TopicRowSpacer(visible = expanded)
/**
* Shows a separator for topics.
*/
@OptIn(ExperimentalAnimationApi::class)
@Composable
fun TopicRowSpacer(visible: Boolean)
AnimatedVisibility(visible = visible)
Spacer(modifier = Modifier.height(8.dp))
/**
* Shows the bar that holds 2 tabs.
*
* @param backgroundColor The background color for the bar.
* @param tabPage The [TabPage] that is currently selected.
* @param onTabSelected Called when the tab is switched.
*/
@Composable
private fun HomeTabBar(
backgroundColor: Color,
tabPage: TabPage,
onTabSelected: (tabPage: TabPage) -> Unit
)
TabRow(
selectedTabIndex = tabPage.ordinal,
backgroundColor = backgroundColor,
indicator = tabPositions ->
HomeTabIndicator(tabPositions, tabPage)
)
HomeTab(
icon = Icons.Default.Home,
title = stringResource(R.string.home),
onClick = onTabSelected(TabPage.Home)
)
HomeTab(
icon = Icons.Default.AccountBox,
title = stringResource(R.string.work),
onClick = onTabSelected(TabPage.Work)
)
/**
* Shows an indicator for the tab.
*
* @param tabPositions The list of [TabPosition]s from a [TabRow].
* @param tabPage The [TabPage] that is currently selected.
*/
@Composable
private fun HomeTabIndicator(
tabPositions: List<TabPosition>,
tabPage: TabPage
)
// TODO 4: Animate these value changes.
val indicatorLeft = tabPositions[tabPage.ordinal].left
val indicatorRight = tabPositions[tabPage.ordinal].right
val color = if (tabPage == TabPage.Home) Purple700 else Green800
Box(
Modifier
.fillMaxSize()
.wrapContentSize(align = Alignment.BottomStart)
.offset(x = indicatorLeft)
.width(indicatorRight - indicatorLeft)
.padding(4.dp)
.fillMaxSize()
.border(
BorderStroke(2.dp, color),
RoundedCornerShape(4.dp)
)
)
/**
* Shows a tab.
*
* @param icon The icon to be shown on this tab.
* @param title The title to be shown on this tab.
* @param onClick Called when this tab is clicked.
* @param modifier The [Modifier].
*/
@Composable
private fun HomeTab(
icon: ImageVector,
title: String,
onClick: () -> Unit,
modifier: Modifier = Modifier
)
Row(
modifier = modifier
.clickable(onClick = onClick)
.padding(16.dp),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically
)
Icon(
imageVector = icon,
contentDescription = null
)
Spacer(modifier = Modifier.width(16.dp))
Text(text = title)
/**
* Shows the weather.
*
* @param onRefresh Called when the refresh icon button is clicked.
*/
@Composable
private fun WeatherRow(
onRefresh: () -> Unit
)
Row(
modifier = Modifier
.heightIn(min = 64.dp)
.padding(16.dp),
verticalAlignment = Alignment.CenterVertically
)
Box(
modifier = Modifier
.size(48.dp)
.clip(CircleShape)
.background(Amber600)
)
Spacer(modifier = Modifier.width(16.dp))
Text(text = stringResource(R.string.temperature), fontSize = 24.sp)
Spacer(modifier = Modifier.weight(1f))
IconButton(onClick = onRefresh)
Icon(
imageVector = Icons.Default.Refresh,
contentDescription = stringResource(R.string.refresh)
)
/**
* Shows the loading state of the weather.
*/
@Composable
private fun LoadingRow()
// TODO 5: Animate this value between 0f and 1f, then back to 0f repeatedly.
val alpha = 1f
Row(
modifier = Modifier
.heightIn(min = 64.dp)
.padding(16.dp),
verticalAlignment = Alignment.CenterVertically
)
Box(
modifier = Modifier
.size(48.dp)
.clip(CircleShape)
.background(Color.LightGray.copy(alpha = alpha))
)
Spacer(modifier = Modifier.width(16.dp))
Box(
modifier = Modifier
.fillMaxWidth()
.height(32.dp)
.background(Color.LightGray.copy(alpha = alpha))
)
/**
*
* @param task The task description.
* @param onRemove Called when the task is swiped away and removed.
*/
@Composable
private fun TaskRow(task: String, onRemove: () -> Unit)
Surface(
modifier = Modifier
.fillMaxWidth()
.swipeToDismiss(onRemove),
elevation = 2.dp
)
Row(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
)
Icon(
imageVector = Icons.Default.Check,
contentDescription = null
)
Spacer(modifier = Modifier.width(16.dp))
Text(
text = task,
style = MaterialTheme.typography.body1
)
/**
* The modified element can be horizontally swiped away.
*
* @param onDismissed Called when the element is swiped to the edge of the screen.
*/
private fun Modifier.swipeToDismiss(
onDismissed: () -> Unit
): Modifier = composed
// TODO 6-1: Create an Animatable instance for the offset of the swiped element.
pointerInput(Unit)
// Used to calculate a settling position of a fling animation.
val decay = splineBasedDecay<Float>(this)
// Wrap in a coroutine scope to use suspend functions for touch events and animation.
coroutineScope
while (true)
// Wait for a touch down event.
val pointerId = awaitPointerEventScope awaitFirstDown().id
// TODO 6-2: Touch detected; the animation should be stopped.
// Prepare for drag events and record velocity of a fling.
val velocityTracker = VelocityTracker()
// Wait for drag events.
awaitPointerEventScope
horizontalDrag(pointerId) change ->
launch
// TODO 6-3: Apply the drag change to the Animatable offset.
// Record the velocity of the drag.
velocityTracker.addPosition(change.uptimeMillis, change.position)
val velocity = velocityTracker.calculateVelocity().x
launch
.offset
// TODO 6-7: Use the animating offset value here.
IntOffset(0, 0)
@Preview
@Composable
private fun PreviewHomeTabBar()
HomeTabBar(
backgroundColor = Purple100,
tabPage = TabPage.Home,
onTabSelected =
)
@Preview
@Composable
private fun PreviewHome()
AnimationCodelabTheme
Home()
官网学习文档:
Jetpack Compose | Android Developers
官方布局基础
https://developer.android.google.cn/jetpack/compose/layouts/basic
以上是关于android -------- Jetpack Compose基础使用的主要内容,如果未能解决你的问题,请参考以下文章
Android Jetpack架构组件带你了解Android Jetpack
Android Jetpack架构组件——什么是Jetpack?
Android Jetpack架构组件——什么是Jetpack?