Skip to content

Instantly share code, notes, and snippets.

@pingbird
Created March 29, 2021 05:57
Show Gist options
  • Select an option

  • Save pingbird/b7dc0cc2b7f64adcadf22070f48747c4 to your computer and use it in GitHub Desktop.

Select an option

Save pingbird/b7dc0cc2b7f64adcadf22070f48747c4 to your computer and use it in GitHub Desktop.
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