-
-
Save slightfoot/a8d97045cd21a4bcd9e5098026d1dba2 to your computer and use it in GitHub Desktop.
Force Intrinsics - by Simon Lightfoot - Humpday Q&A :: 12th June 2024 #Flutter #Dart - https://www.youtube.com/watch?v=QBmqKvw_0s8
This file contains 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 'package:flutter/material.dart'; | |
import 'package:flutter/rendering.dart'; | |
void main() => runApp(const ExampleApp()); | |
class ExampleApp extends StatelessWidget { | |
const ExampleApp({super.key}); | |
@override | |
Widget build(BuildContext context) { | |
return const MaterialApp( | |
home: SingleChildScrollViewExample(), | |
); | |
} | |
} | |
class SingleChildScrollViewExample extends StatelessWidget { | |
const SingleChildScrollViewExample({super.key}); | |
@override | |
Widget build(BuildContext context) { | |
return DefaultTextStyle( | |
style: Theme.of(context).textTheme.bodyMedium!, | |
child: ColoredBox( | |
color: Colors.white, | |
child: Center( | |
child: SizedBox( | |
height: 400, | |
child: Container( | |
decoration: BoxDecoration( | |
border: Border.all(color: Colors.black), | |
), | |
child: SingleChildScrollView( | |
child: Padding( | |
padding: const EdgeInsets.all(8.0), | |
child: Column( | |
children: [ | |
const Text('Header stuff'), | |
IntrinsicHeight( | |
child: DecoratedBox( | |
decoration: BoxDecoration( | |
border: Border.all(color: Colors.black), | |
), | |
child: const Row( | |
mainAxisSize: MainAxisSize.min, | |
crossAxisAlignment: CrossAxisAlignment.stretch, | |
children: <Widget>[ | |
Expanded( | |
child: Checklist(), | |
), | |
Expanded( | |
child: WorkArea(), | |
), | |
], | |
), | |
), | |
), | |
], | |
), | |
), | |
), | |
), | |
), | |
), | |
), | |
); | |
} | |
} | |
class Checklist extends StatefulWidget { | |
const Checklist({super.key}); | |
@override | |
State<Checklist> createState() => _ChecklistState(); | |
} | |
class _ChecklistState extends State<Checklist> { | |
int _numberOfItems = 10; | |
void adjustItemCount(int amount) { | |
setState(() { | |
_numberOfItems = (_numberOfItems + amount) // | |
.clamp(0, 100); | |
}); | |
} | |
@override | |
Widget build(BuildContext context) { | |
return ForceIntrinsics( | |
width: 0, | |
height: 0, | |
child: CustomScrollView( | |
physics: const ClampingScrollPhysics(), | |
slivers: [ | |
SliverToBoxAdapter( | |
child: Row( | |
children: [ | |
ElevatedButton( | |
onPressed: () => adjustItemCount(-1), | |
child: const Text('-'), | |
), | |
Text(_numberOfItems.toString()), | |
ElevatedButton( | |
onPressed: () => adjustItemCount(1), | |
child: const Text('+'), | |
), | |
], | |
), | |
), | |
SliverList( | |
delegate: SliverChildBuilderDelegate( | |
childCount: _numberOfItems, | |
(BuildContext context, int index) { | |
return Material( | |
child: Container( | |
color: Colors.red, | |
child: SizedBox( | |
height: 25, | |
width: 100, | |
child: Checkbox( | |
value: false, | |
//Yes, I know they don't work, that's ok for this example. | |
onChanged: (bool? value) {}, | |
), | |
), | |
), | |
); | |
}, | |
), | |
), | |
], | |
), | |
); | |
} | |
} | |
class WorkArea extends StatefulWidget { | |
const WorkArea({super.key}); | |
@override | |
State<WorkArea> createState() => _WorkAreaState(); | |
} | |
class _WorkAreaState extends State<WorkArea> { | |
double _height = 200; | |
void adjustHeight(double amount) { | |
setState(() { | |
_height = (_height + amount).clamp(0, 500); | |
}); | |
} | |
@override | |
Widget build(BuildContext context) { | |
return ColoredBox( | |
color: Colors.teal, | |
child: SizedBox( | |
height: _height, | |
child: Row( | |
children: [ | |
ElevatedButton( | |
onPressed: () => adjustHeight(-50), | |
child: const Text('-'), | |
), | |
Text(_height.toString()), | |
ElevatedButton( | |
onPressed: () => adjustHeight(50), | |
child: const Text('+'), | |
), | |
], | |
), | |
), | |
); | |
} | |
} | |
class ForceIntrinsics extends SingleChildRenderObjectWidget { | |
const ForceIntrinsics({ | |
super.key, | |
this.width, | |
this.height, | |
required super.child, | |
}); | |
final double? width; | |
final double? height; | |
@override | |
RenderObject createRenderObject(BuildContext context) { | |
return RenderForceIntrinsics( | |
width: width, | |
height: height, | |
); | |
} | |
@override | |
void updateRenderObject( | |
BuildContext context, covariant RenderForceIntrinsics renderObject) { | |
renderObject | |
..width = width | |
..height = height; | |
} | |
} | |
class RenderForceIntrinsics extends RenderProxyBox { | |
RenderForceIntrinsics({ | |
double? width, | |
double? height, | |
}) : _width = width, | |
_height = height; | |
double? _width; | |
double? _height; | |
double? get width => _width; | |
set width(double? value) { | |
if (_width != value) { | |
_width = value; | |
markNeedsLayout(); | |
} | |
} | |
double? get height => _height; | |
set height(double? value) { | |
if (_height != value) { | |
_height = value; | |
markNeedsLayout(); | |
} | |
} | |
@override | |
double getMinIntrinsicHeight(double width) { | |
if (_height case double height) { | |
return height; | |
} | |
return super.getMinIntrinsicHeight(width); | |
} | |
@override | |
double getMaxIntrinsicHeight(double width) { | |
if (_height case double height) { | |
return height; | |
} | |
return super.getMaxIntrinsicHeight(width); | |
} | |
@override | |
double getMinIntrinsicWidth(double height) { | |
if (_width case double width) { | |
return width; | |
} | |
return super.getMinIntrinsicWidth(height); | |
} | |
@override | |
double getMaxIntrinsicWidth(double height) { | |
if (_width case double width) { | |
return width; | |
} | |
return super.getMaxIntrinsicWidth(height); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment