Error: SliverGeometry has a paintOffset that exceeds the remainingPaintExtent from the constraints
813
Just use prepared SliverPersistentHeaderDelegate it works from the box...
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primarySwatch: Colors.teal,
canvasColor: Colors.transparent,
),
home: DemoScreen(),
);
}
}
class DemoScreen extends StatelessWidget {
static String id = '/demo';
int numberOfColumns(dynamic context) =>
((MediaQuery.of(context).size.width - (2 * kBigBoxPadding)) /
kMaxCrossAxisExtent)
.floor();
// Widget _buildGrid() => GridView.extent(
// maxCrossAxisExtent: kMaxCrossAxisExtent,
// padding: const EdgeInsets.all(4),
// mainAxisSpacing: 4,
// crossAxisSpacing: 4,
// children: _buildGridTileList(500));
List<Container> _buildGridTileList(dynamic context, int count) =>
List.generate(
count,
(i) => Container(
//NOTE: workaround according to: https://github.com/flutter/flutter/issues/25009
decoration: BoxDecoration(
color: colorBackground, //the color of the main container
border: Border.all(
//apply border to only that side where the line is appearing i.e. top | bottom | right | left.
width: 4, //depends on the width of the unintended line
color: colorBackground,
),
),
child: Container(
decoration: BoxDecoration(
color: colorBackground,
),
child: Center(
child: Text(
'$i / ${numberOfColumns(context)}',
style: TextStyle(color: Colors.grey),
//textAlign: TextAlign.center,
),
),
//margin: EdgeInsets.all(0),
),
));
// List<Widget> tabbarViewItems() {
// List<Widget> items = [];
// for (int i = 0; i < 25; i++) {
// Widget listView = _buildGrid();
// items.add(listView);
// }
// return items;
// }
List<Widget> listViewItems() {
List<Widget> items = [];
for (int i = 0; i < 500; i++) {
Widget widgetItem = Text(
'item $i',
textAlign: TextAlign.center,
style: TextStyle(color: Colors.white),
);
items.add(widgetItem);
}
return items;
}
@override
Widget build(BuildContext context) {
var topPadding = kCoverHeightProportion *
kCoverHeightProportion *
MediaQuery.of(context).size.height /
(kCoverHeightProportion *
(MediaQuery.of(context).size.height -
kBigBoxPadding -
kBottomBigBoxPadding));
return DefaultTabController(
length: 25,
child: Scaffold(
backgroundColor: colorBackground,
//floatingActionButton: MyTabBar(),
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
body: Stack(
children: [
Container(
width: double.infinity,
color: Colors.amber,
child: Image.network(
'https://images.unsplash.com/photo-1517248135467-4c7edcad34c4?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=2700&q=80',
fit: BoxFit.cover,
height:
MediaQuery.of(context).size.height * kCoverHeightProportion,
),
//color: Colors.green,
),
Align(
alignment: Alignment.bottomCenter,
child: Container(
height: 40,
width: 300,
color: Colors.red,
),
),
Align(
alignment: Alignment.bottomCenter,
child: Container(
margin: EdgeInsets.only(
left: kBigBoxPadding,
right: kBigBoxPadding,
top: kBigBoxPadding,
bottom: kBottomBigBoxPadding),
//width: MediaQuery.of(context).size.width * 0.9,
//margin: EdgeInsets.symmetric(horizontal: kBigBoxPadding),
decoration: BoxDecoration(
//color: Colors.pink,
borderRadius: BorderRadius.all(Radius.circular(30)),
),
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(30)),
child: CustomScrollView(
//physics: FixedExtentScrollPhysics(),
anchor: topPadding,
slivers: [
SliverPadding(
padding: EdgeInsets.only(
top: topPadding,
),
sliver: SliverPersistentHeader(
pinned: true,
floating: false,
delegate: _SliverPersistentHeaderDelegate(
Container(
width: double.infinity,
height: 100,
decoration: BoxDecoration(
color: colorBackground,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(30),
topRight: Radius.circular(30))),
child: Center(
child: Text(
'La casa de don Juan',
style: TextStyle(
color: colorPrimary1,
fontSize: 32,
fontWeight: FontWeight.w800),
),
),
),
),
),
),
SliverGrid.extent(
maxCrossAxisExtent: kMaxCrossAxisExtent,
childAspectRatio: 1,
mainAxisSpacing: 0,
crossAxisSpacing: 0,
children: _buildGridTileList(context, 250),
),
],
),
),
),
),
],
),
),
);
}
}
const Color colorShade1 = Color(0xFFEFF0F2);
const Color colorShade2 = Color(0xFF777777);
const Color colorShade3 = Color(0xFF424242);
const Color colorShade4 = Color(0xFF4B4935);
const Color colorShade5 = Color(0xFF3D2916);
const Color colorShade6 = Color(0xFF1D1C0A);
const Color colorBackground = Color(0xFF101A24);
const Color colorPrimary1 = Color(0xFFCC9757);
const double kTabIconHeight = 28;
const double kCoverHeightProportion = 0.35;
const double kBigBoxPadding = 8;
const double kBottomBigBoxPadding = 60;
const double kMaxCrossAxisExtent = 150;
class _SliverPersistentHeaderDelegate extends SliverPersistentHeaderDelegate {
_SliverPersistentHeaderDelegate(this.child);
final Widget child;
@override
Widget build(
BuildContext context, double shrinkOffset, bool overlapsContent) {
return child;
}
@override
double get maxExtent => 100;
@override
double get minExtent => 100;
@override
bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) => false;
}
Author by
Tomas Baran
Updated on December 23, 2022Comments
-
Tomas Baran 12 months
I get this error:
════════ Exception caught by rendering library ═════════════════════════════════ SliverGeometry has a paintOffset that exceeds the remainingPaintExtent from the constraints. The relevant error-causing widget was SliverAppBarLayer
It happens every time I scroll it up. The error is not visible on the screen, only in the console which also prevents me to do hot restart/hot reload. What does it mean? Why does it happen? How to fix it, please?
screenshot
my SliverWidget:
sliver_app_bar_layer.dart
import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; class SliverAppBarLayer extends SingleChildRenderObjectWidget { SliverAppBarLayer({Widget child, Key key}) : super(child: child, key: key); @override RenderObject createRenderObject(BuildContext context) { return RenderSliverAppBarLayer(); } } class RenderSliverAppBarLayer extends RenderSliverToBoxAdapter { RenderSliverAppBarLayer({ RenderBox child, }) : super(child: child); @override void performResize() {} @override void performLayout() { if (child == null) { geometry = SliverGeometry.zero; return; } final SliverConstraints constraints = this.constraints; child.layout(constraints.asBoxConstraints(/* crossAxisExtent: double.infinity */), parentUsesSize: true); double childExtent; switch (constraints.axis) { case Axis.horizontal: childExtent = child.size.width; break; case Axis.vertical: childExtent = child.size.height; break; } assert(childExtent != null); final double paintedChildSize = calculatePaintOffset(constraints, from: 0.0, to: childExtent); final double cacheExtent = calculateCacheOffset(constraints, from: 0.0, to: childExtent); assert(paintedChildSize.isFinite); assert(paintedChildSize >= 0.0); geometry = SliverGeometry( scrollExtent: 0, paintExtent: childExtent, paintOrigin: constraints.scrollOffset, cacheExtent: cacheExtent, maxPaintExtent: childExtent, hitTestExtent: paintedChildSize, ); setChildParentData(child, constraints, geometry); } }
main.dart
import 'package:flutter/material.dart'; import 'theme/style_constants.dart'; import 'widgets/sliver_app_bar_layer.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( theme: ThemeData( primarySwatch: Colors.teal, canvasColor: Colors.transparent, ), home: DemoScreen(), ); } } class DemoScreen extends StatelessWidget { static String id = '/demo'; int numberOfColumns(dynamic context) => ((MediaQuery.of(context).size.width - (2 * kBigBoxPadding)) / kMaxCrossAxisExtent).floor(); // Widget _buildGrid() => GridView.extent( // maxCrossAxisExtent: kMaxCrossAxisExtent, // padding: const EdgeInsets.all(4), // mainAxisSpacing: 4, // crossAxisSpacing: 4, // children: _buildGridTileList(500)); List<Container> _buildGridTileList(dynamic context, int count) => List.generate( count, (i) => Container( //NOTE: workaround according to: https://github.com/flutter/flutter/issues/25009 decoration: BoxDecoration( color: colorBackground, //the color of the main container border: Border.all( //apply border to only that side where the line is appearing i.e. top | bottom | right | left. width: 4, //depends on the width of the unintended line color: colorBackground, ), ), child: Container( decoration: BoxDecoration( color: colorBackground, ), child: Center( child: Text( '$i / ${numberOfColumns(context)}', style: TextStyle(color: Colors.grey), //textAlign: TextAlign.center, ), ), //margin: EdgeInsets.all(0), ), )); // List<Widget> tabbarViewItems() { // List<Widget> items = []; // for (int i = 0; i < 25; i++) { // Widget listView = _buildGrid(); // items.add(listView); // } // return items; // } List<Widget> listViewItems() { List<Widget> items = []; for (int i = 0; i < 500; i++) { Widget widgetItem = Text( 'item $i', textAlign: TextAlign.center, style: TextStyle(color: Colors.white), ); items.add(widgetItem); } return items; } @override Widget build(BuildContext context) { return DefaultTabController( length: 25, child: Scaffold( backgroundColor: colorBackground, //floatingActionButton: MyTabBar(), floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat, body: Stack( children: [ Container( width: double.infinity, color: Colors.amber, child: Image.network( 'https://images.unsplash.com/photo-1517248135467-4c7edcad34c4?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=2700&q=80', fit: BoxFit.cover, height: MediaQuery.of(context).size.height * kCoverHeightProportion, ), //color: Colors.green, ), Align( alignment: Alignment.bottomCenter, child: Container( height: 40, width: 300, color: Colors.red, ), ), Align( alignment: Alignment.bottomCenter, child: Container( margin: EdgeInsets.only(left: kBigBoxPadding, right: kBigBoxPadding, top: kBigBoxPadding, bottom: kBottomBigBoxPadding), //width: MediaQuery.of(context).size.width * 0.9, //margin: EdgeInsets.symmetric(horizontal: kBigBoxPadding), decoration: BoxDecoration( //color: Colors.pink, borderRadius: BorderRadius.all(Radius.circular(30)), ), child: ClipRRect( borderRadius: BorderRadius.all(Radius.circular(30)), child: CustomScrollView( //physics: FixedExtentScrollPhysics(), anchor: kCoverHeightProportion * kCoverHeightProportion * MediaQuery.of(context).size.height / (kCoverHeightProportion * (MediaQuery.of(context).size.height - kBigBoxPadding - kBottomBigBoxPadding)), slivers: [ SliverAppBarLayer( child: Container( width: double.infinity, height: 100, decoration: BoxDecoration( color: colorBackground, borderRadius: BorderRadius.only(topLeft: Radius.circular(30), topRight: Radius.circular(30))), child: Center( child: Text( 'La casa de don Juan', style: TextStyle(color: colorPrimary1, fontSize: 32, fontWeight: FontWeight.w800), ), ), ), ), SliverGrid.extent( maxCrossAxisExtent: kMaxCrossAxisExtent, childAspectRatio: 1, mainAxisSpacing: 0, crossAxisSpacing: 0, children: _buildGridTileList(context, 250), ), ], ), ), ), ), ], ), ), ); } }
style_constants.dart
import 'package:flutter/material.dart'; const Color colorShade1 = Color(0xFFEFF0F2); const Color colorShade2 = Color(0xFF777777); const Color colorShade3 = Color(0xFF424242); const Color colorShade4 = Color(0xFF4B4935); const Color colorShade5 = Color(0xFF3D2916); const Color colorShade6 = Color(0xFF1D1C0A); const Color colorBackground = Color(0xFF101A24); const Color colorPrimary1 = Color(0xFFCC9757); const double kTabIconHeight = 28; const double kCoverHeightProportion = 0.35; const double kBigBoxPadding = 8; const double kBottomBigBoxPadding = 60; const double kMaxCrossAxisExtent = 150;
-
Tomas Baran over 3 yearsWow! Huge thanks @Kherel! Your solution rocks! Not only it solved the issue with the error but the fps went from 0.9 fps - 7.7 fps (avg. ~5 fps) -> 7 fps - 24 fps (avg. ~18 fps). Could you please explain why
SliverPersistentHeaderDelegate
is the correct solution here instead of extendingSingleChildRenderObjectWidget
? Why is your solution errorless andSingleChildRenderObjectWidget
gives the error and slow frame rate? Un saludo de Las Palmas de Gran Canaria :) -
Kherel over 3 yearsThe main difference in paint methods of RenderSliverSingleBoxAdapter and RenderSliverPersistentHeader. When you are using SingleChildRenderObjectWidget with RenderSliverToBoxAdapter, your are pushing sliver down using paintOrigin. You have to do it on every paint cycle. But when you are are using SliverPersistentHeader and SliverPersistentHeaderDelegate, we need to calucalte offset only if sliver header is moving on the screen.
-
Kherel over 3 yearsAfter it's find its fixed place, performLayout not trigered anymore and geometry is not changing. And paint method just need to know where it need to be paint, without calculating all overflowed slivers. I'm not 100% sure,, but this is how I understand it. Thanks for the kind words, I've checked some of your articles. Good luck with your projects, and happy codding mi amigo.
-
Tomas Baran over 3 yearsVery valuable insights. Now, it's clear. Thanks a lot for sharing, tío :)