Skip to content

Instantly share code, notes, and snippets.

@jogboms
Last active August 19, 2023 20:10
Show Gist options
  • Save jogboms/6c966ad741e2ad35ef1c952943491168 to your computer and use it in GitHub Desktop.
Save jogboms/6c966ad741e2ad35ef1c952943491168 to your computer and use it in GitHub Desktop.
SliverPhysicalShape
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