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简介

Android Jetpack架构组件——什么是Jetpack?

Android Jetpack架构组件——什么是Jetpack?

《Android Jetpack从入门到精通+高级Jetpack强化实战》,最新Jetpack系列开发笔记开源

Android高级Jetpack架构组件+Jetpack compose强化实战