├── .gitignore
├── CHANGELOG.md
├── LICENSE
├── README.md
├── cupertino_segment_control.iml
├── lib
└── cupertino_segment_control.dart
├── pubspec.yaml
├── screenshot.png
└── test
└── cupertino_segment_control_test.dart
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .atom/
3 | .idea
4 | .packages
5 | .pub/
6 | packages
7 | pubspec.lock
8 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## [0.0.3] - Readme instructions changed
2 |
3 | * Readme changes
4 |
5 | ## [0.0.2] - Refactor
6 |
7 | * Refactored class naming
8 |
9 | ## [0.0.1] - Initial release
10 |
11 | * Initial release
12 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | TODO: Add your license here.
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Development Stopped
2 |
3 | Flutter has a Cupertino Segmentcontrol now: https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/cupertino/segmented_control.dart
4 |
5 | # cupertino_segment_control
6 |
7 | A flutter package which adds the [Apple's iOS Segment Control UI element](https://developer.apple.com/ios/human-interface-guidelines/controls/segmented-controls/).
8 |
9 | ## Getting Started
10 |
11 | - Add the package to your pubspec
12 | - Add following code:
13 | ```dart
14 | new SegmentControl([
15 | new SegmentControlItem("test1", new Text("test1")),
16 | new SegmentControlItem("test2", new Text("test2")),
17 | new SegmentControlItem("test3", new Text("test3")),
18 | ]),
19 | ```
20 |
21 | PS: minimum of 1 `SegmentControlItem` and maximum of 3 `SegmentControlItem` due to this bug: https://github.com/flutter/flutter/issues/12583
22 |
23 | ## Showcase
24 |
25 | 
26 |
--------------------------------------------------------------------------------
/cupertino_segment_control.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/lib/cupertino_segment_control.dart:
--------------------------------------------------------------------------------
1 | library cupertino_segement_control;
2 |
3 | import 'package:flutter/widgets.dart';
4 | import 'package:flutter/cupertino.dart';
5 | import 'package:flutter/painting.dart';
6 |
7 | class SegmentControlItem {
8 | SegmentControlItem(this.title, this.content);
9 |
10 | final String title;
11 | final Widget content;
12 | }
13 |
14 | abstract class SegmentControlCallbacks {
15 | void _changeTab(String title);
16 | }
17 |
18 | class SegmentControl extends StatefulWidget {
19 | SegmentControl(this.tabs, {this.activeTabIndex = 0})
20 | : assert(tabs.length > 1 && tabs.length <= 3),
21 | assert(activeTabIndex <= tabs.length - 1);
22 |
23 | final List tabs;
24 | final int activeTabIndex;
25 |
26 | @override
27 | _SegmentControlState createState() => new _SegmentControlState();
28 | }
29 |
30 | class _SegmentControlState extends State
31 | with SegmentControlCallbacks {
32 | int _activeTabIndex;
33 |
34 | @override
35 | void initState() {
36 | super.initState();
37 |
38 | setState(() {
39 | _activeTabIndex = widget.activeTabIndex;
40 | });
41 | }
42 |
43 | void _changeTab(String title) {
44 | setState(() {
45 | for (int i = 0; i < widget.tabs.length; i++) {
46 | SegmentControlItem t = widget.tabs[i];
47 | if (t.title == title) {
48 | _activeTabIndex = i;
49 | }
50 | }
51 | });
52 | }
53 |
54 | @override
55 | Widget build(BuildContext context) {
56 | Widget activeTab = widget.tabs[_activeTabIndex].content;
57 |
58 | List<_SegmentControlItem> list = <_SegmentControlItem>[];
59 |
60 | for (int i = 0; i < widget.tabs.length; i++) {
61 | SegmentControlItem tap = widget.tabs[i];
62 | bool isActive = tap == widget.tabs[_activeTabIndex];
63 | _ButtonPlace place = _ButtonPlace.start;
64 |
65 | if (i > 0 && (widget.tabs.length - 1 == i)) {
66 | place = _ButtonPlace.end;
67 | } else if (i > 0 && (widget.tabs.length - 1 > i)) {
68 | place = _ButtonPlace.middle;
69 | }
70 |
71 | list.add(new _SegmentControlItem(this, tap, place, isActive));
72 | }
73 |
74 | return new Column(
75 | mainAxisAlignment: MainAxisAlignment.start,
76 | children: [
77 | new Padding(
78 | child: new Row(
79 | mainAxisAlignment: MainAxisAlignment.center,
80 | children: list,
81 | ),
82 | padding: new EdgeInsets.all(12.0),
83 | ),
84 | activeTab,
85 | ],
86 | );
87 | }
88 | }
89 |
90 | class _SegmentControlItem extends StatefulWidget {
91 | _SegmentControlItem(this.callbacks, this.buttonTab, this.place, this.isActive,
92 | {this.color = CupertinoColors.activeBlue,
93 | this.inverseColor = CupertinoColors.white});
94 |
95 | final double _defaultBorderRadius = 3.0;
96 |
97 | final SegmentControlItem buttonTab;
98 | final SegmentControlCallbacks callbacks;
99 | final _ButtonPlace place;
100 | final bool isActive;
101 | final Color color;
102 | final Color inverseColor;
103 |
104 | @override
105 | State createState() {
106 | return new _SegmentControlItemState(color, inverseColor);
107 | }
108 | }
109 |
110 | class _SegmentControlItemState extends State<_SegmentControlItem> {
111 | _SegmentControlItemState(this.color, this.inverseColor);
112 |
113 | Color color;
114 | Color inverseColor;
115 | bool tapDown = false;
116 |
117 | BoxDecoration _boxDecoration(_ButtonPlace place) {
118 | BorderRadius radius;
119 |
120 | switch (place) {
121 | case _ButtonPlace.start:
122 | radius = new BorderRadius.only(
123 | topLeft: new Radius.circular(widget._defaultBorderRadius),
124 | bottomLeft: new Radius.circular(widget._defaultBorderRadius),
125 | );
126 | break;
127 | case _ButtonPlace.end:
128 | radius = new BorderRadius.only(
129 | topRight: new Radius.circular(widget._defaultBorderRadius),
130 | bottomRight: new Radius.circular(widget._defaultBorderRadius),
131 | );
132 | break;
133 | default:
134 | break;
135 | }
136 |
137 | BoxDecoration dec = new BoxDecoration(
138 | color: widget.isActive ? color : inverseColor,
139 | border: place == _ButtonPlace.middle
140 | ? new Border(
141 | top: new BorderSide(color: tapDown ? inverseColor : color),
142 | bottom: new BorderSide(color: tapDown ? inverseColor : color),
143 | )
144 | : new Border.all(color: tapDown ? inverseColor : color),
145 | borderRadius: radius,
146 | );
147 |
148 | return dec;
149 | }
150 |
151 | void _tabDown() {
152 | if (!widget.isActive) {
153 | setState(() {
154 | tapDown = true;
155 | final Color _backupColor = color;
156 | color = inverseColor;
157 | inverseColor = _backupColor;
158 | });
159 | }
160 | }
161 |
162 | void _tabUp() {
163 | if (!widget.isActive) {
164 | tapDown = false;
165 | final Color _backupColor = color;
166 | color = inverseColor;
167 | inverseColor = _backupColor;
168 | }
169 | }
170 |
171 | @override
172 | Widget build(BuildContext context) {
173 | return new GestureDetector(
174 | onTapDown: (_) {
175 | _tabDown();
176 | },
177 | onTapUp: (_) {
178 | _tabUp();
179 | },
180 | onTap: () {
181 | widget.callbacks._changeTab(widget.buttonTab.title);
182 | },
183 | child: new Container(
184 | decoration: _boxDecoration(widget.place),
185 | padding: new EdgeInsets.fromLTRB(20.0, 4.0, 20.0, 4.0),
186 | child: new Text(
187 | widget.buttonTab.title,
188 | style: new TextStyle(color: widget.isActive ? inverseColor : color),
189 | ),
190 | ),
191 | );
192 | }
193 | }
194 |
195 | enum _ButtonPlace { start, middle, end }
196 |
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: cupertino_segment_control
2 | description: A Cupertino-stype segment control
3 | version: 0.0.3
4 | author: Theo Bouwman
5 | homepage: https://github.com/theobouwman/flutter_cupertino_segment_control
6 |
7 | dependencies:
8 | flutter:
9 | sdk: flutter
10 |
11 | dev_dependencies:
12 | test: ^0.12.0
13 |
14 | # For information on the generic Dart part of this file, see the
15 | # following page: https://www.dartlang.org/tools/pub/pubspec
16 |
17 | # The following section is specific to Flutter.
18 | flutter:
19 |
20 | # To add assets to your package, add an assets section, like this:
21 | # assets:
22 | # - images/a_dot_burr.jpeg
23 | # - images/a_dot_ham.jpeg
24 | #
25 | # For details regarding assets in packages, see
26 | # https://flutter.io/assets-and-images/#from-packages
27 | #
28 | # An image asset can refer to one or more resolution-specific "variants", see
29 | # https://flutter.io/assets-and-images/#resolution-aware.
30 |
31 | # To add custom fonts to your package, add a fonts section here,
32 | # in this "flutter" section. Each entry in this list should have a
33 | # "family" key with the font family name, and a "fonts" key with a
34 | # list giving the asset and other descriptors for the font. For
35 | # example:
36 | # fonts:
37 | # - family: Schyler
38 | # fonts:
39 | # - asset: fonts/Schyler-Regular.ttf
40 | # - asset: fonts/Schyler-Italic.ttf
41 | # style: italic
42 | # - family: Trajan Pro
43 | # fonts:
44 | # - asset: fonts/TrajanPro.ttf
45 | # - asset: fonts/TrajanPro_Bold.ttf
46 | # weight: 700
47 | #
48 | # For details regarding fonts in packages, see
49 | # https://flutter.io/custom-fonts/#from-packages
--------------------------------------------------------------------------------
/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theobouwman/flutter_cupertino_segment_control/403d358316131f1b89b6014e7de3bc30d68efc7a/screenshot.png
--------------------------------------------------------------------------------
/test/cupertino_segment_control_test.dart:
--------------------------------------------------------------------------------
1 | void main() {
2 | // TODO: add tests
3 | }
4 |
--------------------------------------------------------------------------------