Show content under a SliverChildBuilderDelegate - flutter

Is there a way to show widgets (for example a SliverToBoxAdapter or a normal Container) underneath a SliverChildBuilderDelegate? I have a condition that turns on the SliverList and there can only be one parent widget for a condition, what would I need to wrap it in?
Code currently looks like:
lass Testaaa extends StatelessWidget {
final bool hasData;
const Testaaa({Key key, this.hasData}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
drawer: DrawerSettings(),
body: Container(
child: CustomScrollView(
slivers: <Widget>[
AppBarSliver(),
hasData
? SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int i) {
return ListTile(
title: Text('cool'),
);
},
),
) // I would like to put another Container here that
// scrolls with the bottom, underneath the SliverList
: Container(
child: Text('no data'),
),
],
),
),
);
}

seems like a work for the spread operator
CustomScrollView(
slivers: <Widget>[
AppBarSliver(),
...hasData
? <Widget>[
SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int i) {
return ListTile(
title: Text('cool'),
);
},
),
),
const SliverToBoxAdapter(
child: SizedBox(
child: Text('End of the list'),
),
),
]
: <Widget>[
const SliverToBoxAdapter(
child: SizedBox(
child: Text('no data'),
),
)
]
],
)
This way you're telling if hasData is true add all this widgets in the brackets (SliverList and SliverToBoxAdapter with Text 'End of the list') if false add all this other widgets (which is only a SliverToBoxAdapter)

Related

How to put a Listview under the existing one Listview. Flutter/Dart

hello there i want to add another one listview on the same screen, how can i do that?
hello there i want to add another one listview on the same screen, how can i do that?
here is my code:
return Scaffold(
appBar: AppBar(title: Text('detailsPage'),
),
body: ListView(
children: [
Card(
child: ListTile(
title:new Center(child:new Text(utf8.decode(appController.userName.runes.toList()) + " " + utf8.decode(appController.userSurname.runes.toList()))),
subtitle:new Center(child:new Text('UserID: '+appController.userid.toString())),
)
),
Card(
child: ListTile(
title:new Center(child:new Text(months[index])),
subtitle:new Center(child:new Text("This month you have done "+appController.Totaleachlength[index].toString()+' charges')),
),
),
Card(
child: ListTile(
title:new Center(child:new Text(appController.Totaleachlist[index].toStringAsFixed(3)+"€")),
subtitle:new Center(child:new Text("Total amount")),
)
),
ElevatedButton(child: Text('Download Bill pdf'),
onPressed: () => ''),
ListTile(
title: new Center(child: new Text('Details of your charges'),),
),
],
shrinkWrap: true,
),
);
if you want to divide your screen, you can use Column
return Scaffold(
appBar: AppBar(title: Text('detailsPage'),),
body : Column(
children: [
Expanded(flex: 2 // you can customize as you need
child: ListView()
),
Expanded(flex: 3 // you can customize as you need
child: ListView()
),
])
Column:(
children: [
ListView1(),
ListView2(),
]
),
If each list didnt scroll, wrap your each one with SingleChildScrollView and if you like to listviews expand all height you can use Expanded
You can also add your another ListView at last child like
ListView:(
children: [
Card()
ListView()
]
)
You have to use shrinkWrap in your child ListView to extend the size in the screen
dont forget to add ClampingScrollPhysics to scroll from parent pehavior
class NestedListView extends StatelessWidget {
const NestedListView({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView(
children: [
...List.generate(
20, (index) => Text('Parent List View Index $index')),
ListView(
/// * [ClampingScrollPhysics], which provides the clamping overscroll behavior
physics: const ClampingScrollPhysics(),
/// * [shrinkWrap], which provides the Max size of list in screen
shrinkWrap: true,
children: List.generate(
20, (index) => Text('List View ONE Index $index')),
),
ListView(
physics: const ClampingScrollPhysics(),
shrinkWrap: true,
children: List.generate(
20, (index) => Text('List View Two Index $index')),
),
],
),
);
}
}

How to make a list of widgets mutate state based on activity on any one widget?

I have a GridView Widget which has a list of Custom Buttons. I want to freeze/disable all the remaining buttons in the list if one of the button in the list is clicked.
How can this be done? I had some ideas around perhaps making a Stateful List Widget that holds the state of whats clicked. But i do not know how to mutate that state. Or broadcast it to all the other objects to manipulate its state. Some guidance would be helpful.
#override
Widget build(BuildContext context) {
final title = 'Grid List';
return MaterialApp(
title: title,
home: Scaffold(
appBar: AppBar(
title: Text(title),
),
body: Column(
children: <Widget>[
Center(
child: Container(
height: 120.0,
width: 120.0,
color: Colors.blue[50],
child: Align(
alignment: Alignment.topRight,
child: FlutterLogo(
size: 60,
),
),
),
),
new Expanded(
child: GridView.count(
// shrinkWrap: false,
// Create a grid with 2 columns. If you change the scrollDirection to
// horizontal, this produces 2 rows.
childAspectRatio: 1.2,
crossAxisCount: 2,
// Generate 100 widgets that display their index in the List.
children: <Center> [
Center(child: Option("Option 1")),
Center(child: Option("Option 2")),
Center(child: Option("Option 3")),
Center(child: Option("Option 4"))
],
)
)
],
),
),
);
}
}
You should employ a state management solution such as riverpod (pub.dev) (docs).
This isn't a scalable example but should be enough to get you started.
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
final disabledButtonsProvider = StateProvider<List<bool>>((_) => List.generate(4, (_) => false));
class ButtonGrid extends ConsumerWidget {
const ButtonGrid({Key? key}) : super(key: key);
#override
Widget build(BuildContext context, ScopedReader watch) {
final disabledButtons = watch(disabledButtonsProvider).state;
return Scaffold(
body: GridView.count(
crossAxisCount: 2,
children: List.generate(
4,
(index) => ElevatedButton(
onPressed: disabledButtons[index]
? null
: () => context.read(disabledButtonsProvider).state =
List.generate(4, (i) => i != index),
child: Text(index.toString()),
),
),
),
);
}
}

Rounded corners with Customscrolview and SliverList / SliverAppBar in Flutter

I'm working on an app in Flutter and want to have the following design of my SliverAppBar with the rounded corners to the bottom in my App. How can I do this when I use slivers?
Design rounded corner
I found the design on Dribbble from a YouTuber who created the app as a tutorial but without using a PageView with Slivers
This is a simplified version of the code I'm using:
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: PageView(
children: [
CustomScrollView(
slivers: <Widget>[
SliverAppBar(
backgroundColor: Colors.red,
expandedHeight: 250.0,
),
SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return Card(
child: ListTile(
title: Text('something'),
),
);
},
childCount: 10,
))
],
),
],
),
),
);
}
}
use SliverPadding like this:
DefaultTabController(
child:NestedScrollView(
headerSliverBuilder:
(BuildContext context, bool innerBoxIsScrolled) {
return [
SliverPadding(
padding: new EdgeInsets.only(top: 5.0),
sliver: new SliverList(
delegate: new SliverChildListDelegate(
[YOR_WIDGET()]),
),
);
]

Create customized SliverPersistentHeader like Widget with Flutter

I have a Header that consists of:
1 - appBar (title + return button)
2 - row with a data picker)
3 - a row serving as a customized TabBar (with two Tabs)
4 - a row serving as a FilterBar (with a Button and a search field)
Then I have the "body" with a list of Cards that is scrollable.
I needed to retract/hide numbers 1-3 and keep only number 4 visible when I scroll down the list of cards. How could I build a customized Widget to help me with that?
Here is part of the code (it's too long to bring everything):
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
slivers: [
SliverAppBar(
backgroundColor: Colors.blue,
title: 'List of Tasks',
elevation: 0.0,
pinned: true,
),
SliverPadding(
padding: EdgeInsets.all(15),
sliver: SliverToBoxAdapter(
child: DatePicker(
date: date,
onChange: (newDate) {
setState(() {});
},
),
),
),
SliverToBoxAdapter(
child: ActivitiesTabController(
pageController: _pageController,
currentTab: currentTab,
onChangedTab: (currentTab) {},
),
),
SliverToBoxAdapter(
child: Row(
children: [
SearchFilterBar(
taskId: taskId,
onChange: (floors, serviceName) {},
),
],
),
),
SliverList(
delegate: SliverChildBuilderDelegate((BuildContext context, int index) {
return new Container(color: Colors.amberAccent, height: 150.0);
}),
),
],
));
}
I think you're referring to two app bars, where the first one can be scrolled away while the second one is persistent.
I think it would be something like this:
#override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(slivers: [
SliverAppBar(
title: Text('This hides'),
),
SliverAppBar(
title: Text('This is always shown'),
pinned: true,
primary: false,
),
SliverList(
delegate: SliverChildBuilderDelegate(
(_, i) {
return ListTile(title: Text('Line $i'));
},
childCount: 150,
),
),
]),
);
}

How to change SliverAppBar height dynamically

I show image from network, which shrink on scrolling. I want to show whole image without paddings or crops. But if I comment line with expandedHeight - there is no image - only appbar with its height. Is there any widget, which can change its size according to size of uploaded image?
CustomScrollView(
controller: controller,
key: listKey,
slivers: <Widget>[
SliverAppBar(
// expandedHeight: 200.0,
flexibleSpace: FlexibleSpaceBar(
background: getHeroWidget(
_conference.dbId,
FadeInImage.assetNetwork(
placeholder: conf_img_placeholder,
image: _conference.info.image,
fit: BoxFit.cover,
)),
title: Text(conference_title),
centerTitle: true,
),
pinned: true,
),
Finally I created custom SliverAppBar. Another issue appears - width of status bar which have to be taken into consideration on calculation.
import 'dart:ui' as ui;
class _HeaderBar extends StatefulWidget {
#override
State<StatefulWidget> createState() => _HeaderState();
}
class _HeaderState extends State<_HeaderBar> {
#override
Widget build(BuildContext context) {
Image image = Image.network(...);
Completer<ui.Image> completer = new Completer<ui.Image>();
image.image.resolve(ImageConfiguration()).addListener((ImageInfo info, bool _) {
completer.complete(info.image);
});
final double statusBarHeight = MediaQuery.of(context).padding.top;
return FutureBuilder(
future: completer.future,
builder: (context, AsyncSnapshot<ui.Image> snapshot) {
return SliverAppBar(
expandedHeight: snapshot.hasData
? MediaQuery.of(context).size.width / snapshot.data.width.toDouble() * snapshot.data.height.toDouble() -
statusBarHeight
: 0.0,
...
I was looking for this problem, I find a solution with NestedScrollView and a plugin SliverStickyHeader
Here is how I did this,
Scaffold(
body: SafeArea(
child: NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[
SliverStickyHeader(
sticky: false,
header: Container(
color: Theme.of(context).primaryColor,
child: Column(
children: [
Text(
'Header',
style: Theme.of(context).textTheme.headline6,
),
Text(
'Header',
style: Theme.of(context).textTheme.headline5,
),
Text(
'Header',
style: Theme.of(context).textTheme.headline4,
),
Text(
'Header',
style: Theme.of(context).textTheme.headline3,
),
],
),
),
)
];
},
body: Column(
children: [
AppBar(
title: Text('My List items'),
),
Expanded(
child: ListView.builder(itemBuilder: (context, i) {
return ListTile(
leading: CircleAvatar(child: Text('$i')),
title: Text('Appbar with dynamic height'),
);
}),
),
],
),
),
),
);
and it is fulfilling my requirement, Plugin also support fully Sliver functionality, but I use it with as header only. I hope it will be helpful.