/** * 第 10 章配套代码 · 首页瀑布流 * * 文件位置:shared/src/commonMain/kotlin/com/example/xhs/pages/HomePage.kt * * 综合演示: * - WaterfallList + vfor 长列表复用 * - Refresh 下拉刷新 * - scrollEnd 上拉加载 * - 骨架屏(首屏 loading 状态) * - 全局 NoteStore 跨 Pager 共享数据 * - PageRouterModule 跳转详情页 * - 跟随 ThemeStore 切换暗色模式 */ package com.example.xhs.pages import com.example.xhs.components.NoteCard import com.example.xhs.store.NoteStore import com.example.xhs.store.ThemeStore import com.tencent.kuikly.core.annotations.Page import com.tencent.kuikly.core.base.Color import com.tencent.kuikly.core.base.ViewBuilder import com.tencent.kuikly.core.directives.vfor import com.tencent.kuikly.core.module.PageRouterModule import com.tencent.kuikly.core.nvi.serialization.json.JSONObject import com.tencent.kuikly.core.pager.Pager import com.tencent.kuikly.core.views.Refresh import com.tencent.kuikly.core.views.Text import com.tencent.kuikly.core.views.View import com.tencent.kuikly.core.views.WaterfallList @Page("HomePage") internal class HomePage : Pager() { override fun pageDidAppear() { super.pageDidAppear() if (NoteStore.notes.isEmpty()) { NoteStore.refresh() } } override fun body(): ViewBuilder { val ctx = this return { attr { backgroundColor( if (ThemeStore.darkMode) Color(0xFF121212L) else Color(0xFFF5F5F7L) ) } // ─── 顶栏 ───── View { attr { height(48f); allCenter() backgroundColor( if (ThemeStore.darkMode) Color(0xFF1E1E1EL) else Color.WHITE ) } Text { attr { text("迷你小红书") fontSize(18f); fontWeightBold() color(if (ThemeStore.darkMode) Color.WHITE else Color.BLACK) } } } // ─── 内容区 ───── when { NoteStore.loading && NoteStore.notes.isEmpty() -> renderSkeleton().invoke(this) NoteStore.notes.isEmpty() -> renderEmpty().invoke(this) else -> renderWaterfall(ctx).invoke(this) } } } /** 骨架屏 */ private fun renderSkeleton(): ViewBuilder = { View { attr { flex(1f); padding(8f) flexDirectionRow(); flexWrapWrap() } repeat(8) { i -> View { attr { width(174f) height(if (i % 2 == 0) 200f else 240f) backgroundColor(Color(0xFFE0E0E0L)) borderRadius(8f); margin(4f) } } } } } /** 空数据 */ private fun renderEmpty(): ViewBuilder = { View { attr { flex(1f); allCenter() } Text { attr { text("📭"); fontSize(40f); marginBottom(8f) } } Text { attr { text("暂无笔记") fontSize(14f); color(Color(0xFF9E9E9EL)) } } } } /** 瀑布流 */ private fun renderWaterfall(ctx: HomePage): ViewBuilder = { WaterfallList { attr { flex(1f) columnCount(2) columnSpacing(8f) rowSpacing(8f) paddingHorizontal(8f) paddingVertical(8f) } event { scrollEnd { e -> val nearBottom = e.offsetY + e.viewSize.height >= e.contentSize.height - 200f if (nearBottom) NoteStore.loadMore() } } // 下拉刷新 Refresh { attr { refreshing(NoteStore.loading) } event { refresh { NoteStore.refresh() } } Text { attr { text(if (NoteStore.loading) "刷新中…" else "↓ 下拉刷新") fontSize(12f); color(Color(0xFF9E9E9EL)) textAlignCenter(); paddingVertical(12f) } } } // 笔记列表 vfor({ NoteStore.notes }) { note -> NoteCard(note) { ctx.openDetail(note.id) }.invoke(this) } // 加载更多 footer if (NoteStore.notes.isNotEmpty() && !NoteStore.hasMore) { View { attr { height(50f); allCenter() } Text { attr { text("— 没有更多了 —") fontSize(12f); color(Color(0xFFBDBDBDL)) } } } } } } private fun openDetail(noteId: String) { acquireModule(PageRouterModule.MODULE_NAME) .openPage("NoteDetailPage", JSONObject().apply { put("noteId", noteId) }) } }