bluefireteam / photo_view

📸 Easy to use yet very customizable zoomable image widget for Flutter, Photo View provides a gesture sensitive zoomable widget. Photo View is largely used to show interacive images and other stuff such as SVG.
MIT License
1.91k stars 547 forks source link

Zoom in on Flutter's latest sdk 3.22.1 is abnormal and cannot be zoomed out with a click. #557

Open wahkim opened 5 months ago

wahkim commented 5 months ago

Doctor summary (to see all details, run flutter doctor -v): [✓] Flutter (Channel stable, 3.22.1, on macOS 13.6.1 22G313 darwin-x64, locale zh-Hans-CN) [✓] Android toolchain - develop for Android devices (Android SDK version 33.0.0-rc1) [✓] Xcode - develop for iOS and macOS (Xcode 15.0.1) [✓] Chrome - develop for the web [✓] Android Studio (version 2021.3) [✓] VS Code (version 1.89.1) [✓] Network resources

Uploading RPReplay_Final1717070947.mov…

======================== `import 'package:flutter/material.dart'; import 'package:flutter_quill_demo/gallery_example_item.dart'; import 'package:photo_view/photo_view.dart'; import 'package:photo_view/photo_view_gallery.dart';

class GalleryExample extends StatefulWidget { @override _GalleryExampleState createState() => _GalleryExampleState(); }

class _GalleryExampleState extends State { bool verticalGallery = false;

@override Widget build(BuildContext context) { return ExampleAppBarLayout( title: "Gallery Example", showGoBack: true, child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Row( mainAxisAlignment: MainAxisAlignment.center, children: [ GalleryExampleItemThumbnail( galleryExampleItem: galleryItems[0], onTap: () { open(context, 0); }, ), GalleryExampleItemThumbnail( galleryExampleItem: galleryItems[1], onTap: () { open(context, 1); }, ), GalleryExampleItemThumbnail( galleryExampleItem: galleryItems[2], onTap: () { open(context, 2); }, ), ], ), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ const Text("Vertical"), Checkbox( value: verticalGallery, onChanged: (value) { setState(() { verticalGallery = value!; }); }, ), ], ), ], ), ), ); }

void open(BuildContext context, final int index) { Navigator.push( context, MaterialPageRoute( builder: (context) => GalleryPhotoViewWrapper( galleryItems: galleryItems, backgroundDecoration: const BoxDecoration( color: Colors.black, ), initialIndex: index, scrollDirection: verticalGallery ? Axis.vertical : Axis.horizontal, ), ), ); } }

class GalleryPhotoViewWrapper extends StatefulWidget { GalleryPhotoViewWrapper({ this.loadingBuilder, this.backgroundDecoration, this.minScale, this.maxScale, this.initialIndex = 0, required this.galleryItems, this.scrollDirection = Axis.horizontal, }) : pageController = PageController(initialPage: initialIndex);

final LoadingBuilder? loadingBuilder; final BoxDecoration? backgroundDecoration; final dynamic minScale; final dynamic maxScale; final int initialIndex; final PageController pageController; final List galleryItems; final Axis scrollDirection;

@override State createState() { return _GalleryPhotoViewWrapperState(); } }

class _GalleryPhotoViewWrapperState extends State { late int currentIndex = widget.initialIndex;

void onPageChanged(int index) { setState(() { currentIndex = index; }); }

@override Widget build(BuildContext context) { return Scaffold( body: Container( decoration: widget.backgroundDecoration, constraints: BoxConstraints.expand( height: MediaQuery.of(context).size.height, ), child: Stack( alignment: Alignment.bottomRight, children: [ PhotoViewGallery.builder( scrollPhysics: const BouncingScrollPhysics(), builder: _buildItem, itemCount: widget.galleryItems.length, loadingBuilder: widget.loadingBuilder, backgroundDecoration: widget.backgroundDecoration, pageController: widget.pageController, onPageChanged: onPageChanged, scrollDirection: widget.scrollDirection, ), Container( padding: const EdgeInsets.all(20.0), child: Text( "Image ${currentIndex + 1}", style: const TextStyle( color: Colors.white, fontSize: 17.0, decoration: null, ), ), ) ], ), ), ); }

PhotoViewGalleryPageOptions _buildItem(BuildContext context, int index) { final GalleryExampleItem item = widget.galleryItems[index]; return PhotoViewGalleryPageOptions( imageProvider: AssetImage(item.resource), initialScale: PhotoViewComputedScale.contained, minScale: PhotoViewComputedScale.contained (0.5 + index / 10), maxScale: PhotoViewComputedScale.covered 4.1, heroAttributes: PhotoViewHeroAttributes(tag: item.id), ); } }

class ExampleAppBarLayout extends StatelessWidget { const ExampleAppBarLayout({ Key? key, required this.title, this.showGoBack = false, required this.child, }) : super(key: key);

final String title; final bool showGoBack; final Widget child;

@override Widget build(BuildContext context) { return Scaffold( backgroundColor: const Color.fromARGB(255, 255, 255, 255), body: Container( height: MediaQuery.of(context).size.height, child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ ExampleAppBar( title: title, showGoBack: showGoBack, ), Expanded( child: child, ), ], ), ), ); } }

class ExampleAppBar extends StatelessWidget { const ExampleAppBar({required this.title, this.showGoBack = false}) : super();

final String title; final bool showGoBack;

@override Widget build(BuildContext context) { return SafeArea( child: Container( padding: const EdgeInsets.fromLTRB(20.0, 5.0, 20.0, 5.0), decoration: const BoxDecoration( color: Colors.white, borderRadius: const BorderRadius.only( bottomLeft: const Radius.circular(10.0), bottomRight: const Radius.circular(10.0), ), boxShadow: [ const BoxShadow( color: Colors.black12, spreadRadius: 10.0, blurRadius: 20.0) ]), child: Row( children: [ Container( child: showGoBack ? IconButton( icon: const Icon(Icons.chevron_left), onPressed: () { Navigator.pop(context); }, padding: EdgeInsets.zero, ) : Container( height: 50.0, ), ), Expanded( child: Text( title, style: const TextStyle( fontSize: 25.0, fontWeight: FontWeight.w700), ), ) ], ), ), ); } } `