How to Create Custom Switch Button in Flutter
Flutter’s materials include a switch button; however, sometimes this button may not be sufficient for your needs. Therefore, in this article, I will show you how to create your own switch button and how to use it.
Creating a Switch Button
●Step 1 Setting Up the Project:
Open a new terminal. Navigate to the directory where you want to create a new Flutter project using terminal commands. Then, use the following command to create a new Flutter project:
flutter create example_project
You can replace “example_project” with the name of the project you want to create. In my case project name is flutter_switch_button.
● Step 2: Add the code below to the main.dart file (located in the lib folder).
import 'package:flutter/material.dart';
import 'package:flutter_switch_button/custom_switch_button.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: CustomSwitch(),
);
}
}
● Step 3: Create a custom_switch_button.dart
file inside the lib folder and add the following code to it.
import 'package:flutter/material.dart';
class CustomSwitch extends StatefulWidget {
final bool value;
final ValueChanged<bool> onChanged;
CustomSwitch({Key? key, required this.value, required this.onChanged})
: super(key: key);
@override
_CustomSwitchState createState() => _CustomSwitchState();
}
class _CustomSwitchState extends State<CustomSwitch>
with SingleTickerProviderStateMixin {
late AnimationController _animationController;
late Animation<Alignment> _circleAnimation;
bool isFirstCircleVisible = false;
@override
void initState() {
super.initState();
_animationController =
AnimationController(vsync: this, duration: Duration(milliseconds: 300));
_circleAnimation = AlignmentTween(
begin: widget.value ? Alignment.centerRight : Alignment.centerLeft,
end: widget.value ? Alignment.centerLeft : Alignment.centerRight,
).animate(CurvedAnimation(
parent: _animationController,
curve: Curves.easeInOut,
));
}
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
if (_animationController.isCompleted) {
_animationController.reverse();
} else {
_animationController.forward();
}
widget.onChanged(!widget.value);
setState(() {
isFirstCircleVisible = !isFirstCircleVisible;
});
},
child: Container(
width: 80.0,
height: 46.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30),
color: Colors.white,
),
child: Stack(
children: [
Align(
alignment: _circleAnimation.value,
child: Container(
alignment: widget.value
? ((Directionality.of(context) == TextDirection.rtl)
? Alignment.centerLeft
: Alignment.centerRight)
: ((Directionality.of(context) == TextDirection.rtl)
? Alignment.centerRight
: Alignment.centerLeft),
child: Container(
width: 40.0,
height: 40.0,
decoration: BoxDecoration(
color: widget.value ? Colors.green:Colors.pink,
shape: BoxShape.circle,
),
)
),
),
],
),
),
);
}
@override
void dispose() {
_animationController.dispose();
super.dispose();
}
}
Code Explanation
- CustomSwitch Class: Define a new StatefulWidget called
CustomSwitch
. It takes two required parameters,value
(a boolean indicating the current state of the switch) andonChanged
(a callback function that will be called when the switch state changes). - _CustomSwitchState Class: Create the state class
_CustomSwitchState
for theCustomSwitch
widget. - Animation Setup: Initialize an
AnimationController
and anAnimation
to control the animation of the switch. The animation is an alignment animation that controls the position of a circle within the switch.isFirstCircleVisible
is a boolean variable to track the visibility of the first circle. - InitState Method: Override the
initState
method to initialize the animation controller and set up the animation with appropriate values based on the initial state of the switch. - Build Method: Override the
build
method to create the widget tree. It returns aGestureDetector
that responds to taps. When tapped, it triggers the animation controller to either forward or reverse the animation, calls theonChanged
callback, and updates the visibility of the first circle. - Container Structure: The main visual representation of the switch is contained within a
Container
. It has a white background, rounded corners, and a fixed size. - Stack and Align Widgets: Use a
Stack
widget to overlay two containers representing the switch's on and off states. The position of the circle is controlled by theAlign
widget using the animation values. - Circle Decoration: The circle has a dynamic color based on the visibility of the first circle (
isFirstCircleVisible
). It is either green or red. - Dispose Method: Override the
dispose
method to properly dispose of the animation controller when the widget is no longer needed, preventing memory leaks.
Usage
The code example below demonstrates how to use a switch button we created.
import 'package:flutter/material.dart';
import 'package:flutter_switch_button/custom_switch_button.dart';
class MyWidget extends StatefulWidget {
const MyWidget({super.key});
@override
State<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
bool _enable = false;
@override
Widget build(BuildContext context) {
return Center(
child: CustomSwitch(
value: _enable,
onChanged: (bool val){
setState(() {
_enable = val;
});
},
),
);
}
}
Example
Instead of using the ‘container,’ you can use ‘icon’ as an example.
child: Image.asset(
isFirstCircleVisible
? 'assets/icons/switch_button_green.png'
: 'assets/icons/switch_button_pink.png',
height: 50,
width: 50,
),
Happy Coding!