Is it possible to disable a page when using PageView, Swiper or liquid_swiper? - flutter

I want to have the swiper effect in my app, I want to have 7 pages and move between the screens. I plan to have a form on every page.
For example, I am using Swiper package
Swiper(
itemBuilder: (BuildContext context, int index) {
return pagesWizzard[index]; //my 7 pages
},
itemCount: pagesWizzard.length,
pagination: new SwiperPagination(
margin: new EdgeInsets.all(5.0),
builder: new DotSwiperPaginationBuilder(
color: Colors.grey,
activeColor: Colors.blue)),
),
If I completed the form on page 1, I want to be able to slide the screen to go to page 2, and if I want I can go back and so on. If I have not completed the form on page 1, I should not be able to move to page 2 and higher.
Currently in: PageView, Swiper or liquid_swiper I can't find how to disable a page or multiple pages.
I would like you to guide me on how to do this.
Another question, is it a good practice to put my forms inside these components that allow swiping to navigate between screens? I ask about the issue of forms rendering and so on.

Another way on how to achieve this is passing a bool threw your form which checks if the formfields are filled in or not. If no, you prevent swiping to the next pages.
Using PageView with NeverscrollableScrollPhysics() and a PageController does the work for you.
// Outside build method
PageController controller = PageController();
// Inside build method
PageView(
controller: controller,
physics: NeverScrollableScrollPhysics(),
children: <Widget>[
// Add children
],
)
A good article for basic understanding of PageController can be found here: https://medium.com/flutter-community/a-deep-dive-into-pageview-in-flutter-with-custom-transitions-581d9ea6dded
With NeverscrollableScrollPhysics you block the swiping. Now wrap your children with a GestureDetector, and on swiping right you will check if your bool is true or not. If yes you will navigate to the next page with the PageController.
Example for GestureDetector
GestureDetector(onPanUpdate: (details) {
if (details.delta.dx > 0 && formFilled == true) {
pageController.jumpToPage(index);
// swiping in right direction
}
});

Related

flutter: Is it possible to use conditional statements in pageview?

I want to create a function that automatically moves to the next page when a certain condition is met using 'pageview'.
For example, if a=0 becomes a=1, it should automatically advance to the next page.
Instead of going to the next page by clicking a button in the pageview, is it possible to automatically go to the next page using a conditional statement?
Expanded(
child:
PageView.builder(
physics: NeverScrollableScrollPhysics(),
controller: _questionController.pageController,
onPageChanged: _questionController.updateTheQnNum,
itemCount: _questionController.questions.length,
itemBuilder: (context, index) => QuestionCard(
question: _questionController.questions[index],
myanswer: testtext,
),
)
),
This is part of my code. When a=1, it should advance to the next page, otherwise it should keep the current page.
There are two methods that can help you achieve it.
animateToPage
_questionController.pageController.animateToPage(pageIndex);
or
jumpToPage
_questionController.pageController.jumpToPage(pageIndex);
As the name suggests animateToPage will animate the transition from Page A to Page B where jumpToPage won't animate.
Make sure pageIndex is within the range.

Using TextField and Button to create a message bubble in Flutter

Android Studio + Flutter
I have a Row at the bottom of the screen.
It includes TextField and Button (Add).
When there is some text in TextField and user clicks Add, I want it to appear as a Bubble inside a Container starting from the top left.
What would be the correct way to do it? I want the bubbles to accumulate like a notes app and eventually be scrollable too.
Thanks!
Try using the Snackbar Widget, which can be personalized heavily.
Here's the documentation.
EDIT. Since you want a permanent list of bubbles on the top, I'd suggest using a provider, so that when you click the button, the onTap event validates and adds the data to a list (below, myElements). Then, up to the top, just add a Consumer Widget that listens to changes to the list (it rebuilds its children every time something changes). In the following example code (I have not tested it!) I use an Expanded widget just for fun and I use a ListView.builder inside the Consumer to show the list of elements you've added, since the amount of added element could be high. Finally, I suggest using either ListTile or Card or a combination of the two, since you want something aesthetically beatiful like a bubble (you'll have to play with the settings, a little):
return ... (
child: Column(
children: [
Text("Some title..?"),
Expanded(
Consumer(
builder: (ctx, myElements, _) => ListView.builder(
itemCount: myElements.length,
itemBuilder: (ctx, i) => ListTile(
title: Text("You added ${myElements[i]}"),
// something else...?
),
),
),
),
Row( /* ... Text field + Button here... */),
],
),
// ...

FLUTTER: PageView.builder onPage property - can i change so the index is triggered upon a FULL page swipe instead of 0.50

Using PageView.builder in Flutter, I have made a basic quiz with random repopulating questions, and some animation that I want to trigger every time a new page comes into view.
Also, of relevance, the user can only proceed to the next page once they have answered a question on each page. (Hence to control swiping, I created a ternary operator on the physics property where the onScroll boolean is set to false when the onPage method is triggered, (and changed back later by the user to true when they answer a question by pressing a button)).
So, everything is working well, except one annoying sideeffect:
The onPageChange property is "Called whenever the page in the center of the viewport changes." and the animation set for the new page, will play on the previous page as it dissapears from view, as the onState method needed for the onScroll boolean is triggered half way during the scroll causing a rebuild.
A simple fix would be if I could change the onPageChange property to trigger only once a FULL page swipe has been completed...but I cant work out how to achieve this..?
Thank you!
#override
Widget build(BuildContext context) {
return Material(
child: PageView.builder(
onPageChanged: (int i) {
print('page changed! + i');
setState(() {_canScroll = false;});
},
physics: _canScroll
? AlwaysScrollableScrollPhysics()
: NeverScrollableScrollPhysics(),
pageSnapping: true,
itemBuilder: (context, index) {
_index = index;
return WordCardWidget(
word1: _word1,
word2: _word2,
answer: answer,
animationType: _cardAnimType,
buttonSelected: buttonSelected,
);
},
));
}
}
Try using mounted property before triggering setState().
This way it will ensure widget is completely mounted before changing the state.
Leaving this up, in case it helps any future readers.
I got this to work by using itemCount property and incrementing with a local variable, hence I dont need to use the setState method on the onPage property. The users can progress through each page only after attemping to answer a question which increases the itemCount by one.
(I have amended my original post where I wrongly thought this didnt work).
Here is the relevant working code snippet for reference :)
child: PageView.builder(
itemCount: itemCount,
onPageChanged: (int i) {
print('page changed! + i');
},

Killing flutter gesture

I am trying to stop a gesture from continuing if a certain criteria is met.
The scenario is the user is swiping a tab bar and if they go to the next tab and the condition is true it should disable further swiping. I have tried to put the tab bar in a stack with an Absorb pointer container on top but if they don't let go of the original gesture (i.e. they got to the new tab but didnt let go of the screen) it still allows them to drag through it.
is there anyway to stop the original swipe gesture?
i found this cancel method but i have no idea how to access it
https://api.flutter.dev/flutter/gestures/Drag/cancel.html
In your case there is no need to handle gesture out of the TabBarView simply change the ScrollPhysics.
Here a code example:
final isDisable = ValueNotifier(false);
tabController.animation?.addListener(() {
//The scrolling will be disabled if the second tab is displayed so you can
//add your own logic, may be just checking tabController.index
if (tabController.animation!.value == 1.0) {
isDisable.value = true;
}
});
return Scaffold(
body: ValueListenableBuilder(
valueListenable: isDisable,
builder: (context, bool value, child) => TabBarView(
controller: tabController,
// changing the physics to NeverScrollableScrollPhysics will disable scrolling
physics: value
? NeverScrollableScrollPhysics()
: AlwaysScrollableScrollPhysics(),
children: children,
),
),
);

Why Flutter ListTile onTap seems cached?

I have two listview screen on my app. User can navigate between them using BottomNavigationBar control.
On listview.builder function, I return something like this
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
return ListTile(
title: Text('...'),
subtitle: Text('...'),
onTap: () {
...
}
)
});
I found onTap handler seems mixed between those 2 listviews.
When I open first list view, flutter serve the correct onTap,but when I switch to second listview, flutter still serving the first listview onTap.
Seems the onTap is cached by flutter (title & subtitle seems okay). Any idea?
Sample source code: https://github.com/jazarja/flutter_app
The problem is in your compararing transition values. Because you are first reversing the animation transition of current view.
In your botton_nav.dart, change this:
return aValue.compareTo(bValue);
to this:
return bValue.compareTo(aValue);
Yes the problem is that the animations haven't completed by the time the comparison is being done so the widget at the top of the stack is always 1 tab selection behind. You actually don't need to build a stack at all, just replace Center(child: _buildTransitionStack()) here with _navigationViews[_currentIndex].transition(_type, context) and it should work.