@@ -141,6 +141,7 @@ class SegmentedButton<T> extends StatefulWidget {
141
141
this .style,
142
142
this .showSelectedIcon = true ,
143
143
this .selectedIcon,
144
+ this .direction = Axis .horizontal,
144
145
}) : assert (segments.length > 0 ),
145
146
assert (selected.length > 0 || emptySelectionAllowed),
146
147
assert (selected.length < 2 || multiSelectionEnabled);
@@ -154,6 +155,14 @@ class SegmentedButton<T> extends StatefulWidget {
154
155
/// [ChoiceChip] widgets.
155
156
final List <ButtonSegment <T >> segments;
156
157
158
+ /// The orientation of the button's [segments] .
159
+ ///
160
+ /// If this is [Axis.vertical] , the segments will be aligned vertically
161
+ /// and the first item in [segments] will be on the top.
162
+ ///
163
+ /// Defaults to [Axis.horizontal] .
164
+ final Axis direction;
165
+
157
166
/// The set of [ButtonSegment.value] s that indicate which [segments] are
158
167
/// selected.
159
168
///
@@ -449,7 +458,7 @@ class SegmentedButtonState<T> extends State<SegmentedButton<T>> {
449
458
Widget build (BuildContext context) {
450
459
final SegmentedButtonThemeData theme = SegmentedButtonTheme .of (context);
451
460
final SegmentedButtonThemeData defaults = _SegmentedButtonDefaultsM3 (context);
452
- final TextDirection direction = Directionality .of (context);
461
+ final TextDirection textDirection = Directionality .of (context);
453
462
454
463
const Set <MaterialState > enabledState = < MaterialState > {};
455
464
const Set <MaterialState > disabledState = < MaterialState > { MaterialState .disabled };
@@ -576,7 +585,8 @@ class SegmentedButtonState<T> extends State<SegmentedButton<T>> {
576
585
segments: widget.segments,
577
586
enabledBorder: _enabled ? enabledBorder : disabledBorder,
578
587
disabledBorder: disabledBorder,
579
- direction: direction,
588
+ direction: widget.direction,
589
+ textDirection: textDirection,
580
590
isExpanded: widget.expandedInsets != null ,
581
591
children: buttons,
582
592
),
@@ -601,6 +611,7 @@ class _SegmentedButtonRenderWidget<T> extends MultiChildRenderObjectWidget {
601
611
required this .enabledBorder,
602
612
required this .disabledBorder,
603
613
required this .direction,
614
+ required this .textDirection,
604
615
required this .tapTargetVerticalPadding,
605
616
required this .isExpanded,
606
617
required super .children,
@@ -609,7 +620,8 @@ class _SegmentedButtonRenderWidget<T> extends MultiChildRenderObjectWidget {
609
620
final List <ButtonSegment <T >> segments;
610
621
final OutlinedBorder enabledBorder;
611
622
final OutlinedBorder disabledBorder;
612
- final TextDirection direction;
623
+ final Axis direction;
624
+ final TextDirection textDirection;
613
625
final double tapTargetVerticalPadding;
614
626
final bool isExpanded;
615
627
@@ -619,7 +631,8 @@ class _SegmentedButtonRenderWidget<T> extends MultiChildRenderObjectWidget {
619
631
segments: segments,
620
632
enabledBorder: enabledBorder,
621
633
disabledBorder: disabledBorder,
622
- textDirection: direction,
634
+ textDirection: textDirection,
635
+ direction: direction,
623
636
tapTargetVerticalPadding: tapTargetVerticalPadding,
624
637
isExpanded: isExpanded,
625
638
);
@@ -631,7 +644,8 @@ class _SegmentedButtonRenderWidget<T> extends MultiChildRenderObjectWidget {
631
644
..segments = segments
632
645
..enabledBorder = enabledBorder
633
646
..disabledBorder = disabledBorder
634
- ..textDirection = direction;
647
+ ..direction = direction
648
+ ..textDirection = textDirection;
635
649
}
636
650
}
637
651
@@ -651,10 +665,12 @@ class _RenderSegmentedButton<T> extends RenderBox with
651
665
required TextDirection textDirection,
652
666
required double tapTargetVerticalPadding,
653
667
required bool isExpanded,
668
+ required Axis direction,
654
669
}) : _segments = segments,
655
670
_enabledBorder = enabledBorder,
656
671
_disabledBorder = disabledBorder,
657
672
_textDirection = textDirection,
673
+ _direction = direction,
658
674
_tapTargetVerticalPadding = tapTargetVerticalPadding,
659
675
_isExpanded = isExpanded;
660
676
@@ -698,6 +714,16 @@ class _RenderSegmentedButton<T> extends RenderBox with
698
714
markNeedsLayout ();
699
715
}
700
716
717
+ Axis get direction => _direction;
718
+ Axis _direction;
719
+ set direction (Axis value) {
720
+ if (value == _direction) {
721
+ return ;
722
+ }
723
+ _direction = value;
724
+ markNeedsLayout ();
725
+ }
726
+
701
727
double get tapTargetVerticalPadding => _tapTargetVerticalPadding;
702
728
double _tapTargetVerticalPadding;
703
729
set tapTargetVerticalPadding (double value) {
@@ -787,17 +813,28 @@ class _RenderSegmentedButton<T> extends RenderBox with
787
813
double start = 0.0 ;
788
814
while (child != null ) {
789
815
final _SegmentedButtonContainerBoxParentData childParentData = child.parentData! as _SegmentedButtonContainerBoxParentData ;
790
- final Offset childOffset = Offset (start, 0.0 );
791
- childParentData.offset = childOffset;
792
- final Rect childRect = Rect .fromLTWH (start, 0.0 , child.size.width, child.size.height);
793
- final RRect rChildRect = RRect .fromRectAndCorners (childRect);
816
+ late final RRect rChildRect;
817
+ if (direction == Axis .vertical) {
818
+ childParentData.offset = Offset (0.0 , start);
819
+ final Rect childRect = Rect .fromLTWH (0.0 , childParentData.offset.dy, child.size.width, child.size.height);
820
+ rChildRect = RRect .fromRectAndCorners (childRect);
821
+ start += child.size.height;
822
+ } else {
823
+ childParentData.offset = Offset (start, 0.0 );
824
+ final Rect childRect = Rect .fromLTWH (start, 0.0 , child.size.width, child.size.height);
825
+ rChildRect = RRect .fromRectAndCorners (childRect);
826
+ start += child.size.width;
827
+ }
794
828
childParentData.surroundingRect = rChildRect;
795
- start += child.size.width;
796
829
child = nextChild (child);
797
830
}
798
831
}
799
832
800
833
Size _calculateChildSize (BoxConstraints constraints) {
834
+ return direction == Axis .horizontal ? _calculateHorizontalChildSize (constraints) : _calculateVerticalChildSize (constraints);
835
+ }
836
+
837
+ Size _calculateHorizontalChildSize (BoxConstraints constraints) {
801
838
double maxHeight = 0 ;
802
839
RenderBox ? child = firstChild;
803
840
double childWidth;
@@ -820,7 +857,33 @@ class _RenderSegmentedButton<T> extends RenderBox with
820
857
return Size (childWidth, maxHeight);
821
858
}
822
859
860
+ Size _calculateVerticalChildSize (BoxConstraints constraints) {
861
+ double maxWidth = 0 ;
862
+ RenderBox ? child = firstChild;
863
+ double childHeight;
864
+ if (_isExpanded) {
865
+ childHeight = constraints.maxHeight / childCount;
866
+ } else {
867
+ childHeight = constraints.minHeight / childCount;
868
+ while (child != null ) {
869
+ childHeight = math.max (childHeight, child.getMaxIntrinsicHeight (double .infinity));
870
+ child = childAfter (child);
871
+ }
872
+ childHeight = math.min (childHeight, constraints.maxHeight / childCount);
873
+ }
874
+ child = firstChild;
875
+ while (child != null ) {
876
+ final double boxWidth = child.getMaxIntrinsicWidth (maxWidth);
877
+ maxWidth = math.max (maxWidth, boxWidth);
878
+ child = childAfter (child);
879
+ }
880
+ return Size (maxWidth, childHeight);
881
+ }
882
+
823
883
Size _computeOverallSizeFromChildSize (Size childSize) {
884
+ if (direction == Axis .vertical) {
885
+ return constraints.constrain (Size (childSize.width, childSize.height * childCount));
886
+ }
824
887
return constraints.constrain (Size (childSize.width * childCount, childSize.height));
825
888
}
826
889
@@ -926,9 +989,17 @@ class _RenderSegmentedButton<T> extends RenderBox with
926
989
final BorderSide divider = segments[index - 1 ].enabled || segments[index].enabled
927
990
? enabledBorder.side.copyWith (strokeAlign: 0.0 )
928
991
: disabledBorder.side.copyWith (strokeAlign: 0.0 );
929
- final Offset top = Offset (dividerPos, borderRect.top);
930
- final Offset bottom = Offset (dividerPos, borderRect.bottom);
931
- context.canvas.drawLine (top, bottom, divider.toPaint ());
992
+ if (direction == Axis .horizontal) {
993
+ final Offset top = Offset (dividerPos, borderRect.top);
994
+ final Offset bottom = Offset (dividerPos, borderRect.bottom);
995
+ context.canvas.drawLine (top, bottom, divider.toPaint ());
996
+ } else if (direction == Axis .vertical) {
997
+ final Offset start = Offset (borderRect.left, childRect.top);
998
+ final Offset end = Offset (borderRect.right, childRect.top);
999
+ context.canvas..save ()..clipPath (borderClipPath);
1000
+ context.canvas.drawLine (start, end, divider.toPaint ());
1001
+ context.canvas.restore ();
1002
+ }
932
1003
}
933
1004
934
1005
previousChild = child;
0 commit comments