Implementation of image carousel with carousel_slider library

This commit is contained in:
Hank Grabowski 2023-01-29 22:36:01 -05:00
parent 8fad35ed33
commit b23f45a180
3 changed files with 52 additions and 88 deletions

View file

@ -1,6 +1,7 @@
import 'dart:io'; import 'dart:io';
import 'package:cached_network_image/cached_network_image.dart'; import 'package:cached_network_image/cached_network_image.dart';
import 'package:carousel_slider/carousel_slider.dart';
import 'package:file_picker/file_picker.dart'; import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_file_dialog/flutter_file_dialog.dart'; import 'package:flutter_file_dialog/flutter_file_dialog.dart';
@ -19,7 +20,7 @@ class ImageViewerScreen extends StatefulWidget {
const ImageViewerScreen({ const ImageViewerScreen({
super.key, super.key,
required this.attachments, required this.attachments,
int this.initialIndex = 0, this.initialIndex = 0,
}); });
@override @override
@ -27,11 +28,12 @@ class ImageViewerScreen extends StatefulWidget {
} }
class _ImageViewerScreenState extends State<ImageViewerScreen> { class _ImageViewerScreenState extends State<ImageViewerScreen> {
var index = 0; MediaAttachment? currentAttachment;
@override @override
void initState() { void initState() {
index = widget.initialIndex; super.initState();
currentAttachment = widget.attachments[widget.initialIndex];
} }
Future<void> saveImage( Future<void> saveImage(
@ -71,109 +73,62 @@ class _ImageViewerScreenState extends State<ImageViewerScreen> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
print('Index: $index'); final width = MediaQuery.of(context).size.width;
final attachment = widget.attachments[index];
final height = MediaQuery.of(context).size.height; final height = MediaQuery.of(context).size.height;
final carouselHeight =
widget.attachments.length == 1 ? height * 0.9 : height * 0.8;
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
actions: [ actions: [
IconButton( IconButton(
onPressed: () => saveImage(context, attachment), onPressed: currentAttachment == null
? null
: () => saveImage(context, currentAttachment!),
icon: const Icon(Icons.download)) icon: const Icon(Icons.download))
], ],
), ),
body: SafeArea( body: SafeArea(
child: Stack( child: Column(
children: [ children: [
GestureDetector( CarouselSlider.builder(
onHorizontalDragEnd: (details) { itemCount: widget.attachments.length,
final velocity = details.primaryVelocity ?? 0.0; itemBuilder: (context, index, realIndex) {
print('Velocity: $velocity'); return SizedBox(
if (velocity > 0 && index > 0) { width: width,
setState(() { height: carouselHeight,
index--; child: InteractiveViewer(
}); maxScale: 10.0,
} scaleFactor: 400,
child: CachedNetworkImage(
if (velocity < 0 && index < widget.attachments.length - 1) { imageUrl: widget.attachments[index].uri.toString()),
setState(() { ),
index++; );
});
}
}, },
child: buildCoreViewer(attachment), options: CarouselOptions(
height: carouselHeight,
initialPage: widget.initialIndex,
enableInfiniteScroll: false,
enlargeCenterPage: true,
viewportFraction: 0.95,
onPageChanged: (index, reason) {
setState(() {
currentAttachment = widget.attachments[index];
});
}),
), ),
if (index > 0) if (currentAttachment != null) buildTextArea(currentAttachment!),
Positioned(
top: height / 2,
left: 0.0,
child: buildButton(
Icon(Icons.keyboard_arrow_left),
onPressed: () {
setState(() {
index--;
});
},
),
),
if (index < widget.attachments.length - 1)
Positioned(
top: height / 2,
right: 0.0,
child: buildButton(
Icon(Icons.keyboard_arrow_right),
onPressed: () {
setState(() {
index++;
});
},
),
),
], ],
), ),
), ),
); );
} }
Widget buildCoreViewer(MediaAttachment attachment) { Widget buildTextArea(MediaAttachment attachment) {
final width = MediaQuery.of(context).size.width; return Expanded(
final height = MediaQuery.of(context).size.height; child: SingleChildScrollView(
return Column( child: Padding(
mainAxisAlignment: MainAxisAlignment.start, padding: const EdgeInsets.all(8.0),
crossAxisAlignment: CrossAxisAlignment.start, child: Text(attachment.description),
children: [
SizedBox(
width: width,
height: 0.8 * height,
child: InteractiveViewer(
maxScale: 10.0,
scaleFactor: 400,
child: CachedNetworkImage(imageUrl: attachment.uri.toString()),
),
),
Expanded(
child: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(attachment.description),
),
),
),
],
);
}
Widget buildButton(Icon icon, {required Function() onPressed}) {
return Center(
child: Ink(
decoration: ShapeDecoration(
color: Theme.of(context).focusColor,
shape: CircleBorder(),
),
child: IconButton(
icon: icon,
color: Colors.white,
onPressed: onPressed,
), ),
), ),
); );

View file

@ -137,6 +137,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.2" version: "1.0.2"
carousel_slider:
dependency: "direct main"
description:
name: carousel_slider
sha256: "9c695cc963bf1d04a47bd6021f68befce8970bcd61d24938e1fb0918cf5d9c42"
url: "https://pub.dev"
source: hosted
version: "4.2.1"
characters: characters:
dependency: transitive dependency: transitive
description: description:

View file

@ -42,6 +42,7 @@ dependencies:
objectbox: ^1.7.1 objectbox: ^1.7.1
objectbox_flutter_libs: ^1.7.1 objectbox_flutter_libs: ^1.7.1
path_provider: ^2.0.11 path_provider: ^2.0.11
carousel_slider: ^4.2.1
dev_dependencies: dev_dependencies:
flutter_test: flutter_test: