Last active
January 5, 2022 16:41
-
-
Save theachoem/071c1d441bd5c7021a3326129537a66f to your computer and use it in GitHub Desktop.
Tap Effect includes Scale down + Touchable Opacity (Flutter)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright 2021, Thea Choem, All rights reserved. | |
import 'package:flutter/material.dart'; | |
enum TapEffectType { | |
touchableOpacity, | |
scaleDown, | |
} | |
class CustomTapEffect extends StatefulWidget { | |
const CustomTapEffect({ | |
Key? key, | |
required this.child, | |
required this.onTap, | |
this.duration = const Duration(milliseconds: 100), | |
this.vibrate = false, | |
this.behavior = HitTestBehavior.opaque, | |
this.effects = const [ | |
TapEffectType.touchableOpacity, | |
], | |
this.onLongPressed, | |
}) : super(key: key); | |
final Widget child; | |
final List<TapEffectType> effects; | |
final void Function()? onTap; | |
final void Function()? onLongPressed; | |
final Duration duration; | |
final bool vibrate; | |
final HitTestBehavior? behavior; | |
@override | |
State<CustomTapEffect> createState() => _CustomTapEffectState(); | |
} | |
class _CustomTapEffectState extends State<CustomTapEffect> with SingleTickerProviderStateMixin { | |
final double scaleActive = 0.98; | |
final double opacityActive = 0.2; | |
late AnimationController controller; | |
late Animation<double> animation; | |
late Animation<double> animation2; | |
@override | |
void initState() { | |
controller = AnimationController(vsync: this, duration: widget.duration); | |
animation = Tween<double>(begin: 1, end: scaleActive).animate(controller); | |
animation2 = Tween<double>(begin: 1, end: opacityActive).animate(controller); | |
super.initState(); | |
} | |
@override | |
void dispose() { | |
controller.dispose(); | |
super.dispose(); | |
} | |
void onTapCancel() => controller.reverse(); | |
void onTapDown() => controller.forward(); | |
void onTapUp() => controller.reverse().then((value) => widget.onTap!()); | |
@override | |
Widget build(BuildContext context) { | |
if (widget.onTap != null) { | |
return GestureDetector( | |
behavior: widget.behavior, | |
onLongPress: widget.onLongPressed, | |
onTapDown: (detail) => onTapDown(), | |
onTapUp: (detail) => onTapUp(), | |
onTapCancel: () => onTapCancel(), | |
child: buildChild(controller, animation, animation2), | |
); | |
} else { | |
return buildChild(controller, animation, animation2); | |
} | |
} | |
AnimatedBuilder buildChild( | |
AnimationController controller, | |
Animation<double> animation, | |
Animation<double> animation2, | |
) { | |
return AnimatedBuilder( | |
child: widget.child, | |
animation: controller, | |
builder: (context, child) { | |
Widget result = child ?? const SizedBox(); | |
for (var effect in widget.effects) { | |
switch (effect) { | |
case TapEffectType.scaleDown: | |
result = ScaleTransition(scale: animation, child: result); | |
break; | |
case TapEffectType.touchableOpacity: | |
result = Opacity(opacity: animation2.value, child: result); | |
break; | |
} | |
} | |
return result; | |
}, | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I use it in several apps include StoryPad.