mirror of
https://github.com/flutter/samples.git
synced 2025-11-08 22:09:06 +00:00
add carousel, card_swipe, and focus_image samples (#119)
* add carousel, card_swipe, and focus_image samples * fix image assets * fix more asset images * add repeating animation * fix import * add copyright headers * remove Center widget * imageAssetName * use ClipRect, refactor _SwipeableCardState * use offset.zero * add comments * remove reference to coverflow package * change spread to toList() * refactor coverflow sample don't set width and height use const data -> images * return widget directly, fix formatting * inline transitionsBuilder * image -> imageAssetName * _rectTween() => _createTween() * _expandToPageRoute -> _createRoute * move non-updating widgets out of AnimatedBuilder * code review updates to animations demos
This commit is contained in:
188
animations/lib/src/misc/card_swipe.dart
Normal file
188
animations/lib/src/misc/card_swipe.dart
Normal file
@@ -0,0 +1,188 @@
|
||||
// Copyright 2019 The Flutter team. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/physics.dart';
|
||||
|
||||
class CardSwipeDemo extends StatefulWidget {
|
||||
static String routeName = '/misc/card_swipe';
|
||||
|
||||
@override
|
||||
_CardSwipeDemoState createState() => _CardSwipeDemoState();
|
||||
}
|
||||
|
||||
class _CardSwipeDemoState extends State<CardSwipeDemo> {
|
||||
List<String> fileNames;
|
||||
|
||||
void initState() {
|
||||
super.initState();
|
||||
_resetCards();
|
||||
}
|
||||
|
||||
void _resetCards() {
|
||||
fileNames = [
|
||||
'assets/eat_cape_town_sm.jpg',
|
||||
'assets/eat_new_orleans_sm.jpg',
|
||||
'assets/eat_sydney_sm.jpg',
|
||||
];
|
||||
}
|
||||
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text('Card Swipe'),
|
||||
),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.all(12.0),
|
||||
child: Center(
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: ClipRect(
|
||||
child: Stack(
|
||||
overflow: Overflow.clip,
|
||||
children: <Widget>[
|
||||
for (final fileName in fileNames)
|
||||
SwipeableCard(
|
||||
imageAssetName: fileName,
|
||||
onSwiped: () {
|
||||
setState(() {
|
||||
fileNames.remove(fileName);
|
||||
});
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
RaisedButton(
|
||||
child: const Text('Refill'),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_resetCards();
|
||||
});
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class Card extends StatelessWidget {
|
||||
final String imageAssetName;
|
||||
|
||||
Card(this.imageAssetName);
|
||||
|
||||
Widget build(BuildContext context) {
|
||||
return AspectRatio(
|
||||
aspectRatio: 3 / 5,
|
||||
child: DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(20.0),
|
||||
image: DecorationImage(
|
||||
image: AssetImage(imageAssetName),
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class SwipeableCard extends StatefulWidget {
|
||||
final String imageAssetName;
|
||||
final VoidCallback onSwiped;
|
||||
|
||||
SwipeableCard({
|
||||
this.onSwiped,
|
||||
this.imageAssetName,
|
||||
});
|
||||
|
||||
_SwipeableCardState createState() => _SwipeableCardState();
|
||||
}
|
||||
|
||||
class _SwipeableCardState extends State<SwipeableCard>
|
||||
with SingleTickerProviderStateMixin {
|
||||
AnimationController _controller;
|
||||
Animation<Offset> _animation;
|
||||
double _dragStartX;
|
||||
bool _isSwipingLeft = false;
|
||||
|
||||
void initState() {
|
||||
super.initState();
|
||||
_controller = AnimationController.unbounded(vsync: this);
|
||||
_animation = _controller.drive(Tween<Offset>(
|
||||
begin: Offset.zero,
|
||||
end: Offset(1, 0),
|
||||
));
|
||||
}
|
||||
|
||||
Widget build(BuildContext context) {
|
||||
return SlideTransition(
|
||||
position: _animation,
|
||||
child: GestureDetector(
|
||||
onHorizontalDragStart: _dragStart,
|
||||
onHorizontalDragUpdate: _dragUpdate,
|
||||
onHorizontalDragEnd: _dragEnd,
|
||||
child: Card(widget.imageAssetName),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Sets the starting position the user dragged from.
|
||||
void _dragStart(DragStartDetails details) {
|
||||
_dragStartX = details.localPosition.dx;
|
||||
}
|
||||
|
||||
/// Changes the animation to animate to the left or right depending on the
|
||||
/// swipe, and sets the AnimationController's value to the swiped amount.
|
||||
void _dragUpdate(DragUpdateDetails details) {
|
||||
var isSwipingLeft = (details.localPosition.dx - _dragStartX) < 0;
|
||||
if (isSwipingLeft != _isSwipingLeft) {
|
||||
_isSwipingLeft = isSwipingLeft;
|
||||
_updateAnimation(details.localPosition.dx);
|
||||
}
|
||||
|
||||
setState(() {
|
||||
// Calculate the amount dragged in unit coordinates (between 0 and 1)
|
||||
// using this widgets width.
|
||||
_controller.value =
|
||||
(details.localPosition.dx - _dragStartX).abs() / context.size.width;
|
||||
});
|
||||
}
|
||||
|
||||
/// Runs the fling / spring animation using the final velocity of the drag
|
||||
/// gesture.
|
||||
void _dragEnd(DragEndDetails details) {
|
||||
var velocity =
|
||||
(details.velocity.pixelsPerSecond.dx / context.size.width).abs();
|
||||
_animate(velocity: velocity);
|
||||
}
|
||||
|
||||
void _updateAnimation(double dragPosition) {
|
||||
_animation = _controller.drive(Tween<Offset>(
|
||||
begin: Offset.zero,
|
||||
end: _isSwipingLeft ? Offset(-1, 0) : Offset(1, 0),
|
||||
));
|
||||
}
|
||||
|
||||
void _animate({double velocity = 0}) {
|
||||
var description = SpringDescription(mass: 50, stiffness: 1, damping: 1);
|
||||
var simulation =
|
||||
SpringSimulation(description, _controller.value, 1, velocity);
|
||||
_controller.animateWith(simulation).then((_) {
|
||||
widget.onSwiped();
|
||||
});
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user