已合并
fix: window jitter after dragging. #1464
fix: window jitter after dragging. #1464
已合并
xiedairong创建于 2025年8月25日
共 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';
29import { I18nManagerTurboModule } from './RNOHCorePackage/turboModules';29import { I18nManagerTurboModule } from './RNOHCorePackage/turboModules';
30import type { SurfaceContext } from './RNOH/RNInstance';30import type { SurfaceContext } from './RNOH/RNInstance';
31import { NodeContent } from '@ohos.arkui.node'31import { NodeContent } from '@ohos.arkui.node'
32-import { window } from '@kit.ArkUI';
33 32 
34interface RootViewState {}33interface RootViewState {}
35 34 
@@ -114,10 +113,8 @@ struct ContentAdaptiveSurface {
114 private logger!: RNOHLogger113 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 here224 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 here234+ 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.height249 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!: RNOHLogger339 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 
8import {TestSuite} from '@rnoh/testerino';8import {TestSuite} from '@rnoh/testerino';
9import React, {useState, useEffect} from 'react';9import React, {useState, useEffect} from 'react';
10-import {Text, StyleSheet, Dimensions} from 'react-native';10+import {Text, StyleSheet, Dimensions, View} from 'react-native';
11import {TestCase} from '../components';11import {TestCase} from '../components';
12 12 
13export function DimensionsTest() {13export 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+ 
70const styles = StyleSheet.create({87const styles = StyleSheet.create({
71 text: {88 text: {
72 fontSize: 14,89 fontSize: 14,