Created
January 22, 2025 21:31
-
-
Save callmephil/1b5003478f4f8aa4d1d1640d6b58174e to your computer and use it in GitHub Desktop.
bi-directional-page-overflow
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'dart:math' as math; | |
import 'package:flutter/material.dart'; | |
import 'package:flutter/rendering.dart' show RenderAligningShiftedBox; | |
void main() { | |
runApp(const MyApp()); | |
} | |
class MyApp extends StatelessWidget { | |
const MyApp({super.key}); | |
@override | |
Widget build(BuildContext context) { | |
return MaterialApp( | |
debugShowCheckedModeBanner: false, | |
home: PageLayout( | |
children: [ | |
Image.network('https://picsum.photos/1920'), | |
], | |
), | |
); | |
} | |
} | |
class PageLayout extends StatelessWidget { | |
const PageLayout({ | |
super.key, | |
required this.children, | |
}); | |
final List<Widget> children; | |
@override | |
Widget build(BuildContext context) { | |
return PageOverflow( | |
width: 450.0, | |
child: Material( | |
child: SingleChildScrollView( | |
scrollDirection: Axis.horizontal, | |
child: SingleChildScrollView( | |
scrollDirection: Axis.vertical, | |
child: Column(children: children), | |
), | |
), | |
), | |
); | |
} | |
} | |
class PageOverflow extends SingleChildRenderObjectWidget { | |
const PageOverflow({ | |
super.key, | |
this.width, | |
this.height, | |
this.alignment = Alignment.topLeft, | |
required super.child, | |
}); | |
final double? width; | |
final double? height; | |
final AlignmentGeometry alignment; | |
@override | |
RenderObject createRenderObject(BuildContext context) { | |
return RenderPageOverflow( | |
width: width, | |
height: height, | |
alignment: alignment, | |
textDirection: Directionality.of(context), | |
); | |
} | |
@override | |
void updateRenderObject( | |
BuildContext context, | |
RenderPageOverflow renderObject, | |
) { | |
renderObject | |
..width = width | |
..height = height | |
..alignment = alignment | |
..textDirection = Directionality.of(context); | |
} | |
} | |
class RenderPageOverflow extends RenderAligningShiftedBox { | |
RenderPageOverflow({ | |
double? width, | |
double? height, | |
required super.alignment, | |
required TextDirection super.textDirection, | |
super.child, | |
}); | |
double? _width; | |
double? get width => _width; | |
set width(double? value) { | |
if (value != _width) { | |
_width = value; | |
markNeedsLayout(); | |
} | |
} | |
double? _height; | |
double? get height => _height; | |
set height(double? value) { | |
if (value != _height) { | |
_height = value; | |
markNeedsLayout(); | |
} | |
} | |
@override | |
void performLayout() { | |
// Clamp width/height to parent constraints | |
final clampedWidth = _width != null | |
? constraints.constrainWidth(_width!) | |
: constraints.maxWidth; | |
final clampedHeight = _height != null | |
? constraints.constrainHeight(_height!) | |
: constraints.maxHeight; | |
final childConstraints = constraints | |
.copyWith( | |
minWidth: clampedWidth, | |
minHeight: clampedHeight, | |
) | |
.normalize(); | |
// Safer null-check with pattern matching | |
if (child case final it?) { | |
it.layout(childConstraints, parentUsesSize: true); | |
final maxAllowedHeight = constraints.constrainHeight( | |
math.max(clampedHeight, it.size.height), | |
); | |
size = Size(constraints.maxWidth, maxAllowedHeight); | |
} else { | |
// Handle null child case explicitly | |
size = Size(constraints.maxWidth, clampedHeight); | |
} | |
alignChild(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Original code from https://gist.github.com/slightfoot/0a573044351c9be9d46ef936c18adb4e