When using Flutter Visibility widget, can the change in visibility be animated? - flutter

I have a column holding a number of containers. The top and bottom containers are always shown, but the ones between sit inside a Visibility widget. If the user taps the screen, the middle containers are made visible, and then are made invisible again on the next tap. So essentially, the column expands and contracts each time it's tapped.
I'd like the expansion and contraction to happen a bit more gracefully - currently it looks very harsh when the middle containers just suddenly appear. Is there any way of animating the way in which the containers are made visible and hidden? Or should I be looking at using a totally different Widget than Visibility?

You can use an animated crossfade. Make the first child as SizedBox.shrink() and second child as the widget that you wish to display and it should be animating as expected. And switch according to the requirement
bool _first = true;
AnimatedCrossFade(
duration: const Duration(seconds: 1),
firstChild: const SizedBox.shrink(),
secondChild: const FlutterLogo(style: FlutterLogoStyle.stacked, size: 100.0),
crossFadeState: _first ? CrossFadeState.showFirst : CrossFadeState.showSecond,
)
Alter the value of _first to true or false.

Related

Flutter: How configure ListView() to auto-scroll to bottom (as new children are added) except when momentarily scrolling up to view older children

(I'm using a ListView() to implement a little logging pane that shows my app events.)
I looked through the ListView() documentation and can't seem to find a property like autoScrollUnlessBrowsing. I need:
The ListView() to auto-scroll to bottom every time a new child is
added (so I don't have to manually drag up to expose new app activity).
However, while I'm temporarily scrolling-up to view old activity I want auto-scrolling momentarily suspended (because it's annoying to have it yank scrolling to bottom interrupting what I'm trying to read). After I'm done browsing, if I manually scroll back to the bottom I want to auto-scroll to re-enable.
ListView(
autoScrollUnlessBrowsing: true,
children: children),
It would be great if Flutter could add this but until then how could this be implemented?
You can use a scroll controller for that.
Define a scroll controller inside your page.
ScrollController _controller = ScrollController();
Then pass it to your listview widget. For example -
ListView.builder(
controller: _controller,
itemCount: 10,
itemBuilder: (_, __) => ListTile(title: Text('demo')),
)
Then in your child adding function, right after the child adding logic, put the following code for smooth scrolling to the end of the listview.
_controller.animateTo(
_controller.position.maxScrollExtent,
duration: Duration(seconds: 1),
curve: Curves.fastOutSlowIn,
);
your function will look something like this.
void addChild(){
// put your adding child logic here
_controller.animateTo(
_controller.position.maxScrollExtent,
duration: Duration(seconds: 1),
curve: Curves.fastOutSlowIn,
);
}
We can also use _controller.jumpTo() for jumping to the end. But for smooth scrolling _controller.animateTo() is preferred.
But I would suggest adding the recently added children to the beginning of the list rather than adding it to the end. I mean rather than list.add(element), use of list.insert(0, element) is preferred.

How to use a variable with AnimatedContainer but still revert back to default properties

I am trying to add a collapsable note that expands to the full height determined by the amount of text inside of it with the click of a button.
The problem I am facing is when adding variable to determine the height of the AnimatedContainer
I want the AnimatedContainer to take a certain height if isCollapsed is true and a default height (that is, as much height as needed for the children (same as not specifying height)). I am trying to use condition ? do something : do something else but because it requires the :, I cannot just tell it to revert back to default.
This is simplified for the purpose of demonstration:
return AnimatedContainer(
duration: Duration(milliseconds: 300),
height: isCollapsed ? 100 : (revert to default),
child: Column(
TextField(),
TextField(),
),
)
Have you tried setting it to null?
height: isCollapsed ? 100 : null,

Flutter Bottom Container Swipe Up

I'm making an app which shows place detail when clicking a place on Google Maps. I can open a container at bottom of the page but I want to do that when the user swipe this container to up with animation, the container will cover the whole page and I will get extra information about that place and show the user.
How can I do that with Flutter?
You can try to use the package here:
https://pub.dev/packages/sliding_up_panel
However, if this does not fullfill you wish, try this instead: Wrap you Widget with a GestureDetector and an AnimatedController:
double containerHeight = 0;
GestureDetector(
onVerticalDragEnd: (dragUpdateDetails) {
setState(){
containerHeight = //device height or use MediaQuery.of(context).size.height//
}
},
child: AnimatedContainer(
duration: Duration(milliseconds: //how long should it take//),
height: containerHeight,
child: //whatever you want//
)
),
AnimatedController automatically animates between changes of properties. However, you might want to try changing onVertivalDragEnd to something else like onVerticalDragUpdate to fullfill your wish completely. If you want to have that behaviour for the full screen, wrap your first return Widget with the GestureDetector.
I guess DragableScrollableSheet fits your need. There is a good explanation here in the documentation.
You can use DraggableScrollableSheet
Document and Video tutorial available here:
https://api.flutter.dev/flutter/widgets/DraggableScrollableSheet-class.html

Flutter Vertical Scrollable Drawer

I would like to create something like this
I have a page with a list of products and I would like to make visible the "Cart" part only when I scroll to the bottom of the screen and when I click on a product and be able to swipe up to navigate to the cart screen.
A solution could be making a Stack with two Container inside and have a variable that represent the current % of screen of the first Container (products) and moving them with the widget Positioned. So when I scroll to the bottom, I can raise up the product container and reveal the cart container and same thing when I swipe up the first container.
This is an example of the vertical drawer with % and Positioned
Is there a better solution?
EDIT
I did it, but it's not very smooth
The structure:
CustomScrollView()
|
|____SliverList()
| |
| |____Visibility() => Container() //Products list
| |
| |____Visibility() => Container() //Bottom Container with Borders
|
|____SliverList()
|
|____Visibility() => Container() //Bottom Cart part
|
|____Visibility() => Container() //Cart Screen
Starting with only Products List visible
When user clicks on a product, Bottom Container and Bottom Cart will be visible
I also put a GestureDetector() in Bottom Container and Bottom Cart.
With onVerticalDragUpdate if the user swipe up (details.delta.dy < 0):
_controller.animateTo(
_controller.position.maxScrollExtent,
duration: Duration(seconds: 1),
curve: Curves.fastOutSlowIn,
);
And set visibility of Bottom Cart to false and set the Cart Screen visibility to true
As well I can might set the visibility of Products List to false, but this will cause a bug in the scroll animation so I set the mobile screen to only show Bottom Container and Cart Screen with the screen width (I didn't test it on other devices, this may be an error on ui) and I also block the scrolling with NeverScrollableScrollPhysics() in the CustomScrollView
On Swipe down on the Bottom Container, I set the visibility of Cart Screen to false, Bottom Cart to true and set CustomScrollView physics to AlwaysScrollableScrollPhysics() and made a scroll animation:
_controller.animateTo(
_controller.position.maxScrollExtent,
duration: Duration(seconds: 1),
curve: Curves.fastOutSlowIn,
);
That's not very smooth because a better animation could be moving down the Cart Screen with Positioned, instead of making it invisible

Is using AnimatedOpacity to hide and show complex widgets not effective in Flutter?

I'm using AnimatedOpacity to hide some widgets in Stack between various states in my app.
For instance I have Stack with ListView and animating loading indicator (shimmer) below, so that when list is populated the animated background opacity is gradually set to 0.
Stack:
- AnimatedOpacity (
opacity: _populated ? 0.0 : 1.0,
child: AnimatedLoadingWidget,
),
- ListView
Do I understand correctly that the animation in AnimatedLoadingWidget continues and is rendered even if opacity is set to 0.0? Does it have a performance impact on the app?
If you're wondering whether or not the widget is still rendered when an opacity of 0, then no.
Opacity and its animated variant is clever enough to not render the child if the opacity is strictly equal to 0.
But that's not enough. Even with an opacity of 0, your loading widget is still in the widget tree, and its animation continues to play.
To be more specific, with typical:
Opacity(
opacity: 0,
child: const CircularProgressIndicator(),
)
the spinner will not be visible, but it will still endlessly request new frames.
To fix that, we can use TickerMode widget like so:
Opacity(
opacity: 0,
child: TickerMode(
enabled: false,
child: const CircularProgressIndicator(),
),
)
Doing so will "mute" animations played using the animation framework, and as such, the spinner will stop requesting for new frames.
Alternatively, you can use AnimatedCrossFade with a custom layoutBuilder to achieve a similar effect.