How to animate ListView rendering in flutter? - flutter

Okay so there are a couple of questions already asked regarding this but no one is doing what I want to do.
Context :
I've a bloc which maintains a stateCounter. Now whenever user visits the onboarding page, they are shown three different subpages (not exactly pages but 3 different content items). i.e.,
stateCounter == 1 | Fetch image from map at index = stateCounter + Fetch title from map at index = stateCounter + Fetch subtitle from map at index = stateCounter
When user clicks Next button, stateCounter increases and the Map's next child is shown which re-renders my page (to move to the next item).
I'm also using a Dismissble widget on each child so rendered, so that user can also increase the stateCounter when he/she drags from end to start (to achieve a sliding effect)
Now everything works like a charm but the only problem here is that when the next data is rendered (when stateCounter increases and we fetch the next series of image, title and subtitle), the change is not so subtle.
Here, I would want to show some kind of animation so that It looks good to the user. How can i do that ??
Here is the ListView that gets rendered on the screen based on stateCounter value:
ListView onBoardingSubscreens(stateCounter, context, bloc, controller) {
return ListView(
children: [
skipBtn(context, bloc),
renderImage(stateCounter, 0, context),
const SpaceRenderer(
heightFactor: 3,
),
renderScroller(stateCounter, 1, context),
const SpaceRenderer(
heightFactor: 3,
),
titleText(context, stateCounter),
const SpaceRenderer(
heightFactor: 2,
),
captionText(stateCounter),
Timer(
controller: controller,
secondsRemaining: 6,
onFinished: () {
stateChangeLogic(stateCounter, context, bloc, controller);
controller.restart();
},
),
],
);
}
As I mentioned above, this is rendered inside : ConstrainedBox which is rendered inside a Dismissible and a Column in the end.
Kindly help. I already tried using AnimatedContainer etc. but no animations are being shown. I'm open to using a package (if needed)

Related

Flutter: push a new page and scroll down to certain widget

I have a web app in Flutter. My app bar has 5 buttons. Four of them scroll within the first page. The 5th one pushes a new page.
There are three different widgets on stage:
page A (HomeView)
page B (ContactView)
the AppBar
When the user is on page A, the buttons of page A should scroll down or up, and the button of page B should push the new view. When the user is on page B (contact) and presses any of the buttons of page A, it should push the home page and scroll to the required position.
I tried to do this with ScrollController.animateTo and Riverpod for state management, but I couldn't do it. The page scrolled down but, for some reason, it scrolled up again and didn't maintain position. I couldn't find any related post on the Internet and keepScrollOffset was not the answer. I also didn't know how to scroll to the desired position when the user is not on 0 (it scrolled down from current position).
After that, I tried to do it with GlobalKeys. It worked, up to a certain point. On page A, everything worked fine. However, from page B to page A, it said the keys are duplicated. I used pop instead of pushNamed as suggested in one of the answers of this post (the only answer that worked for me). The behavior was finally as expected, but I can't use pop since I have more pages on the website, so I can't ensure that the user is coming from page A. I tried with pushReplacement as the same answer gives that for an alternative option. It doesn't work now. When trying to go from page B (contact) to page A, it throws error Unexpected null value.. Furthermore, I need to keep the back button functionality since it is a website. I would prefer, then, to not pop the current page from the stack.
The page A (HomeView) is built like this inside of a StatefulWidget:
#override
Widget build(BuildContext context) {
return SingleChildScrollView(
controller: _scrollController,
child: Column(
children: [
HomeHeader(key: HomeView.homeKey),
WhatWeOffer(key: HomeView.servicesKey),
WhatWeDo(key: HomeView.referencesKey),
WhoWeAre(key: HomeView.aboutKey),
const LetsGetInTouch(),
],
),
);
}
The GlobalKeys are defined like this inside of the Page A (HomeView) widget:
static GlobalKey homeKey = GlobalKey(debugLabel: 'homeHeaderKey');
static GlobalKey servicesKey = GlobalKey(debugLabel: 'whatWeOfferKey');
static GlobalKey referencesKey = GlobalKey(debugLabel: 'whatWeDoKey');
static GlobalKey aboutKey = GlobalKey(debugLabel: 'whoWeAreKey');
This is how I implement the navigation to page A:
if (ModalRoute.of(context)?.settings.name != '/') {
Navigator.pushReplacementNamed(
context,
Navigation(context).routes["/"]!,
);
}
Scrollable.ensureVisible(
HomeView.homeKey.currentContext!,
duration: const Duration(milliseconds: 500),
curve: Curves.easeInOut,
);
And this is how I implement the navigation to page B:
Navigator.pushReplacementNamed(
context,
Navigation(context).routes["/contact"]!,
),
Maybe GlobalKey is not the right approach to my problem? Is there any easier way to push a new page and scroll down to a widget?
EDIT:
I think the Unexpected null value problem was caused because the view was not built yet when I was trying to call it. I solved it by making the functions async and waiting before using the keys:
TextButton(
child: Text('home', style: style),
onPressed: () async {
if (ModalRoute.of(context)?.settings.name != '/') {
Navigator.pushReplacementNamed(
context,
Navigation(context).routes['/']!,
);
await Future.delayed(const Duration(milliseconds: 500));
}
Scrollable.ensureVisible(
HomeView.homeKey.currentContext!,
duration: const Duration(milliseconds: 500),
curve: Curves.easeInOut,
);
},
),
However, this does not solve my problem of the back button. As I use pushReplacementNamed instead of pushNamed, I can't go back. Is there a more optimal way to do this, where I can keep the back button functionality?

How Do I Create this Page Swipe Behaviour in Flutter?

I want to implement this page swipe behaviour in Flutter as shown in the picture. The user should be able to drag the screen from the right edge of the screen to the left up until the page is dragged halfway through the screen. Once released, the app will move onto a new page.
Desired Outcome
You can use Slidable Package and wrap the whole page in a slideable.
Slidable(
key:UniqueyKey(),
endActionPane: ActionPane(
onDismissed: (){}, // Leave empty, confirmDismiss will handle event
confirmDismiss: () asnyc {
// function that rerender page with next question
}
children: [] //list of widgets to show when slide
child: // this is the widget that shows and will be slideable
if you want to have both sides you just add startActionPane aswell.

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... */),
],
),
// ...

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

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
}
});

Flutter - SliverAppBar with snapping toolbar and nested scroll view

I'm trying to reproduce a UX design in which we have the following components:
A top bar which contains the text "Desmos"
A main post content, which is composed of
A header (user icon, user name, post date, options button)
The post message
Any post image that might be present
A tab bar, which allows the user to show either the Comments list or the Reactions list.
The peculiarity of this UX is that when the user scrools the list of Comments or Reactions (based on which he is currently viewing), the vertical scroll list snaps to the tab bar.
From there, the user will be able to either scroll down the list of comments or, with an additional scroll, showing again the post. Please note that the original post should be placed so that for the user to show it again, a higher amount of scroll force is required.
I have put together a video that you can see here to better understand how this should work:
I've already realized a widget called PostContent that contains all the above mentioned main content of a post. I've also already tried coding something for the wanted UX that looks like the following:
Scaffold(
body: SafeArea(
child: NestedScrollView(
headerSliverBuilder: (context, _) {
return [
SliverAppBar(
backgroundColor: Colors.white,
expandedHeight: 310,
pinned: true,
primary: true,
flexibleSpace: PostContent(post: post),
)
];
},
body: ListView.builder(
itemBuilder: (context, index) {
return Text(index.toString());
},
),
),
),
);
The result can be seen by clicking on the following preview:
The problems with this implementation are the following:
As the PostContent is a Column, how can I get its height so that I don't have to specify a fixed value inside SliverAppBar's expandedHeight attribute?
How can I avoid that when scrolling up the ListView, the scrolling stops when it reaches the AppBar without scrolling further up?