HarmonyOS 7 / API 26 3DGS 多设备预览适配:折叠屏、平板和窗口态下视口怎么稳住

📅 2026/8/8 14:01:10
HarmonyOS 7 / API 26 3DGS 多设备预览适配:折叠屏、平板和窗口态下视口怎么稳住
HarmonyOS 7 / API 26 3DGS 多设备预览适配折叠屏、平板和窗口态下视口怎么稳住3D 预览到了大屏不是简单放大3DGS 模型预览在手机竖屏里能跑不代表放到折叠屏、平板、鸿蒙电脑窗口态里也能跑得舒服。二维列表页面放大以后最多是空白多一点3D 页面放大以后会出现更明显的问题模型被裁切、手势冲突、相机距离不合适、右侧属性面板遮住主体、窗口缩小时状态没有恢复。这篇专门看 3DGS 预览在多设备形态下的适配。它不是普通响应式布局文章因为 3D 页面除了 ArkUI 布局还要同时处理 3D 视口、相机参数和手势区域。先分清三个尺寸很多问题来自一个误区只拿页面宽度判断布局。3D 预览页至少要看三个尺寸尺寸含义常见错误Window Size当前应用窗口大小只按屏幕大小不按窗口变化Preview Viewport真正承载 3D 场景的区域属性面板出现后仍按整屏算相机Model Bounds模型自己的空间范围相机距离固定模型大了就被裁切3DGS 页面要稳不能只写“宽度大于 840 就双栏”。双栏以后3D 视口变窄了相机也要跟着重新算。案例一平板双栏后模型被右侧面板挡住第一个案例是平板双栏。左边是 3D 预览右边是模型信息和操作。页面看起来很合理但如果相机仍按整屏宽度算模型主体就可能偏到右侧被面板遮住。复现步骤手机竖屏打开 3DGS 预览模型居中切到平板或展开折叠屏页面改成左预览、右信息面板如果 3D 相机仍按窗口宽度计算主体容易偏移改成按 previewViewport 计算相机问题消失。interface Size2D { width: number; height: number; } interface PreviewLayoutInfo { windowSize: Size2D; viewportSize: Size2D; sidePanelWidth: number; mode: phone | tablet | desktopWindow; } export function calculatePreviewLayout(windowSize: Size2D): PreviewLayoutInfo { if (windowSize.width 720) { return { windowSize, viewportSize: windowSize, sidePanelWidth: 0, mode: phone }; } const sidePanelWidth Math.min(360, Math.floor(windowSize.width * 0.32)); return { windowSize, sidePanelWidth, viewportSize: { width: windowSize.width - sidePanelWidth, height: windowSize.height }, mode: windowSize.width 1100 ? desktopWindow : tablet }; }这里的关键是 viewportSize。3D 场景不关心整个窗口有多宽它只关心自己实际能画的区域有多大。相机跟着视口重新算interface CameraConfig { distance: number; fieldOfView: number; targetOffsetX: number; targetOffsetY: number; } export class ResponsiveCameraPlanner { plan(layout: PreviewLayoutInfo, bounds: ModelBounds): CameraConfig { const aspect layout.viewportSize.width / Math.max(layout.viewportSize.height, 1); const baseDistance Math.max(bounds.radius, 1) * 2.6; if (layout.mode phone) { return { distance: baseDistance * 1.08, fieldOfView: 48, targetOffsetX: 0, targetOffsetY: 0 }; } if (aspect 1.4) { return { distance: baseDistance * 0.95, fieldOfView: 42, targetOffsetX: 0, targetOffsetY: 0 }; } return { distance: baseDistance * 1.15, fieldOfView: 46, targetOffsetX: 0, targetOffsetY: 0 }; } }我不会在 3D 页面里写一个固定相机距离。模型大小、视口宽高比、双栏状态都会影响第一屏效果。相机参数跟随 viewport 计算才不会出现大屏反而看不清模型的问题。案例二窗口缩放后手势区域和 3D 区域错位第二个案例出现在鸿蒙电脑窗口态或平板分屏里。用户拖动窗口后页面 UI 变了但手势识别区域还停留在旧尺寸结果滑动旋转模型时手势落点和模型不一致。复现步骤打开 3DGS 预览页拖动窗口变窄右侧面板从常驻变成底部抽屉如果手势区域没有重新绑定旋转或缩放会异常在 onSizeChange 后同步更新 viewport 和 gesture zone。interface GestureZone { left: number; top: number; width: number; height: number; } export class SpatialGestureZoneStore { private zone: GestureZone { left: 0, top: 0, width: 0, height: 0 }; updateFromViewport(viewport: Size2D): GestureZone { this.zone { left: 0, top: 0, width: viewport.width, height: viewport.height }; return { ...this.zone }; } canHandle(pointX: number, pointY: number): boolean { return pointX this.zone.left pointX this.zone.left this.zone.width pointY this.zone.top pointY this.zone.top this.zone.height; } }3D 手势不要全屏接管。页面里可能还有返回按钮、底部面板、参数滑块、模型信息卡片。手势区域必须跟实际 3D 视口一致否则用户操作会变得很怪。页面状态和 3D 状态要一起刷新interface SpatialPreviewResizeState { layout: PreviewLayoutInfo; camera: CameraConfig; gestureZone: GestureZone; updatedAt: number; } export class SpatialPreviewResizeController { private cameraPlanner new ResponsiveCameraPlanner(); private gestureStore new SpatialGestureZoneStore(); resize(windowSize: Size2D, bounds: ModelBounds): SpatialPreviewResizeState { const layout calculatePreviewLayout(windowSize); const camera this.cameraPlanner.plan(layout, bounds); const gestureZone this.gestureStore.updateFromViewport(layout.viewportSize); return { layout, camera, gestureZone, updatedAt: Date.now() }; } }这里我把 resize 单独封装。原因是窗口变化时要更新的不止 ArkUI 布局还包括相机和手势。只改页面 Column、Row、Stack不改 3D 视口状态问题还是会复现。多设备验证清单场景必查点通过标准手机竖屏单栏预览模型主体首屏可见底部按钮不挡主体折叠屏展开左预览右信息相机按预览区计算不按整屏计算平板横屏双栏或浮层信息手势只作用在 3D 区域鸿蒙电脑窗口拖动窗口大小相机、手势、布局同时更新分屏视口变窄面板降级模型不裁切最后总结3DGS 多设备适配不能只看 ArkUI 断点。真正要稳定的是 3D 视口、默认相机和手势区域。窗口变了预览区变了相机和手势也要跟着变。HarmonyOS 7 / API 26 的 3DGS 体验如果只在手机竖屏里验证很容易漏掉大屏问题。折叠屏、平板、窗口态都是活动要求里的重要方向。把 viewport、camera、gesture 三个状态统一起来后面接更多 3D 模型和页面形态会稳很多。