采用Jetpack Compose 实现Feed流-UI界面部分

前言

Jetpack Compose 是用于构建原生界面的新款 Android 工具包。它可简化并加快 Android 上的界面开发。使用更少的代码、强大的工具和直观的 Kotlin API,快速让应用生动而精彩。这是官方对它的介绍。2019年Google就推出了Jetpack Compose,并且稳定版本即将在2021年7月发布,所以大家还是有必要提前学习一下的。

通过这一段时间的学习,了解到Jectpack Compose是一种全新的UI开发框架,采用了声明式编程思想,完全基于Kotlin语言,并将之前的Xml UI界面渲染那一套逻辑完全废弃了,所以界面布局/渲染/刷新机制完全是新的。

需要实现的功能

如下图

Screenshot_2021-07-12-15-39-35-513_com.codelab.layouts.jpg

Pager组件介绍

Pager组件是专门为使用Jetpack Compose开发类似页面切换布局的一个库,类似AndroidView中的Viewpager,需要注意的是,当前该组件还在实验阶段,所以库中的API可能还会发生变化,并且所有的API都加了@ExperimentalPagerApi注解

该组件库中目前提供了:

1)HorizontalPager:水平方向切换页面的组件,简单用法:

// Display 10 items

val pagerState = rememberPagerState(pageCount = 10)

HorizontalPager(state = pagerState) { page ->

        // Our page content

       Text( text = "Page: $page", modifier = Modifier.fillMaxWidth() )

}
复制代码

通过pagerState可以得到当前页面:pagerState.currentPage,可以滚动到指定页面:pagerState.scrollToPage(index),或者pagerState.animateScrollToPage(index),但这两个方法需要在CoroutineScope使用,如下:

coroutineScope.launch { pagerState.animateScrollToPage(index)}
复制代码

2) VerticalPager:竖直方向切换页面的组件,基本使用方式同HorizontalPager

3)同ViewPager一样,Pager组件同样可以指定当前页面两侧的页数,通过设置initOffscreenLimit字段

val pagerState = rememberPagerState( pageCount = 10, initialOffscreenLimit = 2,)

HorizontalPager(state = pagerState) { page -> // ...}
复制代码

并且,当用户在界面间滑动时,超过该数量的界面就会被动态移除。

Demo实现

需要上图中多tab样式的feed流样式,需要用到的组件:TabRow + Pager + Indicators + LazyColumn,对应AndroidView的TabLayout + ViewPager + RecyclerView

环境准备:app下的build.gradle中引入如下依赖:

implementation "com.google.accompanist:accompanist-pager:0.13.0"

implementation "com.google.accompanist:accompanist-pager-indicators:0.13.0"
复制代码

Node:本文基于Jetpack Compose 1.0.0-beta09′

@ExperimentalPagerApi
@Composable
private fun TabContentScreen(recItems: List<PostData>, followItems: List<PostData>, hotItems: List<PostData>) {
    val pages = listOf("热门", "关注", "推荐")
    Column {
        val coroutineScope = rememberCoroutineScope()
        val pagerState = rememberPagerState(
            pageCount = pages.size,
            initialOffscreenLimit = 2,
        )
        TabRow(
            selectedTabIndex = pagerState.currentPage,
            indicator = { tabPositions ->
                TabRowDefaults.Indicator(
                    Modifier.pagerTabIndicatorOffset(pagerState, tabPositions),
                    color = Color.White
                )
            },
            backgroundColor = Color.White,
            modifier = Modifier.width(210.dp),
            divider = {
                TabRowDefaults.Divider(color = Color.White)
            }
        ) {
            pages.forEachIndexed { index, title ->
                Tab(
                    selected = pagerState.currentPage == index,
                    onClick = {
                        coroutineScope.launch {
                            pagerState.animateScrollToPage(index)
                        }
                    },
                    modifier = Modifier.height(50.dp).background(Color.White),
                selectedContentColor = Color.Black,
                    unselectedContentColor = Color.Gray
                ) {
                    Text(title,
                        maxLines = 1,
                        fontSize = if (pagerState.currentPage == index) 20.sp else 16.sp,
                        fontWeight = if (pagerState.currentPage == index) FontWeight.Bold else FontWeight.Normal
                    )
                }
            }
        }
        HorizontalPager(
            state = pagerState,
            modifier = Modifier
                .weight(1f)
                .fillMaxWidth()
        ) {
            LazyColumn(contentPadding = PaddingValues(start = 16.dp, end = 16.dp)) {
                val curItems = if (pagerState.currentPage == 0) {
                    recItems
                } else if (pagerState.currentPage == 1) {
                    followItems
                } else {
                    hotItems
                }
                items(items = curItems) {
                    PostCardView(itemData = it)
                }
            }
        }
    }
}
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享