mirror of
https://github.com/Iconica-Development/flutter_carousel.git
synced 2025-05-19 12:13:46 +02:00
initial commit
This commit is contained in:
parent
e260f49c1e
commit
60dd392b50
8 changed files with 171 additions and 128 deletions
29
README.md
29
README.md
|
@ -1,2 +1,27 @@
|
|||
# carousel
|
||||
card carousel widget
|
||||
# Carousel
|
||||
Carousel widget. Makes it easier to create card carousels using a list of transforms.
|
||||
Each card can change its rotation, position and scale when swiping the cards.
|
||||
|
||||
Supports all platforms.
|
||||
|
||||

|
||||
|
||||
## Usage
|
||||
|
||||
To use this package, add `carousel` as a [dependency in your pubspec.yaml file](https://flutter.dev/docs/development/platform-integration/platform-channels).
|
||||
|
||||
### Example
|
||||
|
||||
See [Example Code](example/lib/main.dart) for more info.
|
||||
|
||||
## Issues
|
||||
|
||||
Please file any issues, bugs or feature request as an issue on our [GitHub](https://github.com/Iconica-Development/carousel) page. Commercial support is available if you need help with integration with your app or services. You can contact us at [support@iconica.nl](mailto:support@iconica.nl).
|
||||
|
||||
## Want to contribute
|
||||
|
||||
If you would like to contribute to the plugin (e.g. by improving the documentation, solving a bug or adding a cool new feature), please carefully review our [contribution guide](./CONTRIBUTING.md) and send us your [pull request](https://github.com/Iconica-Development/carousel/pulls).
|
||||
|
||||
## Author
|
||||
|
||||
This carousel for Flutter is developed by [Iconica](https://iconica.nl). You can contact us at <support@iconica.nl>
|
BIN
demo.gif
Normal file
BIN
demo.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.3 MiB |
|
@ -1,5 +1,5 @@
|
|||
import 'package:carousel/carousel.dart';
|
||||
import 'package:carousel/models/card_transform.dart';
|
||||
|
||||
import 'package:carousel_example/pokemon.dart';
|
||||
import 'package:carousel_example/pokemon_card.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
|
|
@ -1,125 +1,4 @@
|
|||
library carousel;
|
||||
|
||||
export 'package:carousel/carousel.dart';
|
||||
|
||||
import 'package:carousel/models/card_transform.dart';
|
||||
import 'package:carousel/widgets/carousel_card.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
typedef CarouselCardBuilder = Widget Function(BuildContext context, int index);
|
||||
|
||||
class Carousel extends StatefulWidget {
|
||||
const Carousel({
|
||||
required this.transforms,
|
||||
required this.builder,
|
||||
required this.selectableCardId,
|
||||
this.pageViewHeight = 300,
|
||||
this.onPageChanged,
|
||||
this.alignment = AlignmentDirectional.topStart,
|
||||
this.onCardClick,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
/// A list of transforms to calculate the position of the card when swiping.
|
||||
/// Every item in the list is one of the possible card positions.
|
||||
final List<CardTransform> transforms;
|
||||
|
||||
/// The index of the transform card which acts as the selected card.
|
||||
final int selectableCardId;
|
||||
|
||||
/// Builder for the card given a [context] and a [index] to identify the right card.
|
||||
final CarouselCardBuilder builder;
|
||||
|
||||
/// Called when selected card is changed to the next one.
|
||||
final void Function(int value)? onPageChanged;
|
||||
|
||||
// Callen when selected card is clicked.
|
||||
final void Function(int value)? onCardClick;
|
||||
|
||||
/// Alignment of the cards.
|
||||
final AlignmentGeometry alignment;
|
||||
|
||||
/// Size of the pageview used to capture swipe gestures.
|
||||
final double pageViewHeight;
|
||||
|
||||
@override
|
||||
State<Carousel> createState() => _CarouselState();
|
||||
}
|
||||
|
||||
class _CarouselState extends State<Carousel> {
|
||||
final PageController _pageController = PageController(initialPage: 0);
|
||||
double _currentPage = 0;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_pageController.addListener(() {
|
||||
_currentPage = _pageController.page!;
|
||||
});
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_pageController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Stack(
|
||||
alignment: widget.alignment,
|
||||
children: [
|
||||
AnimatedBuilder(
|
||||
animation: _pageController,
|
||||
builder: (context, _) {
|
||||
final transitionPos = _currentPage % 1;
|
||||
final index = _currentPage.floor();
|
||||
final length = widget.transforms.length - 1;
|
||||
|
||||
return Stack(
|
||||
children: [
|
||||
for (var i = 0; i < length; i++) ...[
|
||||
CarouselCard(
|
||||
cardTransform: widget.transforms[i]
|
||||
.transform(widget.transforms[i + 1], transitionPos),
|
||||
child: widget.builder.call(context, index - i),
|
||||
),
|
||||
],
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
SizedBox(
|
||||
height: widget.pageViewHeight,
|
||||
child: PageView.builder(
|
||||
onPageChanged: widget.onPageChanged,
|
||||
controller: _pageController,
|
||||
itemBuilder: (context, index) {
|
||||
return Visibility(
|
||||
visible: false,
|
||||
maintainState: true,
|
||||
maintainAnimation: true,
|
||||
maintainInteractivity: true,
|
||||
maintainSemantics: true,
|
||||
maintainSize: true,
|
||||
child: Stack(
|
||||
alignment: widget.alignment,
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
widget.onCardClick
|
||||
?.call(index - widget.selectableCardId);
|
||||
},
|
||||
child: widget.builder
|
||||
.call(context, index - widget.selectableCardId),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
export 'package:carousel/src/carousel.dart';
|
||||
export 'package:carousel/src/models/card_transform.dart';
|
||||
|
|
134
lib/src/carousel.dart
Normal file
134
lib/src/carousel.dart
Normal file
|
@ -0,0 +1,134 @@
|
|||
import 'package:carousel/src/models/card_transform.dart';
|
||||
import 'package:carousel/src/widgets/carousel_card.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
typedef CarouselCardBuilder = Widget Function(BuildContext context, int index);
|
||||
|
||||
class Carousel extends StatefulWidget {
|
||||
/// Animated cards by swiping.
|
||||
/// Each card can change its rotation, position and scale when swiping the cards.
|
||||
/// Transform path can be privided using [transforms]
|
||||
const Carousel({
|
||||
required this.transforms,
|
||||
required this.builder,
|
||||
required this.selectableCardId,
|
||||
this.pageViewHeight = 300,
|
||||
this.onPageChanged,
|
||||
this.alignment = AlignmentDirectional.topStart,
|
||||
this.onCardClick,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
/// A list of transforms to calculate the position of the card when swiping.
|
||||
/// Every item in the list is one of the possible card positions.
|
||||
final List<CardTransform> transforms;
|
||||
|
||||
/// The index of the transform card which acts as the selected card.
|
||||
final int selectableCardId;
|
||||
|
||||
/// Builder for the card given a [context] and a [index] to identify the right card.
|
||||
final CarouselCardBuilder builder;
|
||||
|
||||
/// Called when selected card is changed to the next one.
|
||||
final void Function(int value)? onPageChanged;
|
||||
|
||||
// Callen when selected card is clicked.
|
||||
final void Function(int value)? onCardClick;
|
||||
|
||||
/// Alignment of the cards.
|
||||
final AlignmentGeometry alignment;
|
||||
|
||||
/// Size of the pageview used to capture swipe gestures.
|
||||
final double pageViewHeight;
|
||||
|
||||
@override
|
||||
State<Carousel> createState() => _CarouselState();
|
||||
}
|
||||
|
||||
class _CarouselState extends State<Carousel> {
|
||||
final PageController _pageController = PageController(initialPage: 0);
|
||||
double _currentPage = 0;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_pageController.addListener(() {
|
||||
_currentPage = _pageController.page!;
|
||||
});
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_pageController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Stack(
|
||||
alignment: widget.alignment,
|
||||
children: [
|
||||
AnimatedBuilder(
|
||||
animation: _pageController,
|
||||
builder: (context, _) {
|
||||
final transitionPos = _currentPage % 1;
|
||||
final index = _currentPage.floor();
|
||||
final length = widget.transforms.length - 1;
|
||||
|
||||
return Stack(
|
||||
children: [
|
||||
for (var i = 0; i < length; i++) ...[
|
||||
CarouselCard(
|
||||
cardTransform: widget.transforms[i]
|
||||
.transform(widget.transforms[i + 1], transitionPos),
|
||||
child: widget.builder.call(context, index - i),
|
||||
),
|
||||
],
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
SizedBox(
|
||||
height: widget.pageViewHeight,
|
||||
child: PageView.builder(
|
||||
scrollBehavior: _MouseSwipeOnWeb(),
|
||||
onPageChanged: widget.onPageChanged,
|
||||
controller: _pageController,
|
||||
itemBuilder: (context, index) {
|
||||
return Visibility(
|
||||
visible: false,
|
||||
maintainState: true,
|
||||
maintainAnimation: true,
|
||||
maintainInteractivity: true,
|
||||
maintainSemantics: true,
|
||||
maintainSize: true,
|
||||
child: Stack(
|
||||
alignment: widget.alignment,
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
widget.onCardClick
|
||||
?.call(index - widget.selectableCardId);
|
||||
},
|
||||
child: widget.builder
|
||||
.call(context, index - widget.selectableCardId),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _MouseSwipeOnWeb extends MaterialScrollBehavior {
|
||||
@override
|
||||
Set<PointerDeviceKind> get dragDevices => {
|
||||
PointerDeviceKind.touch,
|
||||
PointerDeviceKind.mouse,
|
||||
};
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
class CardTransform {
|
||||
/// Used by [Carousel] to build cards on the correct position.
|
||||
CardTransform({
|
||||
this.x = 0,
|
||||
this.y = 0,
|
||||
|
@ -10,6 +11,9 @@ class CardTransform {
|
|||
double angle;
|
||||
double scale;
|
||||
|
||||
/// [transitionPos] is a position value of a swipe for example.
|
||||
/// [other] is the position, scale, rotation
|
||||
/// which the current [CardTransform] need to be transformed to.
|
||||
CardTransform transform(CardTransform other, double transitionPos) {
|
||||
return CardTransform(
|
||||
x: _transformValue(x, other.x, transitionPos),
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:carousel/models/card_transform.dart';
|
||||
import 'package:carousel/src/models/card_transform.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// Transformed card used in [Carousel]
|
||||
class CarouselCard extends StatelessWidget {
|
||||
const CarouselCard({
|
||||
required this.cardTransform,
|
|
@ -1,6 +1,6 @@
|
|||
import 'dart:math';
|
||||
|
||||
import 'package:carousel/models/card_transform.dart';
|
||||
import 'package:carousel/src/models/card_transform.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
|
|
Loading…
Reference in a new issue