Skip to content

Instantly share code, notes, and snippets.

@DaniyarGilimov
Created July 8, 2019 16:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DaniyarGilimov/e152c02cdf184c905dbcfe8e838b7097 to your computer and use it in GitHub Desktop.
Save DaniyarGilimov/e152c02cdf184c905dbcfe8e838b7097 to your computer and use it in GitHub Desktop.
Card widget, it's like a real playing card
import 'package:flutter/material.dart';
class CardItem extends StatefulWidget {
CardItem({Key key, this.color, this.value}) : super(key: key);
final int value;
final Color color;
_CardItemState createState() => _CardItemState();
}
class _CardItemState extends State<CardItem> with TickerProviderStateMixin {
// Animation used to slide the card to some position, after dragging ends
AnimationController controller;
Animation<double> animation;
bool isDragging = false; //shows if card is dragging by finger
bool isAnimating = false; //shows if card is thowing(sliding)
double x; //card position in X axis
double y; //card position in Y axis
// Animation used to center the card, after finger touches card
AnimationController controllerCentering;
Animation<double> animationCentering;
//varibles used to center the card, after finger touches card
double dx = 0;
double dy = 0;
double dxx = 0;
double dyy = 0;
// Current position of finger while dragging
double currentPanPositionX = 0;
double currentPanPositionY = 0;
// Position of finger when it starts dragging
double firstPanPositionX = 0;
double firstPanPositionY = 0;
@override
void initState() {
controller = AnimationController(
duration: const Duration(milliseconds: 500), vsync: this);
animation = Tween<double>(begin: 0, end: 250)
.chain(new CurveTween(
curve: Curves.easeOutQuad,
))
.animate(controller)
..addListener(() {})
..addStatusListener((AnimationStatus status) {
if (status == AnimationStatus.completed) {
setState(() {
isAnimating = false;
});
}
});
controllerCentering = AnimationController(
duration: const Duration(milliseconds: 500), vsync: this);
animationCentering = Tween<double>(begin: 0, end: 1)
.chain(new CurveTween(
curve: Curves.easeOutQuad,
))
.animate(controller)
..addListener(() {})
..addStatusListener((AnimationStatus status) {
if (status == AnimationStatus.completed) {
setState(() {});
}
});
isDragging = false;
x = 0;
y = 0;
super.initState();
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
// dragging card
void _onTapUpdate(DragUpdateDetails details) {
if (isAnimating) return;
setState(() {
// setting finger position to card position, dx and dy describes centering the card after first touch
x = details.globalPosition.dx - dx;
y = details.globalPosition.dy - dy;
//setting current drag position
currentPanPositionX = details.globalPosition.dx;
currentPanPositionY = details.globalPosition.dy;
isDragging = true;
isAnimating = false;
});
}
//when finger touches the card
void _onPanStart(DragStartDetails startDetails) {
setState(() {
//setting finger first touch details
firstPanPositionX = startDetails.globalPosition.dx;
firstPanPositionY = startDetails.globalPosition.dy;
currentPanPositionX = firstPanPositionX;
currentPanPositionY = firstPanPositionY;
//centering the card
dxx = (x - firstPanPositionX).abs();
dyy = (y - firstPanPositionY).abs();
animationCentering = Tween<double>(begin: 0, end: 1)
.chain(new CurveTween(
curve: Curves.easeOutQuad,
))
.animate(controllerCentering)
..addListener(() {
setState(() {
dx = dxx + (37.5 - dxx) * animationCentering.value;
dy = dyy + (175 - dyy) * animationCentering.value;
x = currentPanPositionX - dx;
y = currentPanPositionY - dy;
});
})
..addStatusListener((AnimationStatus status) {
if (status == AnimationStatus.completed) {
dx = 37.5;
dy = 175;
}
});
controllerCentering.forward(from: 0.0);
});
}
//when dragging is ended, and card slides to some position, in our case to endPointX
void _onPanEnd(DragEndDetails endDetails) {
double endPointX;
// checking if card position on left side or on right side
if (x < MediaQuery.of(context).size.width / 2) {
endPointX = 0;
} else {
endPointX = MediaQuery.of(context).size.width - 70;
}
setState(() {
isDragging = false;
isAnimating = true;
animation = Tween<double>(begin: x, end: endPointX)
.chain(new CurveTween(
curve: Curves.easeOutQuad,
))
.animate(controller)
..addListener(() {
setState(() {});
})
..addStatusListener((AnimationStatus status) {
if (status == AnimationStatus.completed) {
setState(() {
isAnimating = false;
x = animation.value;
});
}
});
controller.forward(from: 0.0);
isDragging = false;
});
}
@override
Widget build(BuildContext context) {
return Positioned(
left: (isDragging) ? x : (isAnimating) ? animation.value : x,
top: y,
child: SizedBox(
width: 75,
height: 125,
child: GestureDetector(
onPanUpdate: (DragUpdateDetails details) {
if (!isAnimating) {
_onTapUpdate(details);
}
},
onPanEnd: (DragEndDetails endDetails) => _onPanEnd(endDetails),
onPanStart: (DragStartDetails startDetails) {
if (!isAnimating) {
_onPanStart(startDetails);
}
},
child: Container(
color: widget.color,
width: double.infinity,
height: double.infinity,
),
)),
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment