What I'm trying to achieve:
Picture 1: View should be scrollable and the NoData container should fill up the remaining space.
SliverFillRemaining just scrolls under the SliverAppBar which is not wanted - it should stop at the top which seems not to be possible.
Picture 2: You should be able to scroll away the SliverAppBar, Background, TabBar, etc and view the No Data in full like there never was a SliverAppBar there (at least the expanded portion of it).
Picture 3: Now there's ONE content - I still want the view to behave the same.
Currently this just means the screens looks like Picture #1 with a Row inserted. Eh? Ugly.
Picture 4: Now there's many rows of content - the view should scroll away the SliverAppBar and continue with the scroll view.
But this is not what it looks like. If there's no "body" in the Widget the SliverAppBar just sits there. Adding a secondary scrolling view for the Rows just means it scrolls by itself while the SliverAppBar still just sits there. Using a SliverFillRemaining scrolls below the SliverAppBar even though there's just one row of content? That's not the remaining space? That's remaining space + AppBar - which is more than what's remaining.
In this case the SliverAppBar consists of this:
SliverAppBar(
expandedHeight: 512,
collapsedHeight: kToolbarHeight,
toolbarHeight: kToolbarHeight,
pinned: true,
floating: false,
snap: false,
elevation: 0,
backgroundColor: theme.primaryColor,
leading: CloseButton(onPressed: onBackButton),
title: Text("Title"),
automaticallyImplyLeading: false,
stretch: true,
flexibleSpace: const FlexibleSpaceBar(
background: getBackground(), // Background Image with some "Info" in it
),
bottom: getBottom(), // TabBar
)
I've tried calculating the screen size remaining once the "SliverAppBar" is scrolled away but then there's the scrolling issue that it won't scroll both views at the same time. Regardless of primary: true/false, shrinkWrap: true/false. Also adding this "calculated" Container to a SliverFillRemaining is just plain ignored. I can set it to any size it still ignores the height set.
But the biggest question is - why would anyone want a SliverAppBar that's not always "scroll away-able" (for lack of a better term). If there's no content in the screen it just looks weird. I at least want the screen excluding the SliverAppBar to always take up the space of the screen with scrolling intact.
Is SliverListDelegate the only alternative? But Row, Row, Row in Picture #4 may not be the only scenario this applies to. In that case it doesn't feel correct to add a ListBuilder everytime you want to add a few Widgets. If I know there will be 4 widgets I'm not sure why I need a ListBuilder for that. But if I'm scrolling 200 items I agree.
In short, most solutions for this seems like hacks as of now.
Suggestions?
Related
Is there any easy way to have a SliverAppBar be transparent when expanded and then take a color when collapsed when used in combination with a FlexibleSpaceBar?
I want to use the FlexibleSpaceBar so that my title will collapse when the sliver list is scrolled up and down
It seems right now the default behavior is the opposite. If you make the sliverAppBar transparent off the bat
SliverAppBar(
pinned: true,
expandedHeight: 100.0,
elevation: 0,
backgroundColor: Colors.transparent,
Then there is no way to control the background color when its collapsed. If you try to give a color here, then when its collapsed it successfully has a color but it cannot be made transparent when expanded.
Ok I ultimately solved this by keeping the SliverAppBar as transparent, and then placing a Container widget into it. Then using a scrollcontroller listener, I would animate the color of the containers background color as a scroll is happening.
It was a painful process, but it is working flawlessly
I have a transparent app bar that hides some of my content, because the content starts behind the app bar:
My Scaffold looks like this:
return Scaffold(
extendBody: true,
extendBodyBehindAppBar: true,
appBar: getAppBar(),
body: generateMainBody(context),
);
If I would set extendBodyBehindAppBar to false it would work, however, the appbar would not be transparent anymore (when scrolling the area that is not part of that cool shape would be black and not transparent like in the screenshot).
I thought of adding some top padding to just move the cut content down a little bit but surely there has to be a better solution?
In your generateMainBody function, wrap your current return with padding and change the padding padding: const EdgeInsets.only(top: 8.0),. You can increase or decrease the '8.0' to best suit your app.
Since the only solution seems to be some kind of padding I settled with this:
SizedBox(height: MainAppBar.appBarHeight)
I simply added an empty SizedBox that has the height of the AppBar to the top of my content.
I have an app that has a bottomNavigationBar() wrapped in a clipRRect() but the content doesn't show behind it. The same behaviour also happens with transparent SliverAppBar()s in NestedScrollView()s. How can I achieve this?
Edit: Here is an example of the SliverAppBar() problem. The shadow is being hidden by the app bar.
you can try this:
Scaffold(
extendBody: true,
extendBodyBehindAppBar: true,
and give a little padding to the top and bottom of you body content for overlapping at the very top and bottom.
So I'm having some difficulty using the following Setup:
CustomScrollView(
slivers: [
SliverAppBar(...),
SliverToBoxAdapter(SomeRandomWidget),
SliverPersistentHeader(TabBar),
SliverFillRemaining(TabBarView)
])
So the TabBarView contains a Column on one tab, that overflows the screen. The issue is, that even though SliverFillRemaining is obviously not the right choice for the overflowing Widget but sadly as TabBarView looses the hasSize property of its children, I don't know what other Widget I could use to get the layout going. The goal is to achieve something like this (shows the current overflow):
EDIT: Here is a working example on DartPad: https://dartpad.dev/bda4cc5fd2aea292310fe05daa440760
try using extended_nested_scroll_view, maybe that's what you looking for
add floating: true, under pinned: true,
I want to only make a part of my screen scrollable. When the number of items in my ListView exceeds 4 or 5 I am unable to place any widgets below this list view. I am not sure if there is a way to wrap all the contents of the listview to make that scrollable.
ListView(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
children: _getListings(businessListing),
),
This is my ListView and this is how the UI looks
The problem is when the number of RadioTile exceeds 8; the textField and the Button are pushed out of the screen.
I am wondering if it is good to make the entire screen scrollable?
Or make only a part of the screen containing the RadioTiles Scrollable?
Thanks,
To complete thebuggycoder answer if you want to keep only a part of your screen scrollable but keep variable height bottom elements, you can embed your ListView inside the Expanded of a Column, as shown below:
Column(
children: [
Expanded(
child: ListView(
children: _getListings(businessListing),
),
),
Container(
child: Text('This element must stay at the bottom'),
),
],
);
What are you doing there is basically telling your Column that it has 2 (or more) elements where each element usually takes the space it needs, except elements that are Expanded elements and will take "the maximum space left" in the Column.
There are a couple of points to consider:
If you plan to have more fields below the RadioTiles along with the Google Listing URL and the Save button, then it might be a good option to keep the entire screen scrollable.
On the other hand, if it's going to be just the two things below the RadioTiles, then it would be better to keep only the RadioTile list to be scrollable. This way the TextField and the Save button will always be accessible to the user without the need to scroll.
Also, you can decide about the scrolling depending on the priority of the fields. If the TextField and Save button have more priority then it would be best if they are always visible on the screen.
To make only a part of the screen scrollable, you can wrap the ListView in a Container with some fixed height, so that the it will scroll only within those bounds.
You will also need to change the physics property to AlwaysScrollableScrollPhysics().
Example -
Container(
height: 300.0 //Your custom height
child: ListView(
shrinkWrap: true,
physics: AlwaysScrollableScrollPhysics(),
children: _getListings(businessListing),
),
)