diff --git a/.agents/skills/mpx2rn/references/rn-script-reference.md b/.agents/skills/mpx2rn/references/rn-script-reference.md index ee8dba4173..2c10faa553 100644 --- a/.agents/skills/mpx2rn/references/rn-script-reference.md +++ b/.agents/skills/mpx2rn/references/rn-script-reference.md @@ -587,11 +587,13 @@ setAppHide() | `getCurrentPages()` | 返回当前导航栈中已映射的页面实例列表(顺序与路由 state 相关)。 | | `setAppShow()` | 手动触发应用「进入前台」逻辑,驱动已注册的 `onShow`。 | | `setAppHide()` | 手动触发应用「进入后台」逻辑,驱动已注册的 `onHide`。 | +| `notifyDimensionsChange(dimensions?)` | 主动通知框架 dimensions 发生变化,触发 rpx、vw、vh、媒体查询、onResize 等的重新计算。不传参时默认使用当前屏幕 dimensions 并重新执行 `customDimensions`。 | #### 注意事项 - 勿在 App 构造函数执行完成前依赖 `getApp()` 内业务字段已赋值完毕;与路由相关的初始化宜放在 `onLaunch` / `onShow`。 - `getCurrentPages()` 依赖 React Navigation 焦点与 `__mpxPagesMap`,与原生小程序栈细节不完全相同。 +- `notifyDimensionsChange` 由框架在首次样式计算时自动注入,需在开始渲染后才可调用。 --- diff --git a/docs-vitepress/guide/rn/application-api.md b/docs-vitepress/guide/rn/application-api.md index ba225bbfa8..fd7185eb1d 100644 --- a/docs-vitepress/guide/rn/application-api.md +++ b/docs-vitepress/guide/rn/application-api.md @@ -463,7 +463,6 @@ createComponent({ 例如: 在折叠屏中我们期望只在其中一半屏上展示,可在 customDimensions 中判断当前是否为折叠屏展开状态,如果是则将 ScreenWidth 设置为原来的一半。 - ### 前后台切换 {#app-state-change} #### mpx.config.rnConfig.disableAppStateListener diff --git a/packages/core/@types/global.d.ts b/packages/core/@types/global.d.ts index 51dbff4263..7a3297f9db 100644 --- a/packages/core/@types/global.d.ts +++ b/packages/core/@types/global.d.ts @@ -14,3 +14,5 @@ declare module '*?resolve' { declare let setAppShow: () => void declare let setAppHide: () => void + +declare let notifyDimensionsChange: (dimensions?: { window: import('react-native').ScaledSize; screen: import('react-native').ScaledSize }) => void diff --git a/packages/core/@types/index.d.ts b/packages/core/@types/index.d.ts index 41c6840928..237a7d1b22 100644 --- a/packages/core/@types/index.d.ts +++ b/packages/core/@types/index.d.ts @@ -376,9 +376,9 @@ export interface RnConfig { * @param dimensions 包含 window 和 screen 的尺寸信息 * @returns 返回修改后的尺寸对象,或 void 表示不修改 */ - customDimensions?: ( - dimensions: T - ) => T | void + customDimensions?: ( + dimensions: { window: ScaledSize; screen: ScaledSize } + ) => { window: ScaledSize; screen: ScaledSize } | void /** * 加载并执行异步分包的方法。 diff --git a/packages/core/src/platform/builtInMixins/styleHelperMixin.ios.js b/packages/core/src/platform/builtInMixins/styleHelperMixin.ios.js index 0628aaf89f..bf7e1f221e 100644 --- a/packages/core/src/platform/builtInMixins/styleHelperMixin.ios.js +++ b/packages/core/src/platform/builtInMixins/styleHelperMixin.ios.js @@ -4,8 +4,8 @@ import { reactive } from '../../observer/reactive' import Mpx from '../../index' global.__mpxAppDimensionsInfo = { - window: Dimensions.get('window'), - screen: Dimensions.get('screen') + window: Object.assign({}, Dimensions.get('window')), + screen: Object.assign({}, Dimensions.get('screen')) } global.__mpxSizeCount = 0 global.__mpxPageSizeCountMap = reactive({}) @@ -18,30 +18,40 @@ global.__GCC = function (className, classMap, classMapValueCache) { return classMapValueCache.get(className) } -let dimensionsInfoInitialized = false -function useDimensionsInfo (dimensions) { - dimensionsInfoInitialized = true +function getPageSize (screen = global.__mpxAppDimensionsInfo.screen) { + return screen.width + 'x' + screen.height +} + +// 将 dimensions 写入全局(支持 customDimensions 自定义),返回最终生效的 dimensions +function applyDimensionsInfo (dimensions) { if (typeof Mpx.config.rnConfig?.customDimensions === 'function') { dimensions = Mpx.config.rnConfig.customDimensions(dimensions) || dimensions } global.__mpxAppDimensionsInfo.window = dimensions.window global.__mpxAppDimensionsInfo.screen = dimensions.screen + return dimensions } -function getPageSize (window = global.__mpxAppDimensionsInfo.screen) { - return window.width + 'x' + window.height -} - -Dimensions.addEventListener('change', ({ window, screen }) => { - const oldScreen = getPageSize(global.__mpxAppDimensionsInfo.screen) - useDimensionsInfo({ window, screen }) +function onDimensionsChange (dimensions) { + const oldScreen = getPageSize() + /** + * 鸿蒙上在屏幕尺寸不变时,调用 Dimensions.get 获取到的返回值都是同一个对象, + * 为防止外部修改dimensions导致影响其他位置调用Dimensions.get的返回,所以clone一份进行后续处理 + */ + if (!dimensions) { + dimensions = { + window: Dimensions.get('window'), + screen: Dimensions.get('screen') + } + } + applyDimensionsInfo({ window: Object.assign({}, dimensions.window), screen: Object.assign({}, dimensions.screen) }) - // 对比 screen 高宽是否存在变化 - if (getPageSize(screen) === oldScreen) return + // screen 高宽未变化时不触发 resize 副作用 + if (getPageSize() === oldScreen) return global.__classCaches?.forEach(cache => cache?.clear()) - // 更新全局和栈顶页面的标记,其他后台页面的标记在show之后更新 + // 更新全局和栈顶页面的标记,其他后台页面的标记在 show 之后更新 global.__mpxSizeCount++ const navigation = getFocusedNavigation() @@ -52,7 +62,11 @@ Dimensions.addEventListener('change', ({ window, screen }) => { global.__mpxPageStatusMap[navigation.pageId] = `resize${global.__mpxSizeCount}` } } -}) +} +// 默认实现:不传参时通过 Dimensions 实时获取当前屏幕尺寸(拷贝一份防止原对象被外部修改) +global.notifyDimensionsChange = onDimensionsChange + +Dimensions.addEventListener('change', onDimensionsChange) // TODO: 1 目前测试鸿蒙下折叠屏screen固定为展开状态下屏幕尺寸,仅window会变化,且window包含状态栏高度 // TODO: 2 存在部分安卓折叠屏机型在折叠/展开切换时,Dimensions监听到的width/height尺寸错误,并触发多次问题 @@ -79,8 +93,13 @@ const unit = { const empty = {} +let dimensionsApplied = false function formatValue (value, unitType) { - if (!dimensionsInfoInitialized) useDimensionsInfo(global.__mpxAppDimensionsInfo) + // 懒初始化:首次调用时将初始 dimensions 写入全局(触发 customDimensions 处理) + if (!dimensionsApplied) { + dimensionsApplied = true + applyDimensionsInfo(global.__mpxAppDimensionsInfo) + } if (unitType === 'hairlineWidth') { return StyleSheet.hairlineWidth }