The reason I want to use PageView because it can stick to the page when dragging is released. But I can't figure out how to achieve the screen like below:
I want to make the page currently selected page show a larger size, while others show smaller.
The most straightforward method is to set the viewportFraction
(to 0.15). But after that I find out that the pages need the different values of viewportFraction
:
You can see that I want the space between pages equally but only the middle one shows larger. Is this possible to do with the PageView Widget? Or does anyone have other workarounds that can achieve the same result?
If possible, I also want to add GestureDetector
to each page (which can animate to the target page)
Check this dartpad out:
You can check out all the code there but the gist is that inside every page view you have an animated container in which you animate its padding to control its height :
The value is hardcoded but you could use a mediaquery to get a dynamic top padding.
class PageviewGallery extends StatefulWidget {
@override
_PageviewGalleryState createState() => _PageviewGalleryState();
}
class _PageviewGalleryState extends State<PageviewGallery> {
final PageController ctrl = PageController(
viewportFraction: 0.75,
);
int currentPage = 0;
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: PageView.builder(
controller: ctrl,
itemCount: 8,
physics: const BouncingScrollPhysics(),
itemBuilder: (context, int index) {
// Active page
bool active = index == currentPage;
return _buildStoryPage(active);
}),
));
}
@override
void initState() {
super.initState();
ctrl.addListener(() {
int pos = ctrl.page!.round();
if (currentPage != pos) {
{
setState(() {
currentPage = pos;
});
}
}
});
}
@override
void dispose(){
ctrl.dispose();
super.dispose();
}
}
_buildStoryPage( bool active) {
// Animated Properties
final double blur = active ? 30 : 0;
final double offset = active ? 20 : 0;
final double top = active ? 100 : 200;
return AnimatedContainer(
duration: Duration(milliseconds: 500),
curve: Curves.easeOutQuint,
margin: EdgeInsets.only(top: top, bottom: 50, right: 30),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color :Colors.red,
boxShadow: [BoxShadow(color: Colors.black87, blurRadius: blur, offset: Offset(offset, offset))]),
);
}
From the Flutter docs: "Each child of a page view is forced to be the same size as the viewport."
With that in mind, it is possible to achieve the effect you are looking for to some degree using a PageView
. I riffed off of @croxx5f's answer, but here's how you can achieve it: https://dartpad.dev/e3fe965b19d36bc6f58bac8029a89251?null_safety=true.
Note that it is using padding (or lack thereof) to make the active element larger.
In short, the very nature of PageView
required the elements to be the same width. If you want to use PageView
, you will have to use padding or a similar technique to make the non active components smaller than the active one.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With