samples/animations/lib/src/misc/carousel.dart

109 lines
2.8 KiB

// 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 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
class CarouselDemo extends StatelessWidget {
static String routeName = '/misc/carousel';
static const List<String> fileNames = [
'assets/eat_cape_town_sm.jpg',
'assets/eat_new_orleans_sm.jpg',
'assets/eat_sydney_sm.jpg',
];
final List<Widget> images =
fileNames.map((file) => Image.asset(file, fit: BoxFit.cover)).toList();
@override
Widget build(context) {
return Scaffold(
appBar: AppBar(
title: const Text('Carousel Demo'),
),
body: Center(
child: Padding(
padding: const EdgeInsets.all(16),
child: AspectRatio(
aspectRatio: 1,
child: Carousel(itemBuilder: widgetBuilder),
),
),
),
);
}
Widget widgetBuilder(BuildContext context, int index) {
return images[index % images.length];
}
}
typedef OnCurrentItemChangedCallback = void Function(int currentItem);
class Carousel extends StatefulWidget {
final IndexedWidgetBuilder itemBuilder;
const Carousel({Key? key, required this.itemBuilder}) : super(key: key);
@override
_CarouselState createState() => _CarouselState();
}
class _CarouselState extends State<Carousel> {
late final PageController _controller;
late int _currentPage;
bool _pageHasChanged = false;
@override
void initState() {
super.initState();
_currentPage = 0;
_controller = PageController(
viewportFraction: .85,
initialPage: _currentPage,
);
}
@override
Widget build(context) {
var size = MediaQuery.of(context).size;
return PageView.builder(
onPageChanged: (value) {
setState(() {
_pageHasChanged = true;
_currentPage = value;
});
},
controller: _controller,
itemBuilder: (context, index) => AnimatedBuilder(
animation: _controller,
builder: (context, child) {
var result = _pageHasChanged ? _controller.page! : _currentPage * 1.0;
// The horizontal position of the page between a 1 and 0
var value = result - index;
value = (1 - (value.abs() * .5)).clamp(0.0, 1.0);
return Center(
child: SizedBox(
height: Curves.easeOut.transform(value) * size.height,
width: Curves.easeOut.transform(value) * size.width,
child: child,
),
);
},
child: widget.itemBuilder(context, index),
),
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
}