I implemented PageView parallax effects in Flutter using github repo page-transformer . After Null safety migration I am facing the error below.
======== Exception caught by widgets library =======================================================
The following _CastError was thrown building PageTransformer(dirty, state: _PageTransformerState#a4851):
Null check operator used on a null value
I am relatively new to Dart and Flutter, and I know very little about ScrollMetrics
Below is the code file of 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,
);
}
}
Below is the code file of 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),
],
),
);
},
);
},
),
),
),
);
}
}
you can find the entire code files for page_transformer project in above mentioned github link which is not updated for null safety.
terminal screenshot for reference
Your valuable time in response would be much appreciated.
CodePudding user response:
Here is the problem, you have this variable: final ScrollMetrics _pageMetrics;
which is not nullable, on initialization, you assign it to this other variable ScrollMetrics? metrics
, which is nullable. The error you get happened because metrics
was null and you tried to assign it to _pageMetrics
.
So why is metrics
null? Well, you are supposed to pass the value of metrics on the constructor, but you didn't on this line:
final pageView = widget.pageViewBuilder(
context, _visibilityResolver ?? PageVisibilityResolver());
So the solution is to either make _pageMetrics
nullable or to pass metrics
to the constructor.
Pro tip: When you have a named parameter on your constructor that should always be passed (that is to say, it should never be null) you can use the required
keyword:
PageVisibilityResolver({
required ScrollMetrics metrics,
required double viewPortFraction,
}) : this._pageMetrics = metrics,
this._viewPortFraction = viewPortFraction;
Of course you could also give them a default value.