DidChangeMetrics Has Bug
问题描述
在使用 WebF
库时,遇到一个问题。在 Page
组件中使用 WebF
控制器,能够正常显示 HTML 布局,并且可以通过键盘调整布局。但是,当返回到 Page
组件时,会出现 A disposed RenderObject was mutated
的错误。
错误信息
[ERROR:flutter/runtime/dart_vm_initializer.cc(40)] Unhandled Exception: A disposed RenderObject was mutated.
The disposed RenderObject was:
RenderViewportBox#fb351 DISPOSED
#0 RenderObject._debugCanPerformMutations.<anonymous closure> (package:flutter/src/rendering/object.dart:1987:9)
#1 RenderObject._debugCanPerformMutations (package:flutter/src/rendering/object.dart:2095:6)
#2 RenderObject.markNeedsLayout (package:flutter/src/rendering/object.dart:2327:12)
#3 RenderBox.markNeedsLayout (package:flutter/src/rendering/box.dart:2669:11)
#4 RenderViewportBox.bottomInset= (package:webf/src/rendering/viewport.dart:59:7)
#5 WebFViewController.didChangeMetrics (package:webf/src/launcher/controller.dart:808:15)
#6 WidgetsBinding.handleMetricsChanged (package:flutter/src/widgets/binding.dart:755:16)
#7 _invoke (dart:ui/hooks.dart:312:13)
#8 PlatformDispatcher._updateWindowMetrics (dart:ui/platform_dispatcher.dart:316:5)
#9 _updateWindowMetrics (dart:ui/hooks<…>
问题原因
问题的原因是 didChangeMetrics
方法中,尝试访问已经被销毁的 RenderObject
。具体来说,是 viewport?.bottomInset = bottomInsets;
这一行代码引起了问题。
解决方案
为了解决这个问题,我们需要在 didChangeMetrics
方法中,检查 viewport
是否为 null 之前,才尝试访问它的 bottomInset
属性。
@override
void didChangeMetrics() {
final ownerView = rootController.ownerFlutterView;
final bool resizeToAvoidBottomInsets = rootController.resizeToAvoidBottomInsets;
final double bottomInsets;
if (resizeToAvoidBottomInsets) {
bottomInsets = ownerView.viewInsets.bottom / ownerView.devicePixelRatio;
} else {
bottomInsets = 0;
}
if (resizeToAvoidBottomInsets && viewport?.hasSize == true) {
bool shouldScrollByToCenter = false;
Element? focusedElement = document.focusedElement;
double scrollOffset = 0;
if (focusedElement != null) {
RenderBox? renderer = focusedElement.renderer;
if (renderer != null && renderer.attached && renderer.hasSize) {
Offset focusOffset = renderer.localToGlobal(Offset.zero);
// FOCUS_VIEWINSET_BOTTOM_OVERALL to meet border case.
if (focusOffset.dy > viewport!.size.height - bottomInsets - FOCUS_VIEWINSET_BOTTOM_OVERALL) {
shouldScrollByToCenter = true;
scrollOffset =
focusOffset.dy - (viewport!.size.height - bottomInsets) + renderer.size.height + FOCUS_VIEWINSET_BOTTOM_OVERALL;
}
}
}
// Show keyboard
if (shouldScrollByToCenter) {
window.scrollBy(0, scrollOffset, false);
}
}
window.resizeViewportRelatedElements();
if (viewport != null) {
viewport.bottomInset = bottomInsets;
}
}
其他问题
在 WebF
库中,遇到另一个问题。在 WebFController
中,尝试访问 view.document.documentElement!.applyStyle(view.document.documentElement!.style);
时,会出现 Null check operator used on a null value
的错误。
// Manually initialize the root element and create renderObjects for each elements.
view.document.documentElement!.applyStyle(view.document.documentElement!.style);
解决方案
为了解决这个问题,我们需要检查 view.document.documentElement
是否为 null 之前,才尝试访问它的 applyStyle
方法。
// Manually initialize the root element and create renderObjects for each elements.
if (view.document.documentElement != null) {
view.document.documentElement!.applyStyle(view.document.documentElement!.style);
}
总结
问题描述
在使用 WebF
库时,遇到一个问题。在 Page
组件中使用 WebF
控制器,能够正常显示 HTML 布局,并且可以通过键盘调整布局。但是,当返回到 Page
组件时,会出现 A disposed RenderObject was mutated
的错误。
错误信息
[ERROR:flutter/runtime/dart_vm_initializer.cc(40)] Unhandled Exception: A disposed RenderObject was mutated.
The disposed RenderObject was:
RenderViewportBox#fb351 DISPOSED
#0 RenderObject._debugCanPerformMutations.<anonymous closure> (package:flutter/src/rendering/object.dart:1987:9)
#1 RenderObject._debugCanPerformMutations (package:flutter/src/rendering/object.dart:2095:6)
#2 RenderObject.markNeedsLayout (package:flutter/src/rendering/object.dart:2327:12)
#3 RenderBox.markNeedsLayout (package:flutter/src/rendering/box.dart:2669:11)
#4 RenderViewportBox.bottomInset= (package:webf/src/rendering/viewport.dart:59:7)
#5 WebFViewController.didChangeMetrics (package:webf/src/launcher/controller.dart:808:15)
#6 WidgetsBinding.handleMetricsChanged (package:flutter/src/widgets/binding.dart:755:16)
#7 _invoke (dart:ui/hooks.dart:312:13)
#8 PlatformDispatcher._updateWindowMetrics (dart:ui/platform_dispatcher.dart:316:5)
#9 _updateWindowMetrics (dart:ui/hooks<…>
问题原因
问题的原因是 didChangeMetrics
方法中,尝试访问已经被销毁的 RenderObject
。具体来说,是 viewport?.bottomInset = bottomInsets;
这一行代码引起了问题。
解决方案
为了解决这个问题,我们需要在 didChangeMetrics
方法中,检查 viewport
是否为 null 之前,才尝试访问它的 bottomInset
属性。
@override
void didChangeMetrics() {
final ownerView = rootController.ownerFlutterView;
final bool resizeToAvoidBottomInsets = rootController.resizeToAvoidBottomInsets;
final double bottomInsets;
if (resizeToAvoidBottomInsets) {
bottomInsets = ownerView.viewInsets.bottom / ownerView.devicePixelRatio;
} else {
bottomInsets = 0;
}
if (resizeToAvoidBottomInsets && viewport?.hasSize == true) {
bool shouldScrollByToCenter = false;
Element? focusedElement = document.focusedElement;
double scrollOffset = 0;
if (focusedElement != null) {
RenderBox? renderer = focusedElement.renderer;
if (renderer != null && renderer.attached && renderer.hasSize) {
Offset focusOffset = renderer.localToGlobal(Offset.zero);
// FOCUS_VIEWINSET_BOTTOM_OVERALL to meet border case.
if (focusOffset.dy > viewport!.size.height - bottomInsets - FOCUS_VIEWINSET_BOTTOM_OVERALL) {
shouldScrollByToCenter = true;
scrollOffset =
focusOffset.dy - (viewport!.size.height - bottomInsets) + renderer.size.height + FOCUS_VIEWINSET_BOTTOM_OVERALL;
}
}
}
// Show keyboard
if (shouldScrollByToCenter) {
window.scrollBy(0, scrollOffset, false);
}
}
window.resizeViewportRelatedElements();
if (viewport != null) {
viewport.bottomInset = bottomInsets;
}
}
其他问题
在 WebF
库中,遇到另一个问题。在 WebFController
中,尝试访问 view.document.documentElement!.applyStyle(view.document.documentElement!.style);
时,会出现 Null check operator used on a null value
的错误。
// Manually initialize the root element and create renderObjects for each elements.
view.document.documentElement!.applyStyle(view.document.documentElement!.style);
解决方案
为了解决这个问题,我们需要检查 view.document.documentElement
是否为 null 之前,才尝试访问它的 applyStyle
方法。
// Manually initialize the root element and create renderObjects for each elements.
if (view.document.documentElement != null) {
view.document.documentElement!.applyStyle(view.document.documentElement!.style);
}
Q&A
Q: 什么是 didChangeMetrics
方法?
A: didChangeMetrics
方法是 WebF
库中一个重要的方法,它用于处理窗口大小和位置的变化。
Q: 为什么会出现 A disposed RenderObject was mutated
的错误?
A: 这个错误是因为 didChangeMetrics
方法中,尝试访问已经被销毁的 RenderObject
。
Q: 如何解决这个问题?
A: 需要在 didChangeMetrics
方法中,检查 viewport
是否为 null 之前,才尝试访问它的 bottomInset
属性。
Q: 在 WebFController
中,尝试访问 view.document.documentElement!.applyStyle(view.document.documentElement!.style);
时,会出现 Null check operator used on a null value
的错误。如何解决这个问题?
A: 需要检查 view.document.documentElement
是否为 null 之前,才尝试访问它的 applyStyle
方法。
Q: WebF
库中,遇到哪些其他问题?
A: 在 WebF
库中,遇到其他问题,例如 Null check operator used on a null value
的错误。
Q: 如何解决这些问题? A: 需要检查相关的属性或方法是否为 null 之前,才尝试访问它们。