You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 10:06:04