Last active
October 14, 2021 06:39
-
-
Save AlexV525/f3321ee7580336f9c4a20d905b162510 to your computer and use it in GitHub Desktop.
DecoratedSliver
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
/// | |
/// [Author] Alex (https://github.com/AlexV525) | |
/// [Date] 2021/10/13 14:36 | |
/// | |
import 'dart:math' as math; | |
import 'package:flutter/rendering.dart'; | |
import 'package:flutter/widgets.dart'; | |
@immutable | |
class DecoratedSliver extends RenderObjectWidget { | |
const DecoratedSliver({ | |
Key? key, | |
required this.sliver, | |
required this.decoration, | |
}) : super(key: key); | |
final Widget sliver; | |
final BoxDecoration decoration; | |
@override | |
_RenderSliverDecoration createRenderObject(BuildContext context) => | |
_RenderSliverDecoration(); | |
@override | |
_DecoratedSliverElement createElement() => _DecoratedSliverElement(this); | |
@override | |
void updateRenderObject( | |
BuildContext context, | |
_RenderSliverDecoration renderObject, | |
) => | |
renderObject; | |
} | |
class _DecoratedSliverElement extends RenderObjectElement { | |
/// Creates an element that uses the given widget as its configuration. | |
_DecoratedSliverElement(DecoratedSliver widget) : super(widget); | |
@override | |
DecoratedSliver get widget => super.widget as DecoratedSliver; | |
Element? _decoration; | |
Element? _sliver; | |
Widget get _decoratedBox => Container(decoration: widget.decoration); | |
@override | |
void visitChildren(ElementVisitor visitor) { | |
if (_decoration != null) { | |
visitor(_decoration!); | |
} | |
if (_sliver != null) { | |
visitor(_sliver!); | |
} | |
} | |
@override | |
void forgetChild(Element child) { | |
super.forgetChild(child); | |
if (child == _decoration) { | |
_decoration = null; | |
} | |
if (child == _sliver) { | |
_sliver = null; | |
} | |
} | |
@override | |
void mount(Element? parent, dynamic newSlot) { | |
super.mount(parent, newSlot); | |
_decoration = updateChild(_decoration, _decoratedBox, 0); | |
_sliver = updateChild(_sliver, widget.sliver, 1); | |
} | |
@override | |
void update(DecoratedSliver newWidget) { | |
super.update(newWidget); | |
assert(widget == newWidget); | |
_decoration = updateChild(_decoration, _decoratedBox, 0); | |
_sliver = updateChild(_sliver, widget.sliver, 1); | |
} | |
@override | |
void insertRenderObjectChild(RenderObject child, int? slot) { | |
final _RenderSliverDecoration renderObject = | |
this.renderObject as _RenderSliverDecoration; | |
if (slot == 0) { | |
renderObject.decoration = child as RenderBox?; | |
} | |
if (slot == 1) { | |
renderObject.child = child as RenderSliver?; | |
} | |
assert(renderObject == this.renderObject); | |
} | |
@override | |
void moveRenderObjectChild( | |
RenderObject child, | |
Object? slot, | |
Object? newSlot, | |
) { | |
assert(false); | |
} | |
@override | |
void removeRenderObjectChild(RenderObject child, Object? slot) { | |
final _RenderSliverDecoration renderObject = | |
this.renderObject as _RenderSliverDecoration; | |
if (renderObject.decoration == child) { | |
renderObject.decoration = null; | |
} | |
if (renderObject.child == child) { | |
renderObject.child = null; | |
} | |
assert(renderObject == this.renderObject); | |
} | |
} | |
class _RenderSliverDecoration extends RenderSliver with RenderSliverHelpers { | |
_RenderSliverDecoration({ | |
RenderObject? decoration, | |
RenderSliver? child, | |
}) { | |
this.decoration = decoration as RenderBox?; | |
this.child = child; | |
} | |
/// The render object's decoration. | |
RenderBox? get decoration => _decoration; | |
RenderBox? _decoration; | |
set decoration(RenderBox? value) { | |
if (_decoration != null) { | |
dropChild(_decoration!); | |
} | |
_decoration = value; | |
if (_decoration != null) { | |
adoptChild(_decoration!); | |
} | |
} | |
/// The render object's unique child | |
RenderSliver? get child => _child; | |
RenderSliver? _child; | |
set child(RenderSliver? value) { | |
if (_child != null) { | |
dropChild(_child!); | |
} | |
_child = value; | |
if (_child != null) { | |
adoptChild(_child!); | |
} | |
} | |
@override | |
void setupParentData(RenderObject child) { | |
if (child.parentData is! SliverPhysicalParentData) | |
child.parentData = SliverPhysicalParentData(); | |
} | |
@override | |
void attach(PipelineOwner owner) { | |
super.attach(owner); | |
if (_decoration != null) { | |
_decoration!.attach(owner); | |
} | |
if (_child != null) { | |
_child!.attach(owner); | |
} | |
} | |
@override | |
void detach() { | |
super.detach(); | |
if (_decoration != null) { | |
_decoration!.detach(); | |
} | |
if (_child != null) { | |
_child!.detach(); | |
} | |
} | |
@override | |
void redepthChildren() { | |
if (_decoration != null) { | |
redepthChild(_decoration!); | |
} | |
if (_child != null) { | |
redepthChild(_child!); | |
} | |
} | |
@override | |
void visitChildren(RenderObjectVisitor visitor) { | |
if (_decoration != null) { | |
visitor(_decoration!); | |
} | |
if (_child != null) { | |
visitor(_child!); | |
} | |
} | |
@override | |
List<DiagnosticsNode> debugDescribeChildren() { | |
return <DiagnosticsNode>[ | |
if (decoration != null) decoration!.toDiagnosticsNode(name: 'decoration'), | |
if (child != null) child!.toDiagnosticsNode(name: 'child'), | |
]; | |
} | |
@override | |
void performLayout() { | |
if (child == null) { | |
geometry = SliverGeometry.zero; | |
return; | |
} | |
child!.layout(constraints, parentUsesSize: true); | |
final SliverGeometry childLayoutGeometry = child!.geometry!; | |
geometry = childLayoutGeometry; | |
if (decoration != null) { | |
decoration!.layout( | |
constraints.asBoxConstraints( | |
maxExtent: childLayoutGeometry.maxPaintExtent, | |
crossAxisExtent: constraints.crossAxisExtent, | |
), | |
parentUsesSize: true, | |
); | |
} | |
if (child == null) { | |
geometry = SliverGeometry( | |
hasVisualOverflow: constraints.scrollOffset > 0.0, | |
); | |
} else { | |
child!.layout( | |
constraints.copyWith( | |
scrollOffset: math.max(0.0, constraints.scrollOffset), | |
cacheOrigin: math.min(0.0, constraints.cacheOrigin), | |
overlap: 0.0, | |
remainingPaintExtent: constraints.remainingPaintExtent, | |
remainingCacheExtent: constraints.remainingCacheExtent, | |
), | |
parentUsesSize: true, | |
); | |
final SliverGeometry childLayoutGeometry = child!.geometry!; | |
if (childLayoutGeometry.scrollOffsetCorrection != null) { | |
geometry = SliverGeometry( | |
scrollOffsetCorrection: childLayoutGeometry.scrollOffsetCorrection, | |
); | |
return; | |
} | |
final double paintExtent = math.min( | |
math.max( | |
childLayoutGeometry.paintExtent, | |
childLayoutGeometry.layoutExtent, | |
), | |
constraints.remainingPaintExtent, | |
); | |
geometry = SliverGeometry( | |
scrollExtent: childLayoutGeometry.scrollExtent, | |
paintExtent: paintExtent, | |
layoutExtent: math.min( | |
childLayoutGeometry.layoutExtent, | |
paintExtent, | |
), | |
cacheExtent: math.min( | |
childLayoutGeometry.cacheExtent, | |
constraints.remainingCacheExtent, | |
), | |
maxPaintExtent: childLayoutGeometry.maxPaintExtent, | |
hitTestExtent: math.max( | |
childLayoutGeometry.paintExtent, | |
childLayoutGeometry.hitTestExtent, | |
), | |
hasVisualOverflow: childLayoutGeometry.hasVisualOverflow, | |
); | |
} | |
} | |
@override | |
bool hitTestChildren( | |
SliverHitTestResult result, { | |
required double mainAxisPosition, | |
required double crossAxisPosition, | |
}) { | |
assert(geometry!.hitTestExtent > 0.0); | |
if (child != null && child!.geometry!.hitTestExtent > 0.0) { | |
return child!.hitTest( | |
result, | |
mainAxisPosition: mainAxisPosition - childMainAxisPosition(child), | |
crossAxisPosition: crossAxisPosition, | |
); | |
} | |
return false; | |
} | |
@override | |
double childMainAxisPosition(RenderObject? child) => 0; | |
@override | |
void applyPaintTransform(RenderObject child, Matrix4 transform) { | |
final SliverPhysicalParentData childParentData = | |
child.parentData as SliverPhysicalParentData; | |
childParentData.applyPaintTransform(transform); | |
} | |
@override | |
void paint(PaintingContext context, Offset offset) { | |
if (geometry!.visible) { | |
if (decoration != null) { | |
final SliverPhysicalParentData childParentData = | |
decoration!.parentData as SliverPhysicalParentData; | |
context.paintChild(decoration!, offset + childParentData.paintOffset); | |
} | |
if (child != null && child!.geometry!.visible) { | |
final SliverPhysicalParentData childParentData = | |
child!.parentData as SliverPhysicalParentData; | |
context.paintChild(child!, offset + childParentData.paintOffset); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment