Flutter null 安全迁移错误 Null check operator used on a null value - occurred at PageTransformer ScrollMetrics object

Flutter null safety migration error Null check operator used on a null value - occured at PageTransformer ScrollMetrics object

我使用 github repo page-transformer 在 Flutter 中实现了 PageView 视差效果。 Null 安全迁移后,我面临以下错误。

======== Exception caught by widgets library =======================================================
The following _CastError was thrown building PageTransformer(dirty, state: _PageTransformerState#a4851):
Null check operator used on a null value

本人对Dart和Flutter比较陌生,对ScrollMetrics知之甚少

下面是page_transformer.dart

的代码文件
import 'package:flutter/material.dart';
import 'package:meta/meta.dart';

/// A function that builds a [PageView] lazily.
typedef PageView PageViewBuilder(
BuildContext context, PageVisibilityResolver visibilityResolver);

/// A class that can be used to compute visibility information about
/// the current page.
class PageVisibilityResolver {
  PageVisibilityResolver({
    ScrollMetrics? metrics,
    double? viewPortFraction,
  }) : this._pageMetrics = metrics!, //Error here <----- When the exception was thrown, this was the stack: #0 new PageVisibilityResolver
       this._viewPortFraction = viewPortFraction!;

  final ScrollMetrics _pageMetrics;
  final double _viewPortFraction;

  PageVisibility resolvePageVisibility(int pageIndex) {
    final double pagePosition = _calculatePagePosition(pageIndex);
    final double visiblePageFraction =
        _calculateVisiblePageFraction(pageIndex, pagePosition);

    return PageVisibility(
      visibleFraction: visiblePageFraction,
      pagePosition: pagePosition,
    );
  }

  double _calculateVisiblePageFraction(int index, double pagePosition) {
    if (pagePosition > -1.0 && pagePosition <= 1.0) {
      return 1.0 - pagePosition.abs();
    }

    return 0.0;
  }

  double _calculatePagePosition(int index) {
    final double viewPortFraction = _viewPortFraction ?? 1.0;
    final double pageViewWidth =
        (_pageMetrics?.viewportDimension ?? 1.0) * viewPortFraction;
    final double pageX = pageViewWidth * index;
    final double scrollX = (_pageMetrics?.pixels ?? 0.0);
    final double pagePosition = (pageX - scrollX) / pageViewWidth;
    final double safePagePosition = !pagePosition.isNaN ? pagePosition : 0.0;

    if (safePagePosition > 1.0) {
      return 1.0;
    } else if (safePagePosition < -1.0) {
      return -1.0;
    }

    return safePagePosition;
  }
}

 /// A class that contains visibility information about the current page.
  class PageVisibility {
    PageVisibility({
      required this.visibleFraction,
      required this.pagePosition,
    });

  final double visibleFraction;
  final double pagePosition;
}

class PageTransformer extends StatefulWidget {
  PageTransformer({
    required this.pageViewBuilder,
  });

  final PageViewBuilder pageViewBuilder;

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

class _PageTransformerState extends State<PageTransformer> {
  PageVisibilityResolver? _visibilityResolver;

  @override
  Widget build(BuildContext context) {
    final pageView = widget.pageViewBuilder(
        context, _visibilityResolver ?? PageVisibilityResolver());

    final controller = pageView.controller;
    final viewPortFraction = controller.viewportFraction;

    return NotificationListener<ScrollNotification>(
      onNotification: (ScrollNotification notification) {
        setState(() {
          _visibilityResolver = PageVisibilityResolver(
            metrics: notification.metrics,
            viewPortFraction: viewPortFraction,
          );
        });
        return false;     //need a check
      },
      child: pageView,
    );
  }
}

下面是intro_page_view.dart

的代码文件
import 'dart:math';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:tailor_ai/screens/main/main_page.dart';
import 'package:tailor_ai/screens/product/product_page.dart';
import 'package:flutter/material.dart';
import 'package:tailor_ai/models/product.dart';
import 'page_transformer.dart';
import 'intro_page_item.dart';

class IntroPageView extends StatelessWidget {
  final List<Product>? product;
  final _controller = new PageController(viewportFraction: 0.85);
  static const _kDuration = const Duration(milliseconds: 300);
  static const _kCurve = Curves.ease;
  final _kArrowColor = Colors.black.withOpacity(0.8);
  IntroPageView({Key? key,this.product}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: SizedBox.fromSize(
          size: const Size.fromHeight(500.0),
          child: PageTransformer(         //<-------------- The relevant error-causing widget was: PageTransformer PageTransformer
            pageViewBuilder: (context, visibilityResolver) {
              return PageView.builder(
                controller: _controller,
                itemCount: product!.length,
                itemBuilder: (context, index) {
                  //final item = product;
                  final pageVisibility =
                      visibilityResolver.resolvePageVisibility(index);
                  return InkWell(
                    onTap: () => Navigator.of(context)
                        .push(MaterialPageRoute(builder: (_) => ProductPage(
                        product: product![index]

                    ))),
                    child: Stack(
                      children: <Widget>[
                        IntroPageItem(product: product![index], pageVisibility: pageVisibility),
                      ],
                    ),
                  );
                },
              );
            },
          ),
        ),
      ),
    );
  }
}

您可以在上面提到的 github link 中找到 page_transformer 项目的完整代码文件,它没有针对空安全进行更新。

terminal screenshot for reference

非常感谢您宝贵的时间回复。

这是问题所在,您有这个变量:final ScrollMetrics _pageMetrics;,它 不可为空 ,在初始化时,您将它分配给另一个变量 ScrollMetrics? metrics ,其中 可以为 null。你得到的错误发生是因为 metrics 是空的,你试图将它分配给 _pageMetrics.

那么为什么 metrics 为空?嗯,你应该在构造函数上传递指标的值,但你没有在这一行:

final pageView = widget.pageViewBuilder(
        context, _visibilityResolver ?? PageVisibilityResolver());

因此解决方案是使 _pageMetrics 可为空或将 metrics 传递给构造函数。

专业提示:当您的构造函数中有一个应始终传递的命名参数时(也就是说,它应该永远不会为空) 您可以使用 required 关键字:

PageVisibilityResolver({
    required ScrollMetrics metrics,
    required double viewPortFraction,
  }) : this._pageMetrics = metrics, 
       this._viewPortFraction = viewPortFraction;

当然你也可以给他们一个默认值。