Compare commits

...

23 commits

Author SHA1 Message Date
Gorter-dev
eef26a375b
Merge pull request #12 from Iconica-Development/chore/deploy
chore: ready the package for deployment to the pub server
2024-07-22 14:59:39 +02:00
Bart Ribbers
cb432b548f chore: ready the package for deployment to the pub server 2024-07-11 19:38:45 +02:00
Bart Ribbers
6f9e7c863d chore: add fvm configuration to gitignore 2024-07-11 19:36:42 +02:00
Freek van de Ven
4d1edb208e
Merge pull request #11 from Iconica-Development/update-component-documentation-workflow-correct
Add component-documentation.yml correct
2024-02-14 08:06:23 +01:00
Vick Top
537870d922 feat(documentation): Create component-documentation.yml workflow file 2024-02-13 13:36:23 +01:00
Vick Top
f382ec7e59 chore: Remove old component-documentation.yml 2024-02-13 13:36:23 +01:00
Freek van de Ven
3a6b8e0232
Merge pull request #10 from Iconica-Development/update-component-documentation-workflow
Add component-documentation.yml
2024-02-12 20:18:17 +01:00
Vick Top
6a130302cf feat(documentation): Create component-documentation.yml workflow file 2024-02-12 19:08:14 +01:00
mike doornenbal
9f1fff083c Merge branch 'feature/add_ci_flutter_iconica_analysis' 2024-02-02 16:08:09 +01:00
mike doornenbal
7459954bed feat: add iconica linter and CI 2024-02-02 16:07:29 +01:00
Freek van de Ven
34f9b4143b chore: add figma link 2023-12-17 11:50:44 +01:00
Niels Gorter
7644eafa30 fix version 2023-09-26 11:56:03 +02:00
Gorter-dev
c4d82a1667
Merge pull request #8 from Iconica-Development/hotfix/inital_and_scroll
Hotfix/inital and scroll
2023-09-26 10:12:33 +02:00
Niels Gorter
19d008c411 fix linter 2023-09-26 10:12:08 +02:00
Niels Gorter
6a2161ca03 fix linter 2023-09-26 10:10:14 +02:00
Niels Gorter
782361b846 fix linter 2023-09-26 09:57:59 +02:00
Niels Gorter
7992d71076 fix: https://github.com/Iconica-Development/flutter_carousel/issues/5 2023-09-26 09:53:56 +02:00
Thomas Klein Langenhorst
6a55bc823b
Merge pull request #4 from Iconica-Development/fix/fix_pubspec
set version in pubspec to 0.2.0
2022-12-14 14:29:35 +01:00
Thomas Klein Langenhorst
07964e5e96 set version in pubspec to 0.2.0 2022-12-14 14:29:08 +01:00
Thomas Klein Langenhorst
a6254addd4 Updated README, updated GIF, improved example, added dependabot 2022-12-13 16:26:31 +01:00
b16bcf548f Add BSD-3-Clause license 2022-11-01 08:20:01 +01:00
43528119d5
Merge pull request #3 from Iconica-Development/feature/ci
feat: add Github CI
2022-09-27 09:18:22 +02:00
7d514ef5dc feat: add Github CI 2022-09-27 08:54:08 +02:00
24 changed files with 377 additions and 148 deletions

10
.github/dependabot.yaml vendored Normal file
View file

@ -0,0 +1,10 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
- package-ecosystem: "pub"
directory: "/"
schedule:
interval: "daily"

14
.github/workflows/component-ci.yml vendored Normal file
View file

@ -0,0 +1,14 @@
name: Iconica Standard Component CI Workflow
# Workflow Caller version: 2.0.0
on:
pull_request:
workflow_dispatch:
jobs:
call-global-iconica-workflow:
uses: Iconica-Development/.github/.github/workflows/component-ci.yml@master
secrets: inherit
permissions: write-all
with:
subfolder: "." # add optional subfolder to run workflow in

View file

@ -0,0 +1,14 @@
name: Iconica Standard Component Documentation Workflow
# Workflow Caller version: 1.0.0
on:
release:
types: [published]
workflow_dispatch:
jobs:
call-iconica-component-documentation-workflow:
uses: Iconica-Development/.github/.github/workflows/component-documentation.yml@master
secrets: inherit
permissions: write-all

6
.gitignore vendored
View file

@ -20,4 +20,8 @@ doc/api/
*.js.deps *.js.deps
*.js.map *.js.map
.idea .idea
# FVM Version Cache
.fvm/
.fvmrc

View file

@ -1,3 +1,10 @@
## 0.3.1
* Added Iconica CI and Iconica Linter
## 0.3.0
* Added option for backwards infinite scrolling and intial page
## 0.1.0 ## 0.1.0
* add opacity as an option to the card transform * add opacity as an option to the card transform

7
FEATURES.md Normal file
View file

@ -0,0 +1,7 @@
* Every sort of widget can be animated as a card.
* For the animation the following properties can be set between animation frames:
this.x = 0,
this.y = 0,
this.angle = 0,
this.scale = 1,
this.opacity = 1.0,

10
LICENSE
View file

@ -1 +1,9 @@
TODO: Add your license here. Copyright (c) 2022 Iconica, All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -1,18 +1,21 @@
[![pub package](https://img.shields.io/pub/v/flutter_carousel.svg)](https://github.com/Iconica-Development) [![Build status](https://img.shields.io/github/workflow/status/Iconica-Development/flutter_carousel/CI)](https://github.com/Iconica-Development/flutter_carousel/actions/new) [![style: effective dart](https://img.shields.io/badge/style-effective_dart-40c4ff.svg)](https://github.com/tenhobi/effective_dart)
# Carousel # Carousel
Carousel widget. Makes it easier to create card carousels using a list of transforms. 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. Each card can change its rotation, position and scale when swiping the cards.
Supports all platforms. ![Carousel GIF](carousel.gif)
Figma Design that defines this component (only accessible for Iconica developers): https://www.figma.com/file/4WkjwynOz5wFeFBRqTHPeP/Iconica-Design-System?type=design&node-id=357%3A3335&mode=design&t=XulkAJNPQ32ARxWh-1
![Demo video](demo.gif)
## Usage ## Usage
To use this package, add `carousel` as a [dependency in your pubspec.yaml file](https://flutter.dev/docs/development/platform-integration/platform-channels). To use this package, add `carousel` as a dependency in your pubspec.yaml file.
### Example ## How to use
See [Example Code](example/lib/main.dart) for more info. See the [Example Code](example/lib/main.dart) for an example on how to use this package.
## Issues ## Issues
@ -24,4 +27,4 @@ If you would like to contribute to the plugin (e.g. by improving the documentati
## Author ## Author
This carousel for Flutter is developed by [Iconica](https://iconica.nl). You can contact us at <support@iconica.nl> This `carousel` for Flutter is developed by [Iconica](https://iconica.nl). You can contact us at <support@iconica.nl>

View file

@ -1 +1,9 @@
include: package:flutter_lints/flutter.yaml include: package:flutter_iconica_analysis/analysis_options.yaml
# Possible to overwrite the rules from the package
analyzer:
exclude:
linter:
rules:

BIN
carousel.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 MiB

BIN
demo.gif

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.3 MiB

View file

@ -21,6 +21,6 @@
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>1.0</string> <string>1.0</string>
<key>MinimumOSVersion</key> <key>MinimumOSVersion</key>
<string>9.0</string> <string>11.0</string>
</dict> </dict>
</plist> </plist>

View file

@ -272,7 +272,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0; IPHONEOS_DEPLOYMENT_TARGET = 11.0;
MTL_ENABLE_DEBUG_INFO = NO; MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos; SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos; SUPPORTED_PLATFORMS = iphoneos;
@ -350,7 +350,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0; IPHONEOS_DEPLOYMENT_TARGET = 11.0;
MTL_ENABLE_DEBUG_INFO = YES; MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES; ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos; SDKROOT = iphoneos;
@ -399,7 +399,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0; IPHONEOS_DEPLOYMENT_TARGET = 11.0;
MTL_ENABLE_DEBUG_INFO = NO; MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos; SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos; SUPPORTED_PLATFORMS = iphoneos;

View file

@ -0,0 +1,4 @@
extension CapitalizeExtension on String {
String capitalize() =>
isNotEmpty ? "${this[0].toUpperCase()}${substring(1)}" : this;
}

View file

@ -1,7 +1,12 @@
// SPDX-FileCopyrightText: 2022 Iconica
//
// SPDX-License-Identifier: BSD-3-Clause
import 'package:carousel/carousel.dart'; import 'package:carousel/carousel.dart';
import 'package:carousel_example/pokemon.dart'; import 'package:carousel_example/pokemon.dart';
import 'package:carousel_example/pokemon_card.dart'; import 'package:carousel_example/pokemon_card.dart';
import 'package:carousel_example/pokemon_types.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'dart:math' as math; import 'dart:math' as math;
@ -21,14 +26,65 @@ class _CarouselExampleAppState extends State<CarouselExampleApp> {
Pokemon? selected; Pokemon? selected;
final List<Pokemon> pokemons = [ final List<Pokemon> pokemons = [
Pokemon(name: 'Bulbasaur', nr: 1, types: ['grass', 'poison']), Pokemon(
Pokemon(name: 'Charmander', nr: 4, types: ['fire']), name: 'Bulbasaur',
Pokemon(name: 'Squirtle', nr: 7, types: ['water']), nr: 1,
Pokemon(name: 'Caterpie', nr: 10, types: ['bug']), types: [
Pokemon(name: 'Pidgey', nr: 16, types: ['normal', 'flying']), PokemonType.grass,
Pokemon(name: 'Pikachu', nr: 25, types: ['electric']), PokemonType.poison,
Pokemon(name: 'Machop', nr: 66, types: ['fighting']), ],
Pokemon(name: 'Geodude', nr: 74, types: ['rock', 'ground']), ),
Pokemon(
name: 'Charmander',
nr: 4,
types: [
PokemonType.fire,
],
),
Pokemon(
name: 'Squirtle',
nr: 7,
types: [
PokemonType.water,
],
),
Pokemon(
name: 'Caterpie',
nr: 10,
types: [
PokemonType.bug,
],
),
Pokemon(
name: 'Pidgey',
nr: 16,
types: [
PokemonType.normal,
PokemonType.flying,
],
),
Pokemon(
name: 'Pikachu',
nr: 25,
types: [
PokemonType.electric,
],
),
Pokemon(
name: 'Machop',
nr: 66,
types: [
PokemonType.fighting,
],
),
Pokemon(
name: 'Geodude',
nr: 74,
types: [
PokemonType.rock,
PokemonType.ground,
],
),
]; ];
Widget _buildCard(BuildContext context, int index) { Widget _buildCard(BuildContext context, int index) {
@ -50,7 +106,8 @@ class _CarouselExampleAppState extends State<CarouselExampleApp> {
body: Stack( body: Stack(
alignment: Alignment.bottomCenter, alignment: Alignment.bottomCenter,
children: [ children: [
SafeArea( Padding(
padding: const EdgeInsets.all(16.0),
child: ListView( child: ListView(
children: [ children: [
const SizedBox(height: 50), const SizedBox(height: 50),
@ -121,7 +178,7 @@ class _CarouselExampleAppState extends State<CarouselExampleApp> {
), ),
if (selected != null) if (selected != null)
Padding( Padding(
padding: const EdgeInsets.only(bottom: 10), padding: const EdgeInsets.only(bottom: 20),
child: Text('Clicked: ${selected!.name}'), child: Text('Clicked: ${selected!.name}'),
), ),
], ],

View file

@ -1,3 +1,9 @@
// SPDX-FileCopyrightText: 2022 Iconica
//
// SPDX-License-Identifier: BSD-3-Clause
import 'package:carousel_example/pokemon_types.dart';
class Pokemon { class Pokemon {
Pokemon({ Pokemon({
required this.name, required this.name,
@ -6,5 +12,5 @@ class Pokemon {
}); });
String name; String name;
int nr; int nr;
List<String> types = const []; List<PokemonType> types = const [];
} }

View file

@ -1,4 +1,10 @@
// SPDX-FileCopyrightText: 2022 Iconica
//
// SPDX-License-Identifier: BSD-3-Clause
import 'package:carousel_example/extensions/string.dart';
import 'package:carousel_example/pokemon.dart'; import 'package:carousel_example/pokemon.dart';
import 'package:carousel_example/pokemon_types.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class PokemonCard extends StatelessWidget { class PokemonCard extends StatelessWidget {
@ -16,9 +22,11 @@ class PokemonCard extends StatelessWidget {
width: MediaQuery.of(context).size.width / 2.2, width: MediaQuery.of(context).size.width / 2.2,
height: 220, height: 220,
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.blue.shade700, color: Colors.white,
boxShadow: const [ boxShadow: const [
BoxShadow(blurRadius: 4), BoxShadow(
blurRadius: 8,
),
], ],
borderRadius: BorderRadius.circular(15), borderRadius: BorderRadius.circular(15),
), ),
@ -36,29 +44,12 @@ class PokemonCard extends StatelessWidget {
), ),
Padding( Padding(
padding: const EdgeInsets.only(top: 20, bottom: 8), padding: const EdgeInsets.only(top: 20, bottom: 8),
child: Text('Types', style: textStyle), child: Text('Type', style: textStyle),
), ),
Row( Row(
children: [ children: [
for (var type in pokemon.types) ...[ for (var type in pokemon.types) ...[
Container( TypeBadge(type: type),
height: 25,
width: 60,
margin: const EdgeInsets.only(right: 10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: Color(type.hashCode).withAlpha(255),
),
child: Center(
child: Text(
type,
style: const TextStyle(
color: Colors.white,
),
textAlign: TextAlign.center,
),
),
)
], ],
], ],
), ),
@ -68,3 +59,77 @@ class PokemonCard extends StatelessWidget {
); );
} }
} }
class TypeBadge extends StatelessWidget {
const TypeBadge({
super.key,
required this.type,
});
final PokemonType type;
@override
Widget build(BuildContext context) {
return Container(
height: 25,
width: 60,
margin: const EdgeInsets.only(right: 10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: getTypeColor(type),
),
child: Center(
child: Text(
type.name.capitalize(),
style: const TextStyle(
color: Colors.white,
),
textAlign: TextAlign.center,
),
),
);
}
Color getTypeColor(PokemonType type) {
switch (type) {
case PokemonType.fire:
return const Color(0xFFF08030);
case PokemonType.water:
return const Color(0xFF6890F0);
case PokemonType.grass:
return const Color(0xFF78C850);
case PokemonType.normal:
return const Color(0xFFA8A878);
case PokemonType.electric:
return const Color(0xFFF8D030);
case PokemonType.ice:
return const Color(0xFF98D8D8);
case PokemonType.fighting:
return const Color(0xFFC03028);
case PokemonType.poison:
return const Color(0xFFA040A0);
case PokemonType.ground:
return const Color(0xFFE0C068);
case PokemonType.flying:
return const Color(0xFFA890F0);
case PokemonType.psychic:
return const Color(0xFFF85888);
case PokemonType.bug:
return const Color(0xFFA8B820);
case PokemonType.rock:
return const Color(0xFFB8A038);
case PokemonType.ghost:
return const Color(0xFF705898);
case PokemonType.dark:
return const Color(0xFF705848);
case PokemonType.dragon:
return const Color(0xFF7038F8);
case PokemonType.steel:
return const Color(0xFFB8B8D0);
case PokemonType.fairy:
return const Color(0xFFEE99AC);
default:
return const Color(0xFF68A090);
}
}
}

View file

@ -0,0 +1,20 @@
enum PokemonType {
fire,
water,
grass,
normal,
electric,
ice,
fighting,
poison,
ground,
flying,
psychic,
bug,
rock,
ghost,
dark,
dragon,
steel,
fairy,
}

View file

@ -1,3 +1,7 @@
// SPDX-FileCopyrightText: 2022 Iconica
//
// SPDX-License-Identifier: BSD-3-Clause
/// A Flutter package for creating a carousel widget.
library carousel; library carousel;
export 'package:carousel/src/carousel.dart'; export 'package:carousel/src/carousel.dart';

View file

@ -1,3 +1,7 @@
// SPDX-FileCopyrightText: 2022 Iconica
//
// SPDX-License-Identifier: BSD-3-Clause
import 'package:carousel/src/models/card_transform.dart'; import 'package:carousel/src/models/card_transform.dart';
import 'package:carousel/src/widgets/carousel_card.dart'; import 'package:carousel/src/widgets/carousel_card.dart';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
@ -7,7 +11,8 @@ typedef CarouselCardBuilder = Widget Function(BuildContext context, int index);
class Carousel extends StatefulWidget { class Carousel extends StatefulWidget {
/// Animated cards by swiping. /// Animated cards by swiping.
/// Each card can change its rotation, position and scale when swiping the cards. /// Each card can change its rotation, position
/// and scale when swiping the cards.
/// Transform path can be privided using [transforms] /// Transform path can be privided using [transforms]
const Carousel({ const Carousel({
required this.transforms, required this.transforms,
@ -17,8 +22,10 @@ class Carousel extends StatefulWidget {
this.onPageChanged, this.onPageChanged,
this.alignment = AlignmentDirectional.topStart, this.alignment = AlignmentDirectional.topStart,
this.onCardClick, this.onCardClick,
Key? key, this.initialPage = 0,
}) : super(key: key); this.allowInfiniteScrollingBackwards = false,
super.key,
});
/// A list of transforms to calculate the position of the card when swiping. /// 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. /// Every item in the list is one of the possible card positions.
@ -27,7 +34,8 @@ class Carousel extends StatefulWidget {
/// The index of the transform card which acts as the selected card. /// The index of the transform card which acts as the selected card.
final int selectableCardId; final int selectableCardId;
/// Builder for the card given a [context] and a [index] to identify the right card. /// Builder for the card given a [context] and a [index] to
/// identify the right card.
final CarouselCardBuilder builder; final CarouselCardBuilder builder;
/// Called when selected card is changed to the next one. /// Called when selected card is changed to the next one.
@ -42,16 +50,31 @@ class Carousel extends StatefulWidget {
/// Size of the pageview used to capture swipe gestures. /// Size of the pageview used to capture swipe gestures.
final double pageViewHeight; final double pageViewHeight;
/// The page to show when first creating the [Carousel].
final int initialPage;
/// Whether to allow infinite scrolling backwards. Defaults to false. If true,
/// this works by using a very large number of pages (10000).
/// Works in conjunction with [initialPage].
final bool allowInfiniteScrollingBackwards;
@override @override
State<Carousel> createState() => _CarouselState(); State<Carousel> createState() => _CarouselState();
} }
class _CarouselState extends State<Carousel> { class _CarouselState extends State<Carousel> {
final PageController _pageController = PageController(initialPage: 0); late PageController _pageController;
double _currentPage = 0; double _currentPage = 0;
@override @override
void initState() { void initState() {
_pageController = PageController(
initialPage: widget.allowInfiniteScrollingBackwards
? 10000 + widget.initialPage
: widget.initialPage,
);
_currentPage = _pageController.initialPage.toDouble();
_pageController.addListener(() { _pageController.addListener(() {
_currentPage = _pageController.page!; _currentPage = _pageController.page!;
}); });
@ -65,38 +88,36 @@ class _CarouselState extends State<Carousel> {
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) => Stack(
return Stack( alignment: widget.alignment,
alignment: widget.alignment, children: [
children: [ AnimatedBuilder(
AnimatedBuilder( animation: _pageController,
animation: _pageController, builder: (context, _) {
builder: (context, _) { var transitionPos = _currentPage % 1;
final transitionPos = _currentPage % 1; var index = _currentPage.floor();
final index = _currentPage.floor(); var length = widget.transforms.length - 1;
final length = widget.transforms.length - 1;
return Stack( return Stack(
children: [ children: [
for (var i = 0; i < length; i++) ...[ for (var i = 0; i < length; i++) ...[
CarouselCard( CarouselCard(
cardTransform: widget.transforms[i] cardTransform: widget.transforms[i]
.transform(widget.transforms[i + 1], transitionPos), .transform(widget.transforms[i + 1], transitionPos),
child: widget.builder.call(context, index - i), child: widget.builder.call(context, index - i),
), ),
],
], ],
], );
); },
}, ),
), SizedBox(
SizedBox( height: widget.pageViewHeight,
height: widget.pageViewHeight, child: PageView.builder(
child: PageView.builder( scrollBehavior: _MouseSwipeOnWeb(),
scrollBehavior: _MouseSwipeOnWeb(), onPageChanged: widget.onPageChanged,
onPageChanged: widget.onPageChanged, controller: _pageController,
controller: _pageController, itemBuilder: (context, index) => Visibility(
itemBuilder: (context, index) {
return Visibility(
visible: false, visible: false,
maintainState: true, maintainState: true,
maintainAnimation: true, maintainAnimation: true,
@ -116,13 +137,11 @@ class _CarouselState extends State<Carousel> {
), ),
], ],
), ),
); ),
}, ),
), ),
), ],
], );
);
}
} }
class _MouseSwipeOnWeb extends MaterialScrollBehavior { class _MouseSwipeOnWeb extends MaterialScrollBehavior {

View file

@ -1,3 +1,7 @@
// SPDX-FileCopyrightText: 2022 Iconica
//
// SPDX-License-Identifier: BSD-3-Clause
class CardTransform { class CardTransform {
/// Used by [Carousel] to build cards on the correct position. /// Used by [Carousel] to build cards on the correct position.
CardTransform({ CardTransform({
@ -24,15 +28,14 @@ class CardTransform {
/// [transitionPos] is a position value of a swipe for example. /// [transitionPos] is a position value of a swipe for example.
/// [other] is the position, scale, rotation /// [other] is the position, scale, rotation
/// which the current [CardTransform] need to be transformed to. /// which the current [CardTransform] need to be transformed to.
CardTransform transform(CardTransform other, double transitionPos) { CardTransform transform(CardTransform other, double transitionPos) =>
return CardTransform( CardTransform(
x: _transformValue(x, other.x, transitionPos), x: _transformValue(x, other.x, transitionPos),
y: _transformValue(y, other.y, transitionPos), y: _transformValue(y, other.y, transitionPos),
angle: _transformValue(angle, other.angle, transitionPos), angle: _transformValue(angle, other.angle, transitionPos),
scale: _transformValue(scale, other.scale, transitionPos), scale: _transformValue(scale, other.scale, transitionPos),
opacity: _transformValue(opacity, other.opacity, transitionPos), opacity: _transformValue(opacity, other.opacity, transitionPos),
); );
}
double _transformValue(double valueA, double valueB, double transformPos) => double _transformValue(double valueA, double valueB, double transformPos) =>
valueA - ((valueA - valueB) * transformPos); valueA - ((valueA - valueB) * transformPos);

View file

@ -1,3 +1,7 @@
// SPDX-FileCopyrightText: 2022 Iconica
//
// SPDX-License-Identifier: BSD-3-Clause
import 'package:carousel/src/models/card_transform.dart'; import 'package:carousel/src/models/card_transform.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -6,26 +10,24 @@ class CarouselCard extends StatelessWidget {
const CarouselCard({ const CarouselCard({
required this.cardTransform, required this.cardTransform,
required this.child, required this.child,
Key? key, super.key,
}) : super(key: key); });
final CardTransform cardTransform; final CardTransform cardTransform;
final Widget child; final Widget child;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) => Transform.translate(
return Transform.translate( offset: Offset(cardTransform.x, cardTransform.y),
offset: Offset(cardTransform.x, cardTransform.y), child: Transform.rotate(
child: Transform.rotate( angle: cardTransform.angle,
angle: cardTransform.angle, child: Transform.scale(
child: Transform.scale( scale: cardTransform.scale,
scale: cardTransform.scale, child: Opacity(
child: Opacity( opacity: cardTransform.opacity,
opacity: cardTransform.opacity, child: child,
child: child, ),
), ),
), ),
), );
);
}
} }

View file

@ -1,9 +1,11 @@
name: carousel name: carousel
description: card carousel description: card carousel
version: 0.1.0 version: 0.3.1
publish_to: https://forgejo.internal.iconica.nl/api/packages/internal/pub
environment: environment:
sdk: ">=2.17.6 <3.0.0" sdk: ">=3.0.0 <4.0.0"
flutter: ">=1.17.0" flutter: ">=1.17.0"
dependencies: dependencies:
@ -13,41 +15,9 @@ dependencies:
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
sdk: flutter sdk: flutter
flutter_lints: ^2.0.0 flutter_iconica_analysis:
git:
url: https://github.com/Iconica-Development/flutter_iconica_analysis
ref: 6.0.0
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec
# The following section is specific to Flutter packages.
flutter: flutter:
# To add assets to your package, add an assets section, like this:
# assets:
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg
#
# For details regarding assets in packages, see
# https://flutter.dev/assets-and-images/#from-packages
#
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/assets-and-images/#resolution-aware
# To add custom fonts to your package, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a
# "family" key with the font family name, and a "fonts" key with a
# list giving the asset and other descriptors for the font. For
# example:
# fonts:
# - family: Schyler
# fonts:
# - asset: fonts/Schyler-Regular.ttf
# - asset: fonts/Schyler-Italic.ttf
# style: italic
# - family: Trajan Pro
# fonts:
# - asset: fonts/TrajanPro.ttf
# - asset: fonts/TrajanPro_Bold.ttf
# weight: 700
#
# For details regarding fonts in packages, see
# https://flutter.dev/custom-fonts/#from-packages

View file

@ -1,3 +1,7 @@
// SPDX-FileCopyrightText: 2022 Iconica
//
// SPDX-License-Identifier: BSD-3-Clause
import 'dart:math'; import 'dart:math';
import 'package:carousel/src/models/card_transform.dart'; import 'package:carousel/src/models/card_transform.dart';