已合并
fix: window jitter after dragging. #1464
xiedairong创建于 2025年8月25日
fix: window jitter after dragging. #1464
已合并
共 3 个文件变更+37-47
| @@ -208,6 +208,7 @@ export class RNInstancesCoordinator { | |||
| 208 | private onDestroyCallbacks: Function[]; | 208 | private onDestroyCallbacks: Function[]; |
| 209 | private timerId: number = 0; | 209 | private timerId: number = 0; |
| 210 | private lastChangeTime: number = 0; | 210 | private lastChangeTime: number = 0; |
| 211 | + private isWindowRectDrag: boolean = false; | ||
| 211 | /** | 212 | /** |
| 212 | * Note: You may need to change this delay along with RNSurface's onMeasuredSize delay, | 213 | * Note: You may need to change this delay along with RNSurface's onMeasuredSize delay, |
| 213 | * as both have an effect on window changes. | 214 | * as both have an effect on window changes. |
| @@ -341,19 +342,17 @@ export class RNInstancesCoordinator { | |||
| 341 | } | 342 | } |
| 342 | 343 | ||
| 343 | public onWindowRectChange(data: window.RectChangeOptions) { | 344 | public onWindowRectChange(data: window.RectChangeOptions) { |
| 344 | - if (data.reason === window.RectChangeReason.DRAG_START) { | 345 | + const isWindowRectDrag = data.reason === window.RectChangeReason.DRAG; |
| 346 | + if (this.isWindowRectDrag !== isWindowRectDrag) { | ||
| 345 | this.rnInstanceRegistry.forEach((rnInstance) => { | 347 | this.rnInstanceRegistry.forEach((rnInstance) => { |
| 346 | - rnInstance.onWindowReactChange(true) | 348 | + rnInstance.onWindowReactChange(isWindowRectDrag); |
| 347 | - }) | 349 | + }); |
| 348 | - } else if(data.reason === window.RectChangeReason.DRAG_END) { | 350 | + this.isWindowRectDrag = isWindowRectDrag; |
| 349 | - this.rnInstanceRegistry.forEach((rnInstance) => { | ||
| 350 | - rnInstance.onWindowReactChange(false) | ||
| 351 | - }) | ||
| 352 | } | 351 | } |
| 353 | } | 352 | } |
| 354 | 353 | ||
| 355 | public onWindowSizeChange(windowSize: window.Size | window.Rect) { | 354 | public onWindowSizeChange(windowSize: window.Size | window.Rect) { |
| 356 | - const currentTime = Date.now(); | 355 | + const currentTime = Date.now(); |
| 357 | if (currentTime - this.lastChangeTime > this.delayTime) { | 356 | if (currentTime - this.lastChangeTime > this.delayTime) { |
| 358 | this.displayMetricsManager.updateWindowSize(windowSize); | 357 | this.displayMetricsManager.updateWindowSize(windowSize); |
| 359 | this.rnInstanceRegistry.forEach((rnInstance) => { | 358 | this.rnInstanceRegistry.forEach((rnInstance) => { |
| @@ -29,7 +29,6 @@ import { SurfaceHandle, SurfaceProps } from './RNOH/SurfaceHandle'; | |||
| 29 | import { I18nManagerTurboModule } from './RNOHCorePackage/turboModules'; | 29 | import { I18nManagerTurboModule } from './RNOHCorePackage/turboModules'; |
| 30 | import type { SurfaceContext } from './RNOH/RNInstance'; | 30 | import type { SurfaceContext } from './RNOH/RNInstance'; |
| 31 | import { NodeContent } from '@ohos.arkui.node' | 31 | import { NodeContent } from '@ohos.arkui.node' |
| 32 | -import { window } from '@kit.ArkUI'; | ||
| 33 | 32 | ||
| 34 | interface RootViewState {} | 33 | interface RootViewState {} |
| 35 | 34 | ||
| @@ -114,10 +113,8 @@ struct ContentAdaptiveSurface { | |||
| 114 | private logger!: RNOHLogger | 113 | private logger!: RNOHLogger |
| 115 | private rootViewNodeContent: NodeContent = new NodeContent(); | 114 | private rootViewNodeContent: NodeContent = new NodeContent(); |
| 116 | private timerId: undefined | number = undefined; | 115 | private timerId: undefined | number = undefined; |
| 117 | - private lastChangeTime: number = 0; | ||
| 118 | private isWindowRectDrag: boolean = false; | 116 | private isWindowRectDrag: boolean = false; |
| 119 | private currentMeasuredSize: Size | undefined = undefined; | 117 | private currentMeasuredSize: Size | undefined = undefined; |
| 120 | - private lastChangeFlag: boolean = false; | ||
| 121 | /** | 118 | /** |
| 122 | * Note: You may need to change this delay along with RNInstancesCoordinator's | 119 | * Note: You may need to change this delay along with RNInstancesCoordinator's |
| 123 | * onWindowSizeChange delay, as both have an effect on window changes. | 120 | * onWindowSizeChange delay, as both have an effect on window changes. |
| @@ -221,38 +218,25 @@ struct ContentAdaptiveSurface { | |||
| 221 | if (this.surfaceHandle.isDestroyed()) { | 218 | if (this.surfaceHandle.isDestroyed()) { |
| 222 | return {width: 0, height: 0}; | 219 | return {width: 0, height: 0}; |
| 223 | } | 220 | } |
| 224 | - const currentTime = Date.now(); | 221 | + if (!this.isWindowRectDrag) { |
| 225 | - if (!this.isWindowRectDrag || (currentTime - this.lastChangeTime > this.delayTime) || this.lastChangeFlag) { | ||
| 226 | - if (this.timerId) { | ||
| 227 | - clearTimeout(this.timerId); | ||
| 228 | - this.timerId = undefined; | ||
| 229 | - } | ||
| 230 | this.currentMeasuredSize = | 222 | this.currentMeasuredSize = |
| 231 | this.updateSurfaceConstraints({ | 223 | this.updateSurfaceConstraints({ |
| 232 | minWidth: constraint.maxWidth as number, // NOTE: width: 100% doesn't work on the root component hence maxWidth is used here | 224 | minWidth: constraint.maxWidth as number, // NOTE: width: 100% doesn't work on the root component hence maxWidth is used here |
| 233 | minHeight: constraint.minHeight as number, | 225 | minHeight: constraint.minHeight as number, |
| 234 | maxWidth: constraint.maxWidth as number, | 226 | maxWidth: constraint.maxWidth as number, |
| 235 | maxHeight: constraint.maxHeight as number, | 227 | maxHeight: constraint.maxHeight as number, |
| 236 | - }) | 228 | + }); |
| 237 | - this.lastChangeFlag = false; | ||
| 238 | - this.lastChangeTime = currentTime; | ||
| 239 | } else { | 229 | } else { |
| 240 | - if (this.timerId) { | 230 | + clearTimeout(this.timerId); |
| 241 | - clearTimeout(this.timerId) | ||
| 242 | - this.timerId = undefined; | ||
| 243 | - } | ||
| 244 | this.timerId = setTimeout(() =>{ | 231 | this.timerId = setTimeout(() =>{ |
| 245 | this.currentMeasuredSize = | 232 | this.currentMeasuredSize = |
| 246 | - this.updateSurfaceConstraints({ | 233 | + this.updateSurfaceConstraints({ |
| 247 | - minWidth: constraint.maxWidth as number, // NOTE: width: 100% doesn't work on the root component hence maxWidth is used here | 234 | + minWidth: constraint.maxWidth as number, // NOTE: width: 100% doesn't work on the root component hence maxWidth is used here |
| 248 | - minHeight: constraint.minHeight as number, | 235 | + minHeight: constraint.minHeight as number, |
| 249 | - maxWidth: constraint.maxWidth as number, | 236 | + maxWidth: constraint.maxWidth as number, |
| 250 | - maxHeight: constraint.maxHeight as number, | 237 | + maxHeight: constraint.maxHeight as number, |
| 251 | - }) | 238 | + }); |
| 252 | - this.timerId = undefined; | 239 | + }, this.delayTime); |
| 253 | - this.lastChangeFlag = true; | ||
| 254 | - this.lastChangeTime = Date.now(); | ||
| 255 | - }, this.delayTime) | ||
| 256 | } | 240 | } |
| 257 | const measuredSize = this.currentMeasuredSize; | 241 | const measuredSize = this.currentMeasuredSize; |
| 258 | const newSize: Size = | 242 | const newSize: Size = |
| @@ -263,8 +247,8 @@ struct ContentAdaptiveSurface { | |||
| 263 | minWidth: newSize.width, | 247 | minWidth: newSize.width, |
| 264 | maxWidth: newSize.width, | 248 | maxWidth: newSize.width, |
| 265 | maxHeight: newSize.height | 249 | maxHeight: newSize.height |
| 266 | - }) | 250 | + }); |
| 267 | - }) | 251 | + }); |
| 268 | return newSize; | 252 | return newSize; |
| 269 | } | 253 | } |
| 270 | 254 | ||
| @@ -355,10 +339,6 @@ struct ParentBoundSurface { | |||
| 355 | private logger!: RNOHLogger | 339 | private logger!: RNOHLogger |
| 356 | private rootViewNodeContent: NodeContent = new NodeContent(); | 340 | private rootViewNodeContent: NodeContent = new NodeContent(); |
| 357 | private timerId: undefined | number = undefined; | 341 | private timerId: undefined | number = undefined; |
| 358 | - private lastChangeTime: number = 0; | ||
| 359 | - private isWindowRectDrag: boolean = false; | ||
| 360 | - private currentMeasuredSize: Size | undefined = undefined; | ||
| 361 | - private lastChangeFlag: boolean = false; | ||
| 362 | /** | 342 | /** |
| 363 | * Note: You may need to change this delay along with RNInstancesCoordinator's | 343 | * Note: You may need to change this delay along with RNInstancesCoordinator's |
| 364 | * onWindowSizeChange delay, as both have an effect on window changes. | 344 | * onWindowSizeChange delay, as both have an effect on window changes. |
| @@ -396,12 +376,6 @@ struct ParentBoundSurface { | |||
| 396 | tag, | 376 | tag, |
| 397 | (newDescriptor) => this.onUpdateComponent(newDescriptor) | 377 | (newDescriptor) => this.onUpdateComponent(newDescriptor) |
| 398 | )) | 378 | )) |
| 399 | - this.cleanUpCallbacks.push( | ||
| 400 | - this.ctx.rnInstance.subscribeToLifecycleEvents("WINDOW_REACT_DRAG", | ||
| 401 | - (isWindowRectDrag: boolean) => { | ||
| 402 | - this.isWindowRectDrag = isWindowRectDrag; | ||
| 403 | - }) | ||
| 404 | - ) | ||
| 405 | this.surfaceHandle.attachRootView(this.ctx.rnInstance.getId(), this.surfaceHandle.getTag(), | 379 | this.surfaceHandle.attachRootView(this.ctx.rnInstance.getId(), this.surfaceHandle.getTag(), |
| 406 | this.rootViewNodeContent); | 380 | this.rootViewNodeContent); |
| 407 | stopTracing() | 381 | stopTracing() |
| @@ -7,7 +7,7 @@ | |||
| 7 | 7 | ||
| 8 | import {TestSuite} from '@rnoh/testerino'; | 8 | import {TestSuite} from '@rnoh/testerino'; |
| 9 | import React, {useState, useEffect} from 'react'; | 9 | import React, {useState, useEffect} from 'react'; |
| 10 | -import {Text, StyleSheet, Dimensions} from 'react-native'; | 10 | +import {Text, StyleSheet, Dimensions, View} from 'react-native'; |
| 11 | import {TestCase} from '../components'; | 11 | import {TestCase} from '../components'; |
| 12 | 12 | ||
| 13 | export function DimensionsTest() { | 13 | export function DimensionsTest() { |
| @@ -64,9 +64,26 @@ export function DimensionsTest() { | |||
| 64 | Screen dimensions: {JSON.stringify(screenDimensions)} | 64 | Screen dimensions: {JSON.stringify(screenDimensions)} |
| 65 | </Text> | 65 | </Text> |
| 66 | </TestCase.Example> | 66 | </TestCase.Example> |
| 67 | + <TestCase.Example itShould="prevent continuous triggering of onLayout during window drag."> | ||
| 68 | + <DragingWindowExample /> | ||
| 69 | + </TestCase.Example> | ||
| 67 | </TestSuite> | 70 | </TestSuite> |
| 68 | ); | 71 | ); |
| 69 | } | 72 | } |
| 73 | + | ||
| 74 | +const DragingWindowExample = () => { | ||
| 75 | + const [time, setTime] = useState(0); | ||
| 76 | + return ( | ||
| 77 | + <View | ||
| 78 | + style={{width: '100%', height: 20}} | ||
| 79 | + onLayout={() => { | ||
| 80 | + setTime(prev => prev + 1); | ||
| 81 | + }}> | ||
| 82 | + <Text>onLayout: {time}</Text> | ||
| 83 | + </View> | ||
| 84 | + ); | ||
| 85 | +}; | ||
| 86 | + | ||
| 70 | const styles = StyleSheet.create({ | 87 | const styles = StyleSheet.create({ |
| 71 | text: { | 88 | text: { |
| 72 | fontSize: 14, | 89 | fontSize: 14, |