Created with <3 with dartpad.dev.
Last active
August 19, 2023 20:10
-
-
Save jogboms/6c966ad741e2ad35ef1c952943491168 to your computer and use it in GitHub Desktop.
SliverPhysicalShape
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 'package:flutter/material.dart'; | |
import 'package:flutter/rendering.dart'; | |
void main() => runApp( | |
const MaterialApp( | |
debugShowCheckedModeBanner: false, | |
home: SliverPhysicalShapeDemo(), | |
), | |
); | |
class SliverPhysicalShapeDemo extends StatefulWidget { | |
const SliverPhysicalShapeDemo({super.key}); | |
@override | |
State<SliverPhysicalShapeDemo> createState() => _SliverPhysicalShapeDemoState(); | |
} | |
class _SliverPhysicalShapeDemoState extends State<SliverPhysicalShapeDemo> { | |
@override | |
Widget build(BuildContext context) { | |
return Scaffold( | |
appBar: AppBar( | |
title: const Text('SliverPhysicalShape'), | |
), | |
body: CustomScrollView( | |
slivers: [ | |
SliverPhysicalShape( | |
color: Colors.white, | |
borderRadius: const BorderRadius.only( | |
topLeft: Radius.circular(16), | |
topRight: Radius.circular(16), | |
), | |
child: SliverList( | |
delegate: SliverChildBuilderDelegate( | |
(context, index) => ListTile( | |
leading: const Icon(Icons.code), | |
title: Text('Index ${index + 1}'), | |
), | |
childCount: 50, | |
), | |
), | |
), | |
], | |
), | |
); | |
} | |
} | |
class SliverPhysicalShape extends SingleChildRenderObjectWidget { | |
const SliverPhysicalShape({ | |
super.key, | |
this.color = const Color(0xFFFFFFFF), | |
this.elevation = 0.0, | |
this.shadowColor = const Color(0x00000000), | |
this.borderRadius, | |
super.child, | |
}); | |
final Color color; | |
final double elevation; | |
final Color shadowColor; | |
final BorderRadius? borderRadius; | |
@override | |
RenderSliverPhysicalShape createRenderObject(BuildContext context) => | |
RenderSliverPhysicalShape( | |
color: color, | |
elevation: elevation, | |
shadowColor: shadowColor, | |
borderRadius: borderRadius, | |
); | |
@override | |
void updateRenderObject( | |
BuildContext context, RenderSliverPhysicalShape renderObject) => | |
renderObject | |
..color = color | |
..elevation = elevation | |
..shadowColor = shadowColor | |
..borderRadius = borderRadius; | |
} | |
class RenderSliverPhysicalShape extends RenderSliver | |
with RenderObjectWithChildMixin<RenderSliver> { | |
RenderSliverPhysicalShape({ | |
required Color color, | |
required double elevation, | |
required Color shadowColor, | |
BorderRadius? borderRadius, | |
}) : _color = color, | |
_elevation = elevation, | |
_shadowColor = shadowColor, | |
_borderRadius = borderRadius; | |
Color get color => _color; | |
Color _color; | |
set color(Color value) { | |
if (_color == value) { | |
return; | |
} | |
final bool didNeedCompositing = alwaysNeedsCompositing; | |
_color = value; | |
if (didNeedCompositing != alwaysNeedsCompositing) { | |
markNeedsCompositingBitsUpdate(); | |
} | |
markNeedsPaint(); | |
} | |
double get elevation => _elevation; | |
double _elevation; | |
set elevation(double value) { | |
if (_elevation == value) { | |
return; | |
} | |
final bool didNeedCompositing = alwaysNeedsCompositing; | |
_elevation = value; | |
if (didNeedCompositing != alwaysNeedsCompositing) { | |
markNeedsCompositingBitsUpdate(); | |
} | |
markNeedsPaint(); | |
} | |
Color get shadowColor => _shadowColor; | |
Color _shadowColor; | |
set shadowColor(Color value) { | |
if (_shadowColor == value) { | |
return; | |
} | |
final bool didNeedCompositing = alwaysNeedsCompositing; | |
_shadowColor = value; | |
if (didNeedCompositing != alwaysNeedsCompositing) { | |
markNeedsCompositingBitsUpdate(); | |
} | |
markNeedsPaint(); | |
} | |
BorderRadius? get borderRadius => _borderRadius; | |
BorderRadius? _borderRadius; | |
set borderRadius(BorderRadius? value) { | |
if (_borderRadius == value) { | |
return; | |
} | |
final bool didNeedCompositing = alwaysNeedsCompositing; | |
_borderRadius = value; | |
if (didNeedCompositing != alwaysNeedsCompositing) { | |
markNeedsCompositingBitsUpdate(); | |
} | |
markNeedsPaint(); | |
} | |
@override | |
PhysicalModelLayer? get layer => super.layer as PhysicalModelLayer?; | |
@override | |
void applyPaintTransform(RenderObject child, Matrix4 transform) { | |
final SliverPhysicalParentData childParentData = | |
child.parentData as SliverPhysicalParentData; | |
childParentData.applyPaintTransform(transform); | |
} | |
@override | |
void performLayout() { | |
assert(child != null); | |
child!.layout(constraints, parentUsesSize: true); | |
geometry = child!.geometry; | |
} | |
@override | |
void setupParentData(RenderObject child) { | |
if (child.parentData is! SliverPhysicalParentData) { | |
child.parentData = SliverPhysicalParentData(); | |
} | |
} | |
@override | |
bool hitTestChildren( | |
SliverHitTestResult result, { | |
required double mainAxisPosition, | |
required double crossAxisPosition, | |
}) => | |
child != null && | |
child!.geometry!.hitTestExtent > 0 && | |
child!.hitTest(result, | |
mainAxisPosition: mainAxisPosition, | |
crossAxisPosition: crossAxisPosition); | |
@override | |
double childMainAxisPosition(RenderSliver child) { | |
assert(child == this.child); | |
return 0.0; | |
} | |
@override | |
void paint(PaintingContext context, Offset offset) { | |
layer ??= PhysicalModelLayer(); | |
final clipPath = Path(); | |
if (borderRadius != null) { | |
clipPath.addRRect(borderRadius!.toRRect(offset & getAbsoluteSize())); | |
} | |
layer! | |
..color = color | |
..elevation = elevation | |
..shadowColor = shadowColor | |
..clipPath = clipPath; | |
context.pushLayer(layer!, child!.paint, offset); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment