Skip to content

Instantly share code, notes, and snippets.

@amirrezasalimi
Last active February 24, 2024 23:12
Show Gist options
  • Save amirrezasalimi/48132d9330f53672a894829961cb727b to your computer and use it in GitHub Desktop.
Save amirrezasalimi/48132d9330f53672a894829961cb727b to your computer and use it in GitHub Desktop.
flutter toggle password animation v2
import 'package:flutter/material.dart';
//create by Amirreza salimi https://gist.github.com/amirrezasalimi/48132d9330f53672a894829961cb727b/
class ToggleInput extends StatefulWidget {
@override
ToggleInputState createState() => ToggleInputState();
}
class ToggleInputState extends State<ToggleInput>
with TickerProviderStateMixin {
bool isHidden = false;
Animation<double> scaleF;
AnimationController scaleAnim;
Animation<Offset> eyeF;
@override
void initState() {
super.initState();
double maxScale = 14;
scaleAnim = AnimationController(
vsync: this, duration: Duration(milliseconds: 300), value: 1);
scaleF = Tween<double>(begin: 1, end: maxScale).animate(scaleAnim);
scaleAnim.addListener(() {
setState(() {});
});
//+3,-3 to -3,0
eyeF = Tween<Offset>(begin: Offset(3, -3), end: Offset(-3, 0))
.animate(scaleAnim);
}
@override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
return Container(
child: FractionallySizedBox(
widthFactor: 0.85,
child: Container(
height: 80,
child: ClipRRect(
borderRadius: BorderRadius.circular(18.0),
clipBehavior: Clip.antiAliasWithSaveLayer,
child: Stack(
children: [
Container(
decoration: BoxDecoration(
color: Color(0xff121726),
),
),
Positioned(
right: 10,
top: (80 - 50) / 2,
child: Transform.scale(
scale: scaleF.value,
child: SizedBox(
width: 50,
height: 50,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(80),
color: Colors.white),
)),
),
),
Positioned(
left: 10,
top: (80 - 27) / 2,
child: Icon(
Icons.lock,
color: isHidden ? Colors.white : Colors.black,
size: 27,
),
),
Positioned(
left: 27 + 12.0,
top: (80 - 50) / 2,
child: Container(
width: size.width * 0.60,
child: TextField(
textAlign: TextAlign.left,
obscureText: isHidden,
cursorColor: isHidden ? Colors.white : Colors.black,
controller: TextEditingController(text: "f2bfd5g"),
style: TextStyle(
color:
isHidden ? Color(0xff575cba) : Colors.black,
fontSize: isHidden ? 28 : 20),
decoration: InputDecoration(
contentPadding: EdgeInsets.only(left: 5),
border: InputBorder.none,
focusedBorder: InputBorder.none,
enabledBorder: InputBorder.none,
errorBorder: InputBorder.none,
disabledBorder: InputBorder.none,
),
),
)),
Positioned(
right: 10,
top: (80 - 50) / 2,
child: GestureDetector(
onTap: () {
setState(() {
if (!isHidden) {
scaleAnim.reverse();
} else {
scaleAnim.forward();
}
isHidden = !isHidden;
});
},
child: Container(
width: 50,
height: 50,
decoration: BoxDecoration(
color: Colors.transparent,
borderRadius: BorderRadius.circular(80)),
child: Center(
child: SizedBox(
width: 30,
height: 35,
child: CustomPaint(
painter: Eye(eyeF.value),
),
),
)),
),
)
],
),
),
)),
);
}
}
class Eye extends CustomPainter {
Offset eyeMove;
Eye(this.eyeMove);
@override
void paint(Canvas canvas, Size size) {
Paint eye_paint = Paint()
..style = PaintingStyle.stroke
..strokeWidth = 2
..color = Color(0xff575cba);
double marginTop = 5;
double marginSides = 3;
//top
Path top_h = Path();
top_h.moveTo(marginSides, (size.height / 2) + marginTop);
top_h.quadraticBezierTo(size.width / 2, (size.height / 2) - (marginTop * 2),
size.width - marginSides, (size.height / 2) + marginTop);
top_h.moveTo(size.width - marginSides, (size.height / 2) + marginTop);
//eyelash +
double c = (size.height / 2) - marginTop / 2;
//1
top_h.moveTo(marginSides + 4, c + 3);
top_h.lineTo(marginSides, c - 3);
//2
top_h.moveTo(size.width / 2, c);
top_h.lineTo(size.width / 2, c - 7);
//3
top_h.moveTo(size.width - marginSides - 4, c + 3);
top_h.lineTo(size.width - marginSides, c - 3);
//eyeball
top_h.close();
Paint eyeball_paint = Paint()
..style = PaintingStyle.fill
..color = Color(0xff575cba);
canvas.drawCircle(
Offset(size.width / 2 + eyeMove.dx,
c + marginTop + (marginTop / 2) + eyeMove.dy),
3.4,
eyeball_paint);
canvas.drawPath(top_h, eye_paint);
//bottom
Path bottom_h = Path();
bottom_h.moveTo(marginSides, (size.height / 2) + marginTop);
bottom_h.quadraticBezierTo(size.width / 2, size.height,
size.width - marginSides, (size.height / 2) + marginTop);
canvas.drawPath(bottom_h, eye_paint);
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return this != oldDelegate;
}
}
void main() {
runApp(
MaterialApp(
home: Scaffold(
backgroundColor: Colors.blue,
body: Container(
child: Center(child: ToggleInput()),
))),
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment