Created
March 29, 2021 05:57
-
-
Save pingbird/b7dc0cc2b7f64adcadf22070f48747c4 to your computer and use it in GitHub Desktop.
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/foundation.dart'; | |
| import 'package:flutter/material.dart'; | |
| import 'package:flutter/rendering.dart'; | |
| void main() { | |
| runApp(MyApp()); | |
| } | |
| class MyApp extends StatefulWidget { | |
| @override | |
| _MyAppState createState() => _MyAppState(); | |
| } | |
| class _MyAppState extends State<MyApp> { | |
| final textStyle = TextStyle( | |
| fontSize: 24.0, | |
| ); | |
| @override | |
| Widget build(BuildContext context) { | |
| return MaterialApp( | |
| home: Scaffold( | |
| appBar: AppBar( | |
| title: Text('MyFlex'), | |
| ), | |
| body: MyFlex( | |
| direction: Axis.vertical, | |
| children: [ | |
| Text('Test 1', style: textStyle), | |
| StatusFlexible( | |
| status: MyStatus.dead, | |
| child: Text('Test 2', style: textStyle), | |
| ), | |
| Text('Test 3', style: textStyle), | |
| StatusFlexible( | |
| status: MyStatus.dead, | |
| child: Text('Test 4', style: textStyle), | |
| ), | |
| Text('Test 5', style: textStyle), | |
| ], | |
| ), | |
| ), | |
| ); | |
| } | |
| } | |
| enum MyStatus { | |
| dead, | |
| alive, | |
| } | |
| class StatusFlexParentData extends FlexParentData { | |
| MyStatus? status; | |
| } | |
| class StatusFlexible extends ParentDataWidget<StatusFlexParentData> { | |
| StatusFlexible({ | |
| this.flex = 0, | |
| this.fit = FlexFit.loose, | |
| this.status, | |
| required Widget child, | |
| }) : super(child: child); | |
| final int flex; | |
| final FlexFit fit; | |
| final MyStatus? status; | |
| @override | |
| void applyParentData(RenderObject renderObject) { | |
| final parentData = renderObject.parentData! as StatusFlexParentData; | |
| bool needsLayout = false; | |
| bool needsPaint = false; | |
| if (parentData.flex != flex) { | |
| parentData.flex = flex; | |
| needsLayout = true; | |
| } | |
| if (parentData.fit != fit) { | |
| parentData.fit = fit; | |
| needsLayout = true; | |
| } | |
| if (parentData.status != status) { | |
| parentData.status = status; | |
| needsPaint = true; | |
| } | |
| if (needsLayout) { | |
| final AbstractNode? targetParent = renderObject.parent; | |
| if (targetParent is RenderObject) | |
| targetParent.markNeedsLayout(); | |
| } else if (needsPaint) { | |
| final AbstractNode? targetParent = renderObject.parent; | |
| if (targetParent is RenderObject) | |
| targetParent.markNeedsPaint(); | |
| } | |
| } | |
| @override | |
| Type get debugTypicalAncestorWidgetClass => Flex; | |
| } | |
| class MyRenderFlex extends RenderFlex { | |
| MyRenderFlex({ | |
| List<RenderBox>? children, | |
| Axis direction = Axis.horizontal, | |
| MainAxisSize mainAxisSize = MainAxisSize.max, | |
| MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start, | |
| CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center, | |
| TextDirection? textDirection, | |
| VerticalDirection verticalDirection = VerticalDirection.down, | |
| TextBaseline? textBaseline, | |
| Clip clipBehavior = Clip.none, | |
| }) : super( | |
| children: children, | |
| direction: direction, | |
| mainAxisSize: mainAxisSize, | |
| mainAxisAlignment: mainAxisAlignment, | |
| crossAxisAlignment: crossAxisAlignment, | |
| textDirection: textDirection, | |
| verticalDirection: verticalDirection, | |
| textBaseline: textBaseline, | |
| clipBehavior: clipBehavior, | |
| ); | |
| @override | |
| void setupParentData(RenderBox child) { | |
| if (child.parentData is! StatusFlexParentData) | |
| child.parentData = StatusFlexParentData(); | |
| } | |
| @override | |
| bool get alwaysNeedsCompositing => true; | |
| void defaultPaint(PaintingContext context, Offset offset) { | |
| RenderBox? child = firstChild; | |
| while (child != null) { | |
| final childParentData = child.parentData! as StatusFlexParentData; | |
| final alpha = childParentData.status == MyStatus.dead ? 128 : 255; | |
| context.pushOpacity(offset, alpha, (context, offset) { | |
| context.paintChild(child!, childParentData.offset + offset); | |
| }); | |
| child = childParentData.nextSibling; | |
| } | |
| } | |
| } | |
| class MyFlex extends MultiChildRenderObjectWidget { | |
| MyFlex({ | |
| Key? key, | |
| required this.direction, | |
| this.mainAxisAlignment = MainAxisAlignment.start, | |
| this.mainAxisSize = MainAxisSize.max, | |
| this.crossAxisAlignment = CrossAxisAlignment.center, | |
| this.textDirection, | |
| this.verticalDirection = VerticalDirection.down, | |
| this.textBaseline, // NO DEFAULT: we don't know what the text's baseline should be | |
| this.clipBehavior = Clip.none, | |
| List<Widget> children = const <Widget>[], | |
| }) : assert(crossAxisAlignment != CrossAxisAlignment.baseline || textBaseline != null, 'textBaseline is required if you specify the crossAxisAlignment with CrossAxisAlignment.baseline'), | |
| super(key: key, children: children); | |
| final Axis direction; | |
| final MainAxisAlignment mainAxisAlignment; | |
| final MainAxisSize mainAxisSize; | |
| final CrossAxisAlignment crossAxisAlignment; | |
| final TextDirection? textDirection; | |
| final VerticalDirection verticalDirection; | |
| final TextBaseline? textBaseline; | |
| final Clip clipBehavior; | |
| bool get _needTextDirection { | |
| switch (direction) { | |
| case Axis.horizontal: | |
| return true; // because it affects the layout order. | |
| case Axis.vertical: | |
| return crossAxisAlignment == CrossAxisAlignment.start | |
| || crossAxisAlignment == CrossAxisAlignment.end; | |
| } | |
| } | |
| @protected | |
| TextDirection? getEffectiveTextDirection(BuildContext context) { | |
| return textDirection ?? (_needTextDirection ? Directionality.maybeOf(context) : null); | |
| } | |
| @override | |
| RenderFlex createRenderObject(BuildContext context) { | |
| return MyRenderFlex( | |
| direction: direction, | |
| mainAxisAlignment: mainAxisAlignment, | |
| mainAxisSize: mainAxisSize, | |
| crossAxisAlignment: crossAxisAlignment, | |
| textDirection: getEffectiveTextDirection(context), | |
| verticalDirection: verticalDirection, | |
| textBaseline: textBaseline, | |
| clipBehavior: clipBehavior, | |
| ); | |
| } | |
| @override | |
| void updateRenderObject(BuildContext context, covariant RenderFlex renderObject) { | |
| renderObject | |
| ..direction = direction | |
| ..mainAxisAlignment = mainAxisAlignment | |
| ..mainAxisSize = mainAxisSize | |
| ..crossAxisAlignment = crossAxisAlignment | |
| ..textDirection = getEffectiveTextDirection(context) | |
| ..verticalDirection = verticalDirection | |
| ..textBaseline = textBaseline | |
| ..clipBehavior = clipBehavior; | |
| } | |
| @override | |
| void debugFillProperties(DiagnosticPropertiesBuilder properties) { | |
| super.debugFillProperties(properties); | |
| properties.add(EnumProperty<Axis>('direction', direction)); | |
| properties.add(EnumProperty<MainAxisAlignment>('mainAxisAlignment', mainAxisAlignment)); | |
| properties.add(EnumProperty<MainAxisSize>('mainAxisSize', mainAxisSize, defaultValue: MainAxisSize.max)); | |
| properties.add(EnumProperty<CrossAxisAlignment>('crossAxisAlignment', crossAxisAlignment)); | |
| properties.add(EnumProperty<TextDirection>('textDirection', textDirection, defaultValue: null)); | |
| properties.add(EnumProperty<VerticalDirection>('verticalDirection', verticalDirection, defaultValue: VerticalDirection.down)); | |
| properties.add(EnumProperty<TextBaseline>('textBaseline', textBaseline, defaultValue: null)); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment