下面给出一套可落地的方案与实现要点,帮助把“PotatoChat 手机版”做成对折叠屏(foldable)友好的应用。内容包含技术选型、Android 代码/依赖示例、Compose/传统 View 的处理建议、Web/React Native/Flutter 的简要说明,以及测试与 PR 模板,便于直接在项目中使用和验收。

一、总体思路(关键点)
- 优先目标:在折叠/展开切换、跨铰链(hinge)布局、分屏/多窗口场景下保持 UI 连贯且可用。
- 适配策略:根据屏幕姿态(posture)和可用显示区域(display segments)决定单栏/双栏/大屏模式(master-detail)。
- 尽量使用官方库(Jetpack WindowManager)获取设备的折叠信息并处理生命周期/布局变化。
- 兼容退化方案:若设备或浏览器不支持折叠 API,应回退到常规响应式布局(sw/width breakpoints)。
二、Android 推荐实现(原生/AndroidX)
- 依赖(Gradle)
- 使用 Jetpack WindowManager(版本请以项目 Gradle 仓库的最新稳定版为准):
implementation "androidx.window:window:1.1.0" (或 1.0.x / 1.2.x,按实际仓库) - Compose 项目还可以配合 Compose UI(若使用)。
- 获取折叠信息(Kotlin,Activity 中)
示例(简化):
- 在 Activity 中订阅 window layout info:
val windowInfoTracker = WindowInfoTracker.getOrCreate(application)
lifecycleScope.launch {
windowInfoTracker.windowLayoutInfo(this@MainActivity)
.flowWithLifecycle(lifecycle, Lifecycle.State.STARTED)
.collect { layoutInfo ->
val foldingFeatures = layoutInfo.displayFeatures.filterIsInstance<FoldingFeature>()
if (foldingFeatures.isEmpty()) {
// 单屏模式
showSinglePane()
} else {
val folding = foldingFeatures.first()
when (folding.state) {
FoldingFeature.State.FLAT -> showSinglePane()
FoldingFeature.State.HALF_OPENED -> showHingeAwareUi(folding)
}
// 根据 folding.orientation 判断是水平折叠还是垂直折叠
}
}
}
说明:FoldingFeature 提供 bounds、orientation、state,允许我们判断铰链位置并调整布局(如不跨铰链显示重要内容)。
- 布局策略(建议)
- 垂直铰链(屏幕左右两个竖分区域):考虑把会话列表放左侧、聊天窗放右侧(双栏)。
- 水平铰链(上下分区):通常保持单列滚动或把详情放下方,避免重要交互跨铰链。
- 不要把交互控件放在铰链区域,防止被遮挡或不可点击。
- 使用 master-detail(两栏)布局时保证两栏在窄屏下自动回退到单栏(使用 sw/Narrow breakpoint)。
- 使用 ConstraintLayout 或 Compose 的 Row/Column ,也可以用 AndroidX SlidingPaneLayout 或自己实现分栏。
- Compose(若项目为 Jetpack Compose)
- 仍使用 WindowInfoTracker 获取信息;可封装为 rememberWindowLayoutInfo 的可组合函数:
@Composable
fun rememberWindowLayoutInfo(): State<WindowLayoutInfo?> {
val context = LocalContext.current
val lifecycleOwner = LocalLifecycleOwner.current
val windowInfoTracker = WindowInfoTracker.getOrCreate(context)
val state = remember { mutableStateOf<WindowLayoutInfo?>(null) }
DisposableEffect(lifecycleOwner) {
val scope = CoroutineScope(Dispatchers.Main)
val job = scope.launch {
windowInfoTracker.windowLayoutInfo(context as Activity)
.flowWithLifecycle(lifecycleOwner.lifecycle, Lifecycle.State.STARTED)
.collect { info -> state.value = info }
}
onDispose {
job.cancel()
}
}
return state
}
- 根据 state.value 中的 FoldingFeature 决定显示 SinglePane/TwoPane 组合。Jetpack Compose 生态中也有 TwoPane(AndroidX)可参考。
- Activity 配置(生命周期)
- 推荐不要使用 configChanges 直接吞掉所有配置变更,优先响应系统配置变化并利用 WindowManager 提供的信息处理 UI。若用了 configChanges,注意手动处理尺寸/方向/折叠变化。
- 当展开/折叠发生时应保证状态(输入、光标、未读消息等)不丢失:把 UI 状态放在 ViewModel/rememberSaveable 中。
三、Web / PWA(若 PotatoChat 有 Web 视图)
- 现代浏览器支持 CSS 折叠屏适配 API:viewport-segment-* env 变量 与媒体查询。
- 示例:
@media (horizontal-viewport-segments: 2) {
/* 在有两个水平段的设备(垂直铰链)时禁用内容跨铰链 */
.chat-container {
/* 例如为左右两段各自设置宽度或把重要区域避免放在铰链中 */
}
}
/* 访问铰链安全区域 */
padding-left: env(viewport-segment-left);
- Chrome / Edge 等对这些特性部分支持。需提供降级方案(常规 responsive CSS)。
四、跨平台框架简述
- Flutter:
- 可用 platform channels 调用 Android WindowManager 或使用 community 插件(如 foldable_support 等)。
- 通过 MediaQuery.of(context).size 判断分段,并结合 platform 信息决定两栏布局。
- React Native:
- 可引入 native 模块或 community package(搜索 react-native-foldable / react-native-window-manager)。
- 也可在 Android 原生层提供信息并通过 bridge 传递给 JS 层。
五、测试 & 验收清单
- 在 Android Emulator 上创建折叠屏 AVD(如 Surface Duo / Galaxy Fold 模板)进行功能测试。
- 在真实设备(如 Samsung Fold/Flip、Surface Duo)上测试:
- 展开/折叠切换:UI 平滑、状态不丢失。
- 铰链处交互不可用、内容没有被遮挡。
- 多窗口(split-screen)和 freeform 测试。
- 旋转、从后退栈恢复等场景。
- 边界情况:极窄/极宽面板、半开状态、双屏模式。
- 性能:在双栏模式下确保列表/图片加载不卡顿,避免同时加载过多数据或重复布局计算。
- 无障碍(Accessibility):两栏下仍保持无障碍焦点顺序合理。
六、常见实现细节 & 注意点
- 不要把弹窗(Dialog)跨铰链展示,或在铰链上定位弹窗。
- 对于重要交互,避免把单个控件横跨铰链区域。
- 铰链宽度可能不为 0(存在“安全区域”),使用 FoldingFeature.bounds 来避开该区域。
- 在某些设备上折叠为 FLAT,但物理铰链依然存在,要兼顾逻辑判断(state FLAT vs HALF_OPENED)。
- 若项目使用 Fragment,考虑将主/子屏内容拆分为两个 Fragment 并按模式动态 attach/detach。
七、提交/PR 模板(可直接用)
- PR 标题:659: 手机端折叠屏适配(支持 Jetpack WindowManager)
- 变更点(简短):
- 添加 androidx.window 依赖
- 新增 WindowLayoutInfo 订阅与 FoldingFeature 处理(MainActivity / ViewModel)
- 新增双栏布局(res/layout/activity_chat_two_pane.xml / Compose TwoPane)
- 调整状态保存(ViewModel -> 保证折叠/展开切换不丢失)
- 测试:在折叠屏 AVD 与实机(Galaxy Fold)验证通过
- 测试步骤(在 PR 描述里写明)
- 回退方案:未检测到折叠 API 时维持现有单列 UI
八、示例行为建议(UX)
- 手机窄屏:默认单列,消息详情覆盖列表(导航到聊天页)。
- 折叠展开后(宽屏):自动显示列表+详情并列(左列表右聊天)。
- 半开(铰链为中线且状态 HALF_OPENED):按铰链方向决定是否显示两面,或保持单面避免被遮挡。
- 在大屏/两栏下,保持底部输入栏可见,避免被键盘覆盖(可调整窗口输入模式)。
如果你愿意,我可以:
- 根据 PotatoChat 当前代码仓(给我看目录结构或关键文件)给出具体的代码补丁或 PR diff 示例;
- 提供 Compose 或 XML 的两栏完整实现样例(带 ViewModel 状态管理);
- 给出在 Emulator/Surface Duo/三星折叠机型上具体的测试命令与截图示例。
你希望我先给出哪个具体实现(原生 View、Jetpack Compose、Flutter 或 React Native)?或者把仓库结构贴上来我直接帮你生成 patch?