Flutter - SliverAppBar with snapping toolbar and nested scroll view - flutter

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?

Related

How to animate ListView rendering in 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)

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

Dart/Flutter: horizontally scrollable week view - how to display particular items from the ListView?

I've been trying to make horizontal weekly calendar without using third party packages. I've created a horizontally scrollable Listview, containing three weeks : previous, current and next. Obviously, Listview displays from the first item in the list, which is the first day of the previuos week. Is there any way to control the items displayed and to display the current week with previous and next weeks being accessed through horizontal scrolling?
Here is the code for the ListView.builder:
Container(
height: 60,
child: ListView.builder(
scrollDirection: Axis.horizontal,
padding: const EdgeInsets.symmetric(horizontal: 20),
itemCount: threeWeeks2.length,
itemBuilder: (BuildContext context, int index) {
var date = DateFormat('d').format(threeWeeks2[index]);
return DayCardBig(date);
}
),
),
Also, I can't keep but wondering whether the logic behind this implementation of week view is sound. I tried a more complex widget using carousel slider and pageview, but it just got messy. Is there any other widget that I'm not familiar with that I could use for a scrollable week view ?

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

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.