Reputation: 150
I'm new to flutter and am learning about Pageview. In my app I have made an onboarding screen. Is there a way to disable scroll in a particular direction? What I'm trying to achieve is that the user should not be able to scroll/swipe left when they are on the first page and should not be able to scroll/swipe right when they are on the last page. I know you can disable scroll physics by using NeverScrollableScrollPhysics()
, but is there a way to give it a direction?
Code:
PageView(
onPageChanged: (newValue) {
//Update the page
},
physics: activePage == 0 ||
activePage == pages.length - 1
? const NeverScrollableScrollPhysics()
: const PageScrollPhysics(),
controller: pageController,
children: [
for (var page in pages) PageWidget(page: page),
],
)
Upvotes: 0
Views: 2763
Reputation: 1
I had been stuck on trying to implement this behavior for a while now and today I managed to overcome my problem.
What I actually needed is to completely disable forward scrolling only when the user swipes forward in my application.
I still wanted to allow the user to proceed forward after completing some necessary steps
To implement disabling change of page on user-swipe follow the steps:
Create a PageController instance
final PageController _pageController = PageController();
Keep a reference of the current page - very important
int _currentPage = 0
When creating PageView use AlwaysScrollableScrollPhysics()
:
child: PageView(
controller: _pageController,
physics: AlwaysScrollableScrollPhysics(),
onPageChanged: (index) {
// Revert the conditions if you wish to disable backwards scrolling
if (index > _currentPage) {
print("DISABLED FORWARD");
/*
onPageChanged runs first only in case of swipe gestures
Because of this, if users swipe forward then they should not
be allowed to proceed and pageController takes them back to
the page the were on
*/
_pageController.animateToPage(_currentPage, duration: Duration(milliseconds: 200), curve: Curves.easeIn);
} else if (index < _currentPage) {
/*
This runs only when the user SWIPES backwards
*/
print("ALLOWED BACKWARD");
} else {
/*
This is called in the case of the user triggering a function that should allow going forward/backward. The reason we need this else case is the following: If the user completes a step of the process or opts to go back NOT BY SWIPING but by using for example some back button the setState method in the custom functions goToNextPage/goToPreviousPage (see step 4) gets called before onPageChanged. Thus the _currentPage is equal to the index of the new page.
*/
print("USER TRIGGERED ACTION");
}
},
children: [
// your page view children
],
),
void goToNextPage() {
// maxPageInt is the total number of your pages
if (_currentPage < maxPageInt) {
setState(() {
_currentPage++;
// Do anything you want here
});
_pageController.animateToPage(
_currentPage,
duration: Duration(milliseconds: 300),
curve: Curves.easeInOut,
);
}
void goToPreviousPage() {
if (_currentPage > 0) {
setState(() {
_currentPage--;
// Do anything you want here
});
_pageController.animateToPage(
_currentPage,
duration: Duration(milliseconds: 300),
curve: Curves.easeInOut,
);
These two functions should only be called when the user for example completes a step. Suppose you have a function onCompletedStep
you should do:
void onCompletedStep() {
// Do anything you wish here
goToNextPage();
}
Or if you have a back button that calles onBackPressed
you should do:
void onBackPressed() {
// Do anything here
goToPreviousPage();
}
Upvotes: 0
Reputation: 150
Found the answer. Simply set physics of the PageView to ClampingScrollPhysics().
Upvotes: 0
Reputation: 45
To disable scrolling in a particular direction in a PageView widget in Flutter, you can use a combination of physics and onPageChanged callback to control the scroll behavior. For example. import 'package:flutter/material.dart';
class DisableScrollDirectionPageView extends StatefulWidget {
@override
_DisableScrollDirectionPageViewState createState() =>
_DisableScrollDirectionPageViewState();
}
class _DisableScrollDirectionPageViewState
extends State<DisableScrollDirectionPageView> {
PageController _pageController;
int _currentPage = 0;
@override
void initState() {
super.initState();
_pageController = PageController(initialPage: _currentPage);
}
@override
void dispose() {
_pageController.dispose();
super.dispose();
}
void _handlePageChange(int page) {
setState(() {
_currentPage = page;
});
}
bool _isScrollable(int page) {
// Enable scrolling only for pages other than page 2
return page != 2;
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Disable Scroll Direction'),
),
body: PageView(
controller: _pageController,
physics: _isScrollable(_currentPage)
? AlwaysScrollableScrollPhysics()
: NeverScrollableScrollPhysics(),
onPageChanged: _handlePageChange,
children: <Widget>[
Container(
color: Colors.blue,
child: Center(
child: Text(
'Page 1',
style: TextStyle(fontSize: 24, color: Colors.white),
),
),
),
Container(
color: Colors.red,
child: Center(
child: Text(
'Page 2',
style: TextStyle(fontSize: 24, color: Colors.white),
),
),
),
Container(
color: Colors.green,
child: Center(
child: Text(
'Page 3',
style: TextStyle(fontSize: 24, color: Colors.white),
),
),
),
],
),
);
}
}
In the above code DisableScrollDirectionPageView widget creates a PageView with three pages. The _isScrollable method checks the current page index and returns true if scrolling is enabled for that page, and false otherwise. The physics property of the PageView is set to either AlwaysScrollableScrollPhysics() or NeverScrollableScrollPhysics() based on the _isScrollable value.
Upvotes: 0
Reputation: 2398
To get that kind of behaviour you can give controller
to pageview and get swipe direction.
Then you can block the scroll according to you. Refer the link below
https://stackoverflow.com/a/63188690/15438326
Upvotes: 0
Reputation: 2398
You can achieve this behaviour like this
set physics as NeverScrollableScrollPhysics()
then
you can have a next
button, where you can use pageView.animateToPage()
function to animate to next page
This will give you the feel of swiping and can achieve this behaviour.
Here by using this you can only move forward not backward in your pageView
If you have any doubts let me know
Upvotes: 0