如何在Jetpack Compose的LazyRow首项添加类似Ins/FB的故事栏?
Jetpack Compose 实现LazyRow首位置故事栏方案
实现逻辑非常直接:只需在LazyRow的内容声明中,先渲染故事栏模块作为第一个item,再渲染后续的普通业务卡片即可。
1. 先实现单个故事项组件
@Composable fun StoryItem( avatarUrl: String, username: String, isAddStory: Boolean = false, // 标记是否是用户自己的「添加故事」入口 isViewed: Boolean = false // 标记故事是否已读 ) { Column( horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier.padding(horizontal = 8.dp) ) { // 外层渐变环(未读显示彩色渐变,已读/自己的故事显示灰色) Box( modifier = Modifier .size(72.dp) .drawBehind { if (isAddStory || isViewed) { drawCircle(color = Color.Gray, style = Stroke(width = 2.dp.toPx())) } else { drawCircle( brush = Brush.linearGradient( colors = listOf(Color.Yellow, Color.Red, Color.Magenta) ), style = Stroke(width = 2.dp.toPx()) ) } } .padding(4.dp), contentAlignment = Alignment.Center ) { if (isAddStory) { // 自己的故事入口右下角加+号 Image( painter = painterResource(id = R.drawable.ic_add_story), contentDescription = null, modifier = Modifier.align(Alignment.BottomEnd).size(20.dp) ) } // 头像 Image( painter = rememberAsyncImagePainter(model = avatarUrl), contentDescription = username, modifier = Modifier.clip(CircleShape).fillMaxSize() ) } // 用户名 Text( text = username, fontSize = 12.sp, modifier = Modifier.padding(top = 4.dp), maxLines = 1, overflow = TextOverflow.Ellipsis ) } }
2. 实现故事栏横向容器
@Composable fun StoryBar(storyList: List<StoryData>) { LazyRow( modifier = Modifier.fillMaxWidth(), contentPadding = PaddingValues(vertical = 12.dp) ) { items(storyList) { story -> StoryItem( avatarUrl = story.avatar, username = story.userName, isAddStory = story.isMine, isViewed = story.hasViewed ) } } }
3. 主LazyRow中插入故事栏作为第一个item
@Composable fun HomeLazyRow( storyList: List<StoryData>, postCardList: List<PostData> ) { LazyRow(modifier = Modifier.fillMaxSize()) { // 第一个位置放故事栏 item { StoryBar(storyList = storyList) } // 后面的位置放普通业务卡片 items(postCardList) { post -> PostCardItem(post = post) Spacer(modifier = Modifier.width(12.dp)) } } }
补充说明
- 如果需求是故事栏的单个故事项和后面的卡片平级滚动,无需嵌套双层
LazyRow,直接把故事列表的内容放到主LazyRow的最前面即可:LazyRow { // 先放所有故事项 items(storyList) { story -> StoryItem(story = story) } // 再放所有卡片项 items(postList) { post -> PostCard(post = post) } } - 故事已读未读状态通过ViewModel里的状态字段控制,点击后更新对应字段即可触发渐变环的样式更新。
- 如果需要实现故事点击后的全屏轮播效果,可以搭配
Pager组件实现,逻辑和普通轮播一致。
内容的提问来源于stack exchange,提问作者Suman Radhakrishnan
相关产品推荐
相关产品推荐

