Is there any alternatives Transform widget to animate the scale of widget inside PageView.builder? - flutter

I am trying to build a design with the help of PageView.builder. I don't want to use a plugin, since this design is bit different and also I can't get more flexible if I want to try something new.
The design is pretty simple, I'm trying to build a bottomNav using PageView. The design looks like Carousel for me, hence decided to go with PageView, correct me if I am wrong. It is not only sliding widget. If I press any visible CircleAvatar, it will be come to the middle (active we can say)
As of now, I achieved this
Here you can see the gap difference due to Transform. It is occupying space. I tried with AnimatedSize widget but not able to mimic this design.
Code as far I have
PageView.builder(
controller: pageController,
scrollDirection: Axis.horizontal,
itemCount: pages.length,
onPageChanged: (index) => setState(() {}),
scrollBehavior: NoScrollGlowBehaviour(),
itemBuilder: (context, index) {
return GestureDetector(
onTap: () => gotoPage(index),
child: _buildBottomNavAnimated(index),
);
Widget _buildBottomNavAnimated(int index) {
Matrix4 matrix4 = Matrix4.identity();
//computing matrix based on diff currentPage values
return Transform(
transform: matrix4,
alignment: Alignment.center,
child: CircleAvatar(
backgroundColor: pages[index],
child: const FlutterLogo(
size: 20,
),
),
);
}
I just added minimal required code above. For full code dartpad . Incase needed Inspect image for help
I would also like, if it is possible to achieve this design apart from PageView and Transform too.

Related

How can we achieve infinite slider/swiper like this in flutter?

Is there any library or plugin that has the feature to enable infinite scroll with a slider/swiper view like the one below? I have searched for similar sliders, but I haven't found any.
you can just use the PageView.builder() and not specifying the itemCount
final yourPageController= PageController(initialPage: 10000);
PageView.builder(
controller: yourPageController,
itemBuilder: (context, index) {
return Center(
child: Text('page number $index'),
);
},
),
since I didn't specify the itemCount, it's now an infinite PageView that you can use and customize.

How to add other components additional to gridview on same page in flutter

...
if (snapshot.data == null) {
return Container(
child: Center(
child: Text("Loading..."),
));
} else {
return GridView.builder(
itemCount: snapshot.data.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3),
itemBuilder: (context, index) => Card(
child: GridTile(
child: Center(
child: Text(snapshot.data[index].service_type),
),
)));
}
...
When this code is executed, the result is as follows,
In this, I need to add an image component on top of the grids. Please help me on achieving that. The below image is the expected result design.
Using shrinkWrap on big lists is a bad practice, you should wrap your GridView/ ListView with expanded when you want something above or below it, also don't nest scroll views like that. You should use CustomScrollView or NestedScrollView instead. What they said in the docs.
Shrink wrapping the content of the scroll view is significantly more expensive than expanding to the maximum allowed size because the content can expand and contract during scrolling, which means the size of the scroll view needs to be recomputed whenever the scroll position changes.

Persistent draggable bottom sheet in Flutter

I'm using Rubber library at the moment, do you know an approach without using 3rd parts libraries?
The Bottom Sheet must be persistent (not dismissable, not triggered by any button instead, always displayed) and draggable (It must be expanded and collapsed by dragging gestures)
Perhaps DraggableScrollableSheet could work?
I haven't yet tried it out myself, but maybe you could fiddle with a listview to make it work.
I'm guessing something like having it's child be a listview, and then limit both the max child size and the maximum scroll extent
If you do not care that the bottom sheet must snap to different positions you can use the widget from the following package (snapping_sheet) I made.
Or, if you do not want to use it as a 3rd part library, you can copy the code and use it as your own widget from repository here: Github - Snapping sheet
Use DraggableScrollableSheet. Here's an example:
Stack(
children: [
Container(), //the page under the DraggableScrollableSheet goes here
Container(
height: MediaQuery.of(context).size.height,
child: DraggableScrollableSheet(
builder: (BuildContext context, myscrollController) {
return Container(
color: Colors.blue,
child: ListView.builder(
controller: myscrollController,
itemCount: 40,
itemBuilder:(BuildContext context, int index) {
return ListTile(title: Text('Item $index',
style: TextStyle(color: Colors.black),
));
},
),
);
},
),
),
],),

Translating a widget isn't smooth

I am using a widget which starts off from the centre of the screen. I want the widget to move from centre to the top and vice-versa as user drags the widget.
I have wrapped my widget with Gesture detector and also with Transform widget whose Y value gets changed as user drags.
I am using value notifier when the Y position changes as user drags. The widget drags as expected.
The problem is that the scroll of the widget is not smooth. I have tried using Animation controller but I am not very sure how that would fit here.
Is there a way I could use scroll animation on my widget so that its smooth?
Below is my widget that I want to translate on drag:
Transform(
transform: Matrix4.translationValues(0, widget.verticalOffset, 0),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 30.0),
child: Container(
color: Theme.of(context).primaryColor,
child: GestureDetector(
onVerticalDragUpdate: widget.handleDragUpdate,
onVerticalDragEnd: _handleVerticalDragEnd,
child: ListView.builder(
controller: controller,
physics: _getScrollPhysics(context),
itemCount: widget.songs.length,
itemBuilder: (BuildContext context, int index) {
return buildSongRow(widget.songs[index]);
}
)
)
),
),
)
If you're running things in debug mode this is a likely result. To make sure your animation is running as smooth as you hope then you'll want to run things in profile mode.

How to avoid scrolling listview when scrolling in map within listview

I have a ListView, at the top of which I have a map, I want the map to scroll out of view when the ListView is scrolled, but I also want the user to be able to interact with the map. So scrolling should only happen when the user scrolls on the other ListView widgets and not when they scroll on the map, then I want the gesture to be applied directly to the map.
Currently though, when the user scrolls on the map, it scrolls the whole ListView.
I have tried the other suggestion that I have come across on here
In Flutter, how can a child widget prevent the scrolling of its scrollable parent?
I added a GestureDetector as suggested in the answer to the post above wrapping the map container in the sample below, however this just blocked scrolling of both the ListView and the Map when scrolling on the map. Video link https://imgur.com/SeCRzUC
Here is the widget that is returned by my build method. This code depends on the google_maps_flutter plugin.
Container(
height: MediaQuery.of(context).size.height,
child:
ListView.builder(
itemCount: 12 + 1,
itemBuilder: (context, index) {
if (index == 0) return GestureDetector(
onVerticalDragUpdate: (_){},
child: Container(
height: MediaQuery.of(context).size.height / 2,
child: GoogleMap(initialCameraPosition: initalPosition),
),
);
else return ListTile(title: Text("$index"),);
}
)
),
I had hoped the map would capture gestures but it doesn't, the listview which contains it captures all. Could anyone suggest how I could force all gestures for this item in the list to be passed directly to the map, and still have the list scroll when other items in the list are scrolled?
The accepted answer (Eset Mehmet's answer was marked as excepted as of time of writing) is way to complicated and in my case it did not even work! It provided left-to-right scrolling, panning, and scaling, however top-to-bottom scrolling still scrolled the ListView.
A real solution is very simple, since GoogleMap by default has those gesture detectors. You must just specify that gesture detection must be prioritized by GoogleMap and not ListView. This is achieved by giving GoogleMap object an EagerGestureRecognizer in the following way for example.
ListView(
children: <Widget>[
Text('a'),
Text('b'),
GoogleMap(
...,
gestureRecognizers: {
Factory<OneSequenceGestureRecognizer>(
() => EagerGestureRecognizer(),
),
},
),
],
)
In this way, all gestures that happen on or over the GoogleMap object will be prioritized by GoogleMap instead of any other widget.
Edit: campovski 's answer down below is the updated answer.
Depreciated Answer:
Wrap everything with ListView if you want to move out GoogleMap widget from the screen when scrolling.
Override ListView scrolling phyics with GoogleMap gestureRecognizers.
Disable ListView.builder scrolling physics due to conflict between ListView physics.
First import the dependencies:
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
build method:
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView(
children: <Widget>[
SizedBox(
height: MediaQuery.of(context).size.height / 2,
child: GoogleMap(
initialCameraPosition:
CameraPosition(target: LatLng(41, 29), zoom: 10),
gestureRecognizers: Set()
..add(
Factory<PanGestureRecognizer>(() => PanGestureRecognizer()))
..add(
Factory<VerticalDragGestureRecognizer>(
() => VerticalDragGestureRecognizer()),
)
..add(
Factory<HorizontalDragGestureRecognizer>(
() => HorizontalDragGestureRecognizer()),
)
..add(
Factory<ScaleGestureRecognizer>(
() => ScaleGestureRecognizer()),
),
),
),
ListView.builder(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: 12,
itemBuilder: (context, index) {
return ListTile(
title: Text("$index"),
);
},
)
],
),
);
}