cant use Dismissible widget with PhotoViewGallery - flutter

I'm trying to use Dismissible widget to close or dismiss the PhotoViewGallery Widget when scroll vertical
This is app with Dismissible widget : https://ibb.co/SRcQR2Thttps://ibb.co/K0x5883
This Image is app without Dismissible widget : https://ibb.co/SRcQR2T
if you notice that wihtout Dismissible widget you can easily scroll horizontal to change the image
but when i use the Dismissible widget to add dismiss option when you drag vertical, it`s hard to change images (drag horizontal).
Dismissible(
key: GlobalKey(),
direction: DismissDirection.vertical,
onDismissed: (_) => Get.back(),
child: StreamBuilder(
stream: stream,
initialData: 1.0,
builder: (context, snapshot) {
return Listener(
onPointerDown: (event) {
startPosition = event.position.dy;
},
onPointerUp: (event) {
opacity = 1.0;
streamController.add(opacity);
},
onPointerMove: (details) {
if (details.position.dy > startPosition) {
var move = details.position.dy - startPosition;
move = move / 1.sw;
opacity = 1 - move;
streamController.add(opacity);
}
},
child: Opacity(
opacity: snapshot.data,
child: Scaffold(
body: GestureDetector(
onTap: () => isBarsVisible.value =
isBarsVisible.value ? false : true,
child: Container(
constraints: BoxConstraints.expand(height: 1.sh),
child: Stack(
alignment: Alignment.bottomRight,
children: [
//Image
PhotoViewGallery.builder(
scrollPhysics: const BouncingScrollPhysics(),
builder: (BuildContext context, int index) =>
PhotoViewGalleryPageOptions(
imageProvider: galleries![index],
initialScale: PhotoViewComputedScale.contained,
minScale: minScale ??
PhotoViewComputedScale.contained * 1,
// (0.5 + index / 10),
maxScale: maxScale ??
PhotoViewComputedScale.contained * 2.5,
heroAttributes: PhotoViewHeroAttributes(
tag: galleries![index].toString()),
),
itemCount: galleries!.length,
loadingBuilder: loadingBuilder,
backgroundDecoration:
BoxDecoration(color: backgroundColor),
pageController: pageController,
onPageChanged: onPageChanged,
scrollDirection: scrollDirection!,
),
],
)),
),
),
),
);
}),
);
Thanks in Advance.
i want to use the Dismissible widget with PhotoViewGallery widget

Related

Flutter Grid View Reorder & Drag Drop onto Another Item and Merge

I have been trying to add drag/drop support to my app, currently what I have come with is using this library:
reorderable_grid_view
I used this example code:
code link
The reason I used this library is that it's smooth enough of animations when dragging. But what I want to do is to drag one item to another so that I can merge the one to another object when I drop. (It's like in Android/iOS home screen where you can drag apps to folders or drag into another that it creates a folder)
I have searched all the site but couldn't come across with such thing, only drag/drop libraries are available. Can anyone help me on this?
Thanks in advance.
class MyHomePage extends StatelessWidget {
MyHomePage({super.key});
final ValueNotifier<List<ValueNotifier<List<Widget>>>> items = ValueNotifier([
ValueNotifier([Text("A")]),
ValueNotifier([Text("B")]),
ValueNotifier([Text("C")]),
ValueNotifier([Text("D")]),
]);
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 20.0),
child: ValueListenableBuilder(
valueListenable: items,
builder: (BuildContext context, List<ValueNotifier<List<Widget>>> folders, Widget? child) {
return GridView.builder(
physics: const NeverScrollableScrollPhysics(),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3),
itemCount: folders.length,
itemBuilder: (context, index) {
ValueNotifier<List<Widget>> item = folders[index];
return LongPressDraggable(
delay: const Duration(milliseconds: 500),
feedback: SizedBox(width: MediaQuery.of(context).size.width / 4, height: MediaQuery.of(context).size.width / 4, child: FittedBox(child: Icon(Icons.folder))),
data: index,
childWhenDragging: const SizedBox(),
child: DragTarget(
onAccept: (data) {
List<Widget> alreadyHaved = item.value;
alreadyHaved.addAll(folders[data as int].value);
item.value = alreadyHaved;
items.value.removeAt(data);
items.notifyListeners();
},
builder: (context, candidateData, rejectedData) {
return ValueListenableBuilder(
valueListenable: item,
builder: (BuildContext context, List<Widget> boxValues, Widget? child) {
return Stack(children: [
const Positioned.fill(
child: FittedBox(
child: Icon(
Icons.folder,
color: Colors.amber,
))),
Positioned.fill(
child: LayoutBuilder(
builder: (p0, p1) => SizedBox(
height: p1.maxHeight * .7,
width: p1.maxWidth * .7,
child: Center(
child: Wrap(
children: boxValues,
),
))),
)
]);
},
);
},
),
);
});
},
),
),
),
],
),
);
}
}

Flutter Card Swipe Animation with forward and reverse methode without a loop

can i implement my own card swip animation ?
what i want is something similar to this package here. but the slides should shown from the top like so: (and without a loop)
my code:
final controller = SwiperController();
List<Widget> _pages = [
Container(color: Colors.blue),
Container(color: Colors.black),
];
#override
Widget build(BuildContext context) {
return Scaffold(
body: new Swiper(
loop: false,
controller: SwiperController(),
itemBuilder: (BuildContext context, int index) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 40.0),
child: _pages[index],
);
},
itemCount: _pages.length,
itemWidth: 400.0,
itemHeight: 700.0,
layout: SwiperLayout.TINDER,
),
);
}
}
can you suggest me a way to reach that and thanks.
My editor warns me about this:
The library 'package:flutter_swiper/flutter_swiper.dart' is legacy, and shouldn't be imported into a null safe library.
So I guess you should search for a up-to-date, null-safe package which does the same.
And for the vertical layout that you want to achieve... Can't you just rotate the whole swiper widget by 90 degrees?
Like so:
#override
Widget build(BuildContext context) {
return Scaffold(
body: RotatedBox(
quarterTurns: 1,
child: Swiper(
loop: false,
controller: SwiperController(),
itemBuilder: (BuildContext context, int index) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 40.0),
child: _pages[index],
);
},
itemCount: _pages.length,
itemWidth: 400.0,
itemHeight: 700.0,
layout: SwiperLayout.TINDER,
),
),
);
}

Obx - Rebuilding a list on variable change

I am trying to make a stories progress bar.
I have a PageView that shows a new video per page, and a progress bar on top that should show the progress of each PageView when I scroll to it.
The problem is the stories bar only updates the very first progress bar. I need them all to keep listening to the updates.
Video progress code:
RxDouble getVideoProgress(int storyBarIndex) {
if (storyBarIndex < pageIndex.value) {
return 1.0.obs;
} else if (storyBarIndex == pageIndex.value) {
final properVideoController = Get.put(
ProperVideoController(video: pageVideo!.value),
tag: ValueKey(pageVideo!.value.uid + '_' + user.authUid + 'tt')
.toString());
return properVideoController.videoProgress;
} else {
return 0.0.obs;
}
}
ListView code:
Widget build(BuildContext context) {
return GetBuilder<ProfileViewController>(
init: ProfileViewController(),
builder: (controller) => Container(
width: Get.width,
child: LayoutBuilder(
builder: ((context, constraints) => Column(
children: [
Container(
height: 4,
child: ListView.builder(
itemCount: itemCount,
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
return _ProgressBarStep(
width: constraints.maxWidth / 6.2,
index: index,
);
}),
),
],
))),
),
);
}
Single Story bar widget
Widget build(BuildContext context) {
return GetBuilder<ProfileViewController>(
init: ProfileViewController(),
builder: (controller) {
return Padding(
padding: const EdgeInsets.only(right: 0.0),
child: Obx(
() {
return LinearPercentIndicator(
barRadius: Radius.circular(20),
animation: true,
width: width,
lineHeight: 9.0,
percent: controller.getVideoProgress(index).value,
// ignore: deprecated_member_use
linearStrokeCap: LinearStrokeCap.roundAll,
backgroundColor: TabooColors.darkBlueGrey,
progressColor: TabooColors.red,
);
},
));
});
}
You may remove the GetBuilder widget and just use the Obx it would work. Need to add Get.put(ProfileViewController()); above the Widget build() method. I hope this might help you. Please go through the docs: https://pub.dev/packages/get
When we use GetBuilder then we also need to call the update() method in GetxController class to update the UI

Could not find the correct Provider<> with Hero animation Flutter

I'm pushing a new Route in my Gallery file to the Details file with a Hero animation. Everything is fine but when I'm calling the pop() inside the details file to go back to Gallery, I have a Provider error :
flutter: ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
flutter: The following ProviderNotFoundException was thrown building GalleryThumbnail(dirty, state:
flutter: _GalleryThumbnailState#9dc96):
flutter: Error: Could not find the correct Provider<GalleryViewModel> above this GalleryThumbnail Widget
Here is my gallery file :
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider.value(value: galleryViewModel),
ChangeNotifierProvider.value(value: galleryProvider)
],
child: Scaffold(
resizeToAvoidBottomInset: false,
body: Stack(
children: [
Consumer<GalleryViewModel>(
builder: (context, model, child) =>
galleryViewModel.assetsList.length != 0 ? gallery() : emptyGallery()),
...
}
Widget gallery() {
return Container(
padding: EdgeInsets.only(left: 5, right: 5, top: 5),
child: CupertinoScrollbar(
child: GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: 2,
mainAxisSpacing: 2,
childAspectRatio: 0.85,
),
itemCount: galleryViewModel.assetsList.length,
padding: EdgeInsets.only(bottom: Constants.navBarSize),
physics: BouncingScrollPhysics(),
shrinkWrap: true,
itemBuilder: (context, index) {
if(index >= galleryViewModel.assetsList.length-30) {
galleryViewModel.onLoadMore(index);
}
return _galleryItem(index);
},
),
),
);
}
Widget _galleryItem(int index) {
return Stack(
children: [
Consumer<GalleryProvider>(
builder: (context, model, child) {
return Container(
padding:
multipleSelection ? EdgeInsets.all(2) : EdgeInsets.all(0),
decoration: multipleSelection ? BoxDecoration(
borderRadius: BorderRadius.circular(20),
border: Border.all(color: Colors.transparent , width: 2)) : BoxDecoration(),
child: child,
);
},
Hero(
createRectTween: (Rect? begin, Rect? end) {
RectTween _rectTween =
RectTween(begin: begin, end: end);
return _rectTween;
},
tag: galleryViewModel.assetsList[index].id,
child:
child: GalleryThumbnail(
asset: galleryViewModel.assetsList[index],
onTap: (data) {
Navigator.push(context, MaterialPageRoute(builder: (context) {
return MediaEditorPage(
asset: galleryViewModel.assetsList[index],
bytes: data);
}));
},
),
...
}
When I'm pushing without the hero or another route there is no error and I don't why the provider could not be find above the Hero, I'm not notifying any provider while navigator transitions.
Why I'm getting a provider error here and how to fix this ?
Thanks for any help
When using Hero widget, it seems there is a Context issue.
This means that when the animation is performing, and in the destination you are calling a Provider.of<Model>(context), it will not find the correct Provider.
You simply need to do as you would do with a Navigator which gives in your example :
Hero(
createRectTween: (Rect? begin, Rect? end) {
RectTween _rectTween =
RectTween(begin: begin, end: end);
return _rectTween;
},
tag: galleryViewModel.assetsList[index].id,
child: ChangeNotifierProvider.value(
value: galleryViewModel,
child: GalleryThumbnail(
asset: galleryViewModel.assetsList[index],
size: size,
onLongPress: () {
if (!multipleSelection) {
multipleSelection = true;
galleryViewModel.selectedAssets.add(galleryViewModel.assetsList[index]);
galleryProvider.notify();
}
},
onTap: (data) {
Navigator.push(context, MaterialPageRoute(builder: (context) {
return MediaEditorPage(
asset: galleryViewModel.assetsList[index],
bytes: data);
}));
},
),
),
)
I have added : ChangeNotifierProvider.value(value: galleryViewModel) wrapping the GalleryThumbnail.

How do you know if DraggableScrollableSheet is collapsed or expanded

In my app there is a DraggableScrollableSheet and a FAB. I want the FAB be invisible if the DraggableScrollableSheet is expanded. I need to check the event of expansion
I tried to attach a listener to the scrollController and check the value of scrollController.offset. But I realized that the listener is triggered just when the DraggableScrollableSheet is completly expanded and not before. Is there another way to check if it is expanded or collapsed?
double appbarSize = 0.08;
double offsetVisibility=100.0;
bool FAB_visibility=true;
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: Visibility(
visible: FAB_visibility,
child: FloatingActionButton(
child: Icon(Icons.add),
),
),
body: SizedBox.expand(
child: DraggableScrollableSheet(
maxChildSize: 0.8,
minChildSize: appbarSize,
initialChildSize: appbarSize,
builder: (BuildContext context, ScrollController scrollController) {
_scrollListener() {
if(FAB_visibility==false && scrollController.offset<=offsetVisibility){
setState(() {
FAB_visibility=true;
});
}
else if(FAB_visibility==true && scrollController.offset>offsetVisibility){
setState(() {
FAB_visibility=false;
});
}
}
scrollController.addListener(_scrollListener);
return Container(
decoration: new BoxDecoration(
color: Colors.red,
borderRadius: new BorderRadius.only(
topLeft: const Radius.circular(10.0),
topRight: const Radius.circular(10.0))),
child: ListView.builder(
controller: scrollController,
itemCount: 25,
itemBuilder: (BuildContext context, int index) {
return ListTile(title: Text('Item $index'));
},
),
);
},
)),
);
}
Thanks to flutter team I understood how to do it!
We should wrap DraggableScrollableSheet in a NotificationListener
This is the working code:
class _MyHomePageState extends State<MyHomePage> {
double appbarSize = 0.08;
double offsetVisibility = 100.0;
bool FAB_visibility = true;
#override
Widget build(BuildContext context) {
return Scaffold(
body: SizedBox.expand(
child: NotificationListener<DraggableScrollableNotification>(
onNotification: (DraggableScrollableNotification DSNotification){
if(FAB_visibility && DSNotification.extent>=0.2){
setState(() {
FAB_visibility=false;
});
}
else if(!FAB_visibility && DSNotification.extent<0.2){
setState(() {
FAB_visibility=true;
});
}
},
child: DraggableScrollableSheet(
maxChildSize: 0.8,
minChildSize: appbarSize,
initialChildSize: appbarSize,
builder: (BuildContext context, ScrollController scrollController) {
return Container(
child: ListView.builder(
controller: scrollController,
itemCount: 25,
itemBuilder: (BuildContext context, int index) {
return ListTile(title: Text('Item $index'));
},
),
);
},
),
)),
floatingActionButton: Visibility(
visible: FAB_visibility,
child: FloatingActionButton(
child: Icon(Icons.add),
),
),
);
}
}