@@ -20,6 +20,9 @@ class GFToggle extends StatelessWidget {
2020 this .type,
2121 this .height,
2222 this .width,
23+ this .onText,
24+ this .offText,
25+ this .minWidth
2326 }) : super (key: key);
2427
2528
@@ -64,6 +67,17 @@ class GFToggle extends StatelessWidget {
6467 final double width;
6568
6669
70+ ///text for the labeled Switch when it is true
71+ final String onText;
72+
73+ ///text for the labled switch when it is false
74+ final String offText;
75+
76+
77+ ///minwidth of the switch for labeled switch
78+ final bool minWidth;
79+
80+
6781 @override
6882 Widget build (BuildContext context) {
6983 if (type == GFToggleType .androidSwitch) {
@@ -82,10 +96,279 @@ class GFToggle extends StatelessWidget {
8296 return CupertinoSwitch (
8397 value: value,
8498 onChanged: onChanged,
99+ activeColor: activeColor,
100+
101+
102+ );
103+
104+ } else if (type == GFToggleType .labeledSwitch){
105+ return Switch (value: value, onChanged: onChanged,
106+
85107
86108
87109 );
88110
111+
89112 }
90113 }
114+ }
115+
116+ enum TextTransitionTypes { ROTATE , SCALE , FADE , SIZE }
117+
118+ class LabeledToggle extends StatefulWidget {
119+ final Widget child;
120+ final String onText;
121+ final String offText;
122+ final Color onTextColor;
123+ final Color offTextColor;
124+ final Color onThumbColor;
125+ final Color offThumbColor;
126+ final Color onBorderColor;
127+ final Color offBorderColor;
128+ final Color onBkColor;
129+ final Color offBkColor;
130+ final bool value;
131+ final double thumbSize;
132+ final double borderSize;
133+ final Duration duration;
134+ final Curve curve;
135+ final ValueChanged <bool > onChanged;
136+ final bool forceWidth;
137+ final bool rounded;
138+ final TextTransitionTypes transitionType;
139+ final bool rotationAnimation;
140+
141+ const LabeledToggle (
142+ {Key key,
143+ this .value = false ,
144+ this .onText = "" ,
145+ this .offText = "" ,
146+ this .onThumbColor,
147+ this .offThumbColor,
148+ this .onBorderColor,
149+ this .offBorderColor,
150+ this .onBkColor,
151+ this .offBkColor,
152+ this .onChanged,
153+ @required this .thumbSize,
154+ this .duration = const Duration (milliseconds: 400 ),
155+ this .curve = Curves .linear,
156+ this .forceWidth = false ,
157+ this .onTextColor = Colors .black,
158+ this .offTextColor = Colors .black,
159+ this .rounded = true ,
160+ this .borderSize = 1.0 ,
161+ this .transitionType = TextTransitionTypes .SCALE ,
162+ this .rotationAnimation = false ,
163+ this .child})
164+ : assert (thumbSize != null ),
165+ super (key: key);
166+
167+ const LabeledToggle .theme (
168+ {Key key,
169+ this .value = false ,
170+ this .onText = "" ,
171+ this .offText = "" ,
172+ @required onColor,
173+ @required offColor,
174+ this .onChanged,
175+ @required this .thumbSize,
176+ this .duration = const Duration (milliseconds: 400 ),
177+ this .curve = Curves .linear,
178+ this .forceWidth = false ,
179+ this .rounded = true ,
180+ this .borderSize = 1.0 ,
181+ this .transitionType = TextTransitionTypes .SCALE ,
182+ this .rotationAnimation = false ,
183+ this .child})
184+ : assert (thumbSize != null ),
185+ onThumbColor = offColor,
186+ onBorderColor = offColor,
187+ onBkColor = onColor,
188+ offThumbColor = onColor,
189+ offBorderColor = onColor,
190+ offBkColor = offColor,
191+ onTextColor = offColor,
192+ offTextColor = onColor,
193+ super (key: key);
194+
195+ @override
196+ _LabeledToggleState createState () => _LabeledToggleState ();
197+ }
198+
199+ class _LabeledToggleState extends State <LabeledToggle >
200+ with SingleTickerProviderStateMixin {
201+ bool _value;
202+ AnimationController animationController;
203+ Animation <double > animation;
204+
205+ @override
206+ void initState () {
207+ super .initState ();
208+ _value = widget.value;
209+ animationController =
210+ AnimationController (vsync: this , duration: widget.duration);
211+ CurvedAnimation curvedAnimation =
212+ CurvedAnimation (parent: animationController, curve: widget.curve);
213+ animation = Tween <double >(begin: 0.0 , end: 180.0 ).animate (curvedAnimation)
214+ ..addListener (() {
215+ setState (() {});
216+ });
217+ }
218+
219+ @override
220+ void dispose () {
221+ animationController.dispose ();
222+
223+ super .dispose ();
224+ }
225+
226+ @override
227+ void didUpdateWidget (LabeledToggle oldWidget) {
228+ super .didUpdateWidget (oldWidget);
229+ _value = widget.value;
230+ }
231+
232+ @override
233+ Widget build (BuildContext context) {
234+ return GestureDetector (
235+ onTap: () {
236+ widget.onChanged == null ? print ("" ) : widget.onChanged (! _value);
237+ if (widget.rotationAnimation) {
238+ if (animationController.status == AnimationStatus .completed) {
239+ animationController.reverse ();
240+ } else {
241+ animationController.forward ();
242+ }
243+ }
244+ },
245+ child: Opacity (
246+ opacity: widget.onChanged == null ? 0.3 : 1.0 ,
247+ child: AnimatedContainer (
248+ duration: widget.duration,
249+ height: widget.thumbSize,
250+ width: widget.forceWidth ? widget.thumbSize * 2 : null ,
251+ child: Stack (
252+ children: < Widget > [
253+ buildThumb (),
254+ buildLabel (),
255+ ],
256+ ),
257+ decoration: BoxDecoration (
258+ border: Border .all (
259+ color: widget.onChanged == null
260+ ? Color (0xFFD3D3D3 )
261+ : _value
262+ ? (widget.onBorderColor ?? widget.onThumbColor)
263+ : (widget.offBorderColor ?? widget.offThumbColor),
264+ width: widget.borderSize),
265+ color: _value ? widget.onBkColor : widget.offBkColor,
266+ borderRadius:
267+ BorderRadius .circular (widget.rounded ? 100.0 : 0.0 )),
268+ ),
269+ ),
270+ );
271+ }
272+
273+ Widget buildLabel () {
274+ return Padding (
275+ padding: EdgeInsets .only (
276+ right: _value ? widget.thumbSize : 1.0 ,
277+ left: _value ? 1.0 : widget.thumbSize),
278+ child: Row (
279+ children: < Widget > [
280+ Expanded (
281+ child: Padding (
282+ padding: const EdgeInsets .all (5.0 ),
283+ child: Container (
284+ height: widget.thumbSize,
285+ child: FittedBox (
286+ child: Center (
287+ child: AnimatedSwitcher (
288+ duration: widget.duration,
289+ switchInCurve: widget.curve,
290+ switchOutCurve: widget.curve,
291+ transitionBuilder:
292+ (Widget child, Animation <double > animation) {
293+ switch (widget.transitionType) {
294+ case TextTransitionTypes .ROTATE :
295+ {
296+ return RotationTransition (
297+ child: child,
298+ turns: animation,
299+ );
300+ }
301+ break ;
302+ case TextTransitionTypes .FADE :
303+ {
304+ return FadeTransition (
305+ child: child,
306+ opacity: animation,
307+ );
308+ }
309+ break ;
310+
311+ case TextTransitionTypes .SIZE :
312+ {
313+ return SizeTransition (
314+ child: child,
315+ sizeFactor: animation,
316+ axisAlignment: widget.value ? - 5.0 : 5.0 ,
317+ axis: Axis .horizontal,
318+ );
319+ }
320+ break ;
321+
322+ case TextTransitionTypes .SCALE :
323+ {
324+ return ScaleTransition (
325+ child: child,
326+ scale: animation,
327+ );
328+ }
329+ break ;
330+ }
331+ },
332+ child: Text (
333+ _value ? widget.onText : widget.offText,
334+ key: ValueKey <bool >(_value),
335+ style: TextStyle (
336+ color: _value
337+ ? widget.onTextColor
338+ : widget.offTextColor),
339+ ),
340+ ),
341+ ),
342+ ),
343+ ),
344+ ),
345+ ),
346+ ],
347+ ),
348+ );
349+ }
350+
351+ Widget buildThumb () {
352+ return AnimatedAlign (
353+ curve: widget.curve,
354+ alignment: _value ? Alignment .centerRight : Alignment .centerLeft,
355+ duration: widget.duration,
356+ child: RotationTransition (
357+ turns: AlwaysStoppedAnimation (animation.value / 360 ),
358+ child: Padding (
359+ padding: const EdgeInsets .all (5.0 ),
360+ child: AnimatedContainer (
361+ duration: widget.duration,
362+ width: widget.thumbSize,
363+ height: widget.thumbSize,
364+ child: widget? .child,
365+ decoration: BoxDecoration (
366+ shape: widget.rounded ? BoxShape .circle : BoxShape .rectangle,
367+ color: _value ? widget.onThumbColor : widget.offThumbColor,
368+ ),
369+ ),
370+ ),
371+ ),
372+ );
373+ }
91374}
0 commit comments