dart Flink 效果导致Flutter中重建异常

9cbw7uwe  于 5个月前  发布在  Flink
关注(0)|答案(1)|浏览(69)

我遵循Flutter团队的官方教程创建微光效果:Create a shimmer loading effect
我将大部分代码复制到一个文件中,并更新了一些行,例如自定义颜色:

LinearGradient scGradient(BuildContext context) {
  SCThemeData theme = SCTheme.of(context);

  return LinearGradient(
    colors: [
      theme.colors.shimmerBackground,
      theme.colors.shimmerLine,
      theme.colors.shimmerBackground
    ],
    stops: const [
      0.1,
      0.3,
      0.4,
    ],
    begin: const Alignment(-1.0, -0.3),
    end: const Alignment(1.0, 0.3),
    tileMode: TileMode.clamp,
  );
}

class SCShimmerLoading extends StatefulWidget {
  const SCShimmerLoading({
    super.key,
    required this.isLoading,
    required this.child,
  });

  final bool isLoading;
  final Widget child;

  @override
  State<SCShimmerLoading> createState() => _SCShimmerLoadingState();
}

class _SCShimmerLoadingState extends State<SCShimmerLoading> {
  Listenable? _shimmerChanges;

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    if (_shimmerChanges != null) {
      _shimmerChanges!.removeListener(_onShimmerChange);
    }
    _shimmerChanges = SCShimmer.of(context)?.shimmerChanges;
    if (_shimmerChanges != null) {
      _shimmerChanges!.addListener(_onShimmerChange);
    }
  }

  @override
  void dispose() {
    _shimmerChanges?.removeListener(_onShimmerChange);
    super.dispose();
  }

  void _onShimmerChange() {
    if (widget.isLoading) {
      setState(() {
        // update the shimmer painting.
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    if (!widget.isLoading) {
      return widget.child;
    }

    final shimmer = SCShimmer.of(context)!;
    if (!shimmer.isSized) {
      // The ancestor Shimmer widget isn’t laid
      // out yet. Return an empty box.
      return const SizedBox();
    }
    final shimmerSize = shimmer.size;
    final gradient = shimmer.gradient;
    final offsetWithinShimmer = shimmer.getDescendantOffset(
      descendant: context.findRenderObject() as RenderBox,
    );

    return ShaderMask(
      blendMode: BlendMode.srcATop,
      shaderCallback: (bounds) {
        return gradient.createShader(
          Rect.fromLTWH(
            -offsetWithinShimmer.dx,
            -offsetWithinShimmer.dy,
            shimmerSize.width,
            shimmerSize.height,
          ),
        );
      },
      child: widget.child,
    );
  }
}

class SCShimmer extends StatefulWidget {
  static SCShimmerState? of(BuildContext context) {
    return context.findAncestorStateOfType<SCShimmerState>();
  }

  const SCShimmer({
    super.key,
    required this.linearGradient,
    this.child,
  });

  final LinearGradient linearGradient;
  final Widget? child;

  @override
  SCShimmerState createState() => SCShimmerState();
}

class SCShimmerState extends State<SCShimmer>
    with SingleTickerProviderStateMixin {
  late AnimationController _shimmerController;

  @override
  void initState() {
    super.initState();

    _shimmerController = AnimationController.unbounded(vsync: this)
      ..repeat(
        min: -0.5,
        max: 1.5,
        period: const Duration(milliseconds: 1000),
      );
  }

  @override
  void dispose() {
    _shimmerController.dispose();
    super.dispose();
  }

  Gradient get gradient => LinearGradient(
        colors: widget.linearGradient.colors,
        stops: widget.linearGradient.stops,
        begin: widget.linearGradient.begin,
        end: widget.linearGradient.end,
        transform: _SCSlidingGradientTransform(
          slidePercent: _shimmerController.value,
        ),
      );

  Listenable get shimmerChanges => _shimmerController;

  bool get isSized =>
      (context.findRenderObject() as RenderBox?)?.hasSize ?? false;

  Size get size => (context.findRenderObject() as RenderBox).size;

  Offset getDescendantOffset({
    required RenderBox descendant,
    Offset offset = Offset.zero,
  }) {
    final shimmerBox = context.findRenderObject() as RenderBox;
    return descendant.localToGlobal(offset, ancestor: shimmerBox);
  }

  @override
  Widget build(BuildContext context) {
    return widget.child ?? const SizedBox();
  }
}

class _SCSlidingGradientTransform extends GradientTransform {
  const _SCSlidingGradientTransform({
    required this.slidePercent,
  });

  final double slidePercent;

  @override
  Matrix4? transform(Rect bounds, {TextDirection? textDirection}) {
    return Matrix4.translationValues(bounds.width * slidePercent, 0.0, 0.0);
  }
}

class SCShimmerLoadingBox extends StatelessWidget {
  const SCShimmerLoadingBox({
    super.key,
    required this.size,
    this.borderRadius,
  });

  final Size size;
  final double? borderRadius;

  @override
  Widget build(BuildContext context) {
    return Container(
      width: size.width,
      height: size.height,
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(borderRadius ?? size.height / 2.0),
        color: Colors.black,
      ),
    );
  }
}

字符串
然后我使用它,例如,每当TextField中的文本发生变化时,从API获取新结果时,显示微光加载效果:

class _LocationPageState extends ConsumerState<LocationPage> {
    
  @override
  Widget build(BuildContext context) {    
  final AsyncValue<List<LocalLocation>> locationsValue = ref.watch(fetchLocalLocationsProvider);
    
  return SCShimmer(
    linearGradient: scGradient(context),
      child: SCScaffold(
        body: searchValue.when(
          data: (List<LocationModel> locations) => ...
          error: (Object e, StackTrace s) => ..., 
          loading: () => SCShimmerLoading(
            isLoading: true, 
            child: ListView.builder(
              itemCount: 3,
              itemBuilder: (BuildContext context, int index) => SCPadding(
                padding: const SCEdgeInsets.symmetric(vertical: SCGapSize.regular),
                child: Column(
                  children: [
                    SCShimmerLoadingBox(
                      size: Size(
                        MediaQuery.of(context).size.width - 2.0 * SCGapSize.semiBig.getSpacing(theme), 
                        14.0,
                      ),
                      borderRadius: 7.0
                    ),
                      ...
                    ],
                  ),
                ),
              ),
            ),
          ),
        ),
      ),
    );
  }
}


无论出于何种原因,它总是抛出以下异常每次微光效果重建/得到再次显示后,最初显示它:

══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY
╞═══════════════════════════════════════════════════════════ The
following _TypeError was thrown building SCShimmerLoading(dirty,
state:
_SCShimmerLoadingState#d5a76): type 'Null' is not a subtype of type 'RenderBox' in type cast

The relevant error-causing widget was:   SCShimmerLoading  
SCShimmerLoading:file:///Users/fleeser/Desktop/scial_app/sci  
al_app_ui/lib/src/widgets/location/sc_location_loading.dart:   18:12

When the exception was thrown, this was the stack:
#0      _SCShimmerLoadingState.build (package:scial_app_ui/src/widgets/base/sc_shimmer.dart:84:46)
#1      StatefulElement.build (package:flutter/src/widgets/framework.dart:5198:27)
#2      ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:5086:15)
#3      StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:5251:11)
#4      Element.rebuild (package:flutter/src/widgets/framework.dart:4805:7)
#5      ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:5068:5)
#6      StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:5242:11)
#7      ComponentElement.mount (package:flutter/src/widgets/framework.dart:5062:5) ... Normal element mounting (7 frames)
#14     Element.inflateWidget (package:flutter/src/widgets/framework.dart:3971:16)
#15     Element.updateChild (package:flutter/src/widgets/framework.dart:3702:20)
#16     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:5111:16)
#17     Element.rebuild (package:flutter/src/widgets/framework.dart:4805:7)
#18     StatelessElement.update (package:flutter/src/widgets/framework.dart:5162:5)
#19     Element.updateChild (package:flutter/src/widgets/framework.dart:3686:15)
#20     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:5111:16)
#21     Element.rebuild (package:flutter/src/widgets/framework.dart:4805:7)
#22     StatelessElement.update (package:flutter/src/widgets/framework.dart:5162:5)
#23     Element.updateChild (package:flutter/src/widgets/framework.dart:3686:15)
#24     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:5111:16)
#25     Element.rebuild (package:flutter/src/widgets/framework.dart:4805:7)
#26     ProxyElement.update (package:flutter/src/widgets/framework.dart:5417:5)
#27     Element.updateChild (package:flutter/src/widgets/framework.dart:3686:15)
#28     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:5111:16)
#29     Element.rebuild (package:flutter/src/widgets/framework.dart:4805:7)
#30     ProxyElement.update (package:flutter/src/widgets/framework.dart:5417:5)
#31     Element.updateChild (package:flutter/src/widgets/framework.dart:3686:15)
#32     RenderObjectElement.updateChildren (package:flutter/src/widgets/framework.dart:6093:32)
#33     MultiChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:6595:17)
#34     Element.updateChild (package:flutter/src/widgets/framework.dart:3686:15)
#35     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:5111:16)
#36     Element.rebuild (package:flutter/src/widgets/framework.dart:4805:7)
#37     ProxyElement.update (package:flutter/src/widgets/framework.dart:5417:5)
#38     Element.updateChild (package:flutter/src/widgets/framework.dart:3686:15)
#39     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:5111:16)
#40     StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:5251:11)
#41     Element.rebuild (package:flutter/src/widgets/framework.dart:4805:7)
#42     StatefulElement.update (package:flutter/src/widgets/framework.dart:5274:5)
#43     Element.updateChild (package:flutter/src/widgets/framework.dart:3686:15)
#44     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:5111:16)
#45     StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:5251:11)
#46     Element.rebuild (package:flutter/src/widgets/framework.dart:4805:7)
#47     StatefulElement.update (package:flutter/src/widgets/framework.dart:5274:5)
#48     Element.updateChild (package:flutter/src/widgets/framework.dart:3686:15)
#49     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:5111:16)
#50     Element.rebuild (package:flutter/src/widgets/framework.dart:4805:7)
#51     ProxyElement.update (package:flutter/src/widgets/framework.dart:5417:5)
#52     Element.updateChild (package:flutter/src/widgets/framework.dart:3686:15)
#53     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:5111:16)
#54     StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:5251:11)
#55     Element.rebuild (package:flutter/src/widgets/framework.dart:4805:7)
#56     StatefulElement.update (package:flutter/src/widgets/framework.dart:5274:5)
#57     Element.updateChild (package:flutter/src/widgets/framework.dart:3686:15)
#58     SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:6442:14)
#59     Element.updateChild (package:flutter/src/widgets/framework.dart:3686:15)
#60     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:5111:16)
#61     Element.rebuild (package:flutter/src/widgets/framework.dart:4805:7)
#62     ProxyElement.update (package:flutter/src/widgets/framework.dart:5417:5)
#63     Element.updateChild (package:flutter/src/widgets/framework.dart:3686:15)
#64     SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:6442:14)
#65     Element.updateChild (package:flutter/src/widgets/framework.dart:3686:15)
#66     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:5111:16)
#67     StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:5251:11)
#68     Element.rebuild (package:flutter/src/widgets/framework.dart:4805:7)
#69     StatefulElement.update (package:flutter/src/widgets/framework.dart:5274:5)
#70     Element.updateChild (package:flutter/src/widgets/framework.dart:3686:15)
#71     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:5111:16)
#72     StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:5251:11)
#73     Element.rebuild (package:flutter/src/widgets/framework.dart:4805:7)
#74     StatefulElement.update (package:flutter/src/widgets/framework.dart:5274:5)
#75     Element.updateChild (package:flutter/src/widgets/framework.dart:3686:15)
#76     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:5111:16)
#77     Element.rebuild (package:flutter/src/widgets/framework.dart:4805:7)
#78     ProxyElement.update (package:flutter/src/widgets/framework.dart:5417:5)
#79     Element.updateChild (package:flutter/src/widgets/framework.dart:3686:15)
#80     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:5111:16)
#81     Element.rebuild (package:flutter/src/widgets/framework.dart:4805:7)
#82     ProxyElement.update (package:flutter/src/widgets/framework.dart:5417:5)
#83     Element.updateChild (package:flutter/src/widgets/framework.dart:3686:15)
#84     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:5111:16)
#85     Element.rebuild (package:flutter/src/widgets/framework.dart:4805:7)
#86     ProxyElement.update (package:flutter/src/widgets/framework.dart:5417:5)
#87     Element.updateChild (package:flutter/src/widgets/framework.dart:3686:15)
#88     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:5111:16)
#89     StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:5251:11)
#90     Element.rebuild (package:flutter/src/widgets/framework.dart:4805:7)
#91     StatefulElement.update (package:flutter/src/widgets/framework.dart:5274:5)
#92     Element.updateChild (package:flutter/src/widgets/framework.dart:3686:15)
#93     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:5111:16)
#94     Element.rebuild (package:flutter/src/widgets/framework.dart:4805:7)
#95     ProxyElement.update (package:flutter/src/widgets/framework.dart:5417:5)
#96     Element.updateChild (package:flutter/src/widgets/framework.dart:3686:15)
#97     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:5111:16)
#98     StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:5251:11)
#99     Element.rebuild (package:flutter/src/widgets/framework.dart:4805:7)
#100    StatefulElement.update (package:flutter/src/widgets/framework.dart:5274:5)
#101    Element.updateChild (package:flutter/src/widgets/framework.dart:3686:15)
#102    SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:6442:14)
#103    Element.updateChild (package:flutter/src/widgets/framework.dart:3686:15)
#104    ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:5111:16)
#105    Element.rebuild (package:flutter/src/widgets/framework.dart:4805:7)
#106    StatelessElement.update (package:flutter/src/widgets/framework.dart:5162:5)
#107    Element.updateChild (package:flutter/src/widgets/framework.dart:3686:15)
#108    ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:5111:16)
#109    StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:5251:11)
#110    Element.rebuild (package:flutter/src/widgets/framework.dart:4805:7)
#111    StatefulElement.update (package:flutter/src/widgets/framework.dart:5274:5)
#112    Element.updateChild (package:flutter/src/widgets/framework.dart:3686:15)
#113    ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:5111:16)
#114    StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:5251:11)
#115    Element.rebuild (package:flutter/src/widgets/framework.dart:4805:7)
#116    BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2780:19)
#117    WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:903:21)
#118    RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:358:5)
#119    SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1284:15)
#120    SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1214:9)
#121    SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:1072:5)
#122    _invoke (dart:ui/hooks.dart:142:13)
#123    PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:359:5)
#124    _drawFrame (dart:ui/hooks.dart:112:31)

══════════════════════════════════════════════════════════════
══════════════════════════════════════

sg24os4d

sg24os4d1#

更换

final offsetWithinShimmer = shimmer.getDescendantOffset(
  descendant: context.findRenderObject() as RenderBox,
);

字符串

Offset offsetWithinShimmer = Offset.zero;
if(context.findRenderObject() != null) {
  final box = context.findRenderObject() as RenderBox;
  offsetWithinShimmer = shimmer.getDescendantOffset(
    descendant: box,
  );
}


解决了这个问题。
基于:https://github.com/flutter/website/issues/9372#issuecomment-1713651864

相关问题