CustomScrollView within ExpansionTile error - flutter

Tried to fix this reading some documentation and some open issues but was not lucky.. Could someone please help?
I am getting this error:
type 'bool' is not a subtype of type 'double' in type cast
Not sure why though I tried adding container wrapping the component, adding height, adding flexible box etc...
No lucky
`import 'package:flutter/material.dart';
class SampleData {
SampleData(this.title, [this.children = const <SizedBox>[]]);
final String title;
final List<SizedBox> children;
}
final List<SampleData> data = <SampleData>[
SampleData("IT", [
SizedBox(
height: 300,
width: 300,
child: CustomScrollView(
scrollDirection: Axis.horizontal,
slivers: <Widget>[
new SliverToBoxAdapter(
child: Text('fesfefes'),
),
],
),
),
]),
];
class Branch extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Test 123'),
),
body: Container(
width: 500,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemBuilder: (BuildContext context, int index) => Item(data[index]),
itemCount: data.length,
),
),
);
}
}
// Displays one Entry. If the entry has children then it's displayed
// with an ExpansionTile.
class Item extends StatelessWidget {
const Item(this.sample);
final SampleData sample;
Widget _buildTiles(SampleData root) {
return SizedBox(
width: 500,
child: ExpansionTile(
key: PageStorageKey<SampleData>(root),
title: Text(root.title),
children: root.children,
),
);
}
#override
Widget build(BuildContext context) {
return _buildTiles(sample);
}
}
`

You can copy paste run full code blow
You can remove
//key: PageStorageKey<SampleData>(root),
working demo
full code
import 'package:flutter/material.dart';
class SampleData {
SampleData(this.title, [this.children = const <SizedBox>[]]);
final String title;
final List<SizedBox> children;
}
final List<SampleData> data = <SampleData>[
SampleData("IT", [
SizedBox(
height: 300,
width: 300,
child: CustomScrollView(
scrollDirection: Axis.horizontal,
slivers: <Widget>[
new SliverToBoxAdapter(
child: Text('fesfefes'),
),
],
),
),
]),
];
class Branch extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Test 123'),
),
body: Container(
width: 500,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemBuilder: (BuildContext context, int index) => Item(data[index]),
itemCount: data.length,
),
),
);
}
}
// Displays one Entry. If the entry has children then it's displayed
// with an ExpansionTile.
class Item extends StatelessWidget {
const Item(this.sample);
final SampleData sample;
Widget _buildTiles(SampleData root) {
return SizedBox(
width: 500,
child: ExpansionTile(
//key: PageStorageKey<SampleData>(root),
title: Text(root.title),
children: root.children,
),
);
}
#override
Widget build(BuildContext context) {
return _buildTiles(sample);
}
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: Branch(),
);
}
}

Related

Refresh the page data when you go to this page in the flutter

I'm trying to write a small application in which I collect data through api. I take the data, everything works. I decided to make a navigation bar to switch between pages. But when I try on the pages they are empty. In order for the data to be updated on the page, I need to click "Hot reload". I will be grateful for your help.
My main.dart:
import 'package:flutter/material.dart';
import 'package:flutter_app_seals/model/dataArea_list/JsonDataArea.dart';
import 'package:flutter_app_seals/model/object_list/JsonObject.dart';
import 'package:flutter_app_seals/model/seals_list/JsonSeals.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: new HomeScreen());
}
}
class HomeScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text('Журнал пломби'),
),
// body: Seals(),
drawer: Drawer(
child: ListView(
children: <Widget>[
ListTile(
title: Text("Seals List"),
trailing: Icon(Icons.arrow_back),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => Seals()),
);
}
)
],
),
),
);
}
}
class Seals extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home:JsonParseSeals(),
);
}
}
My modul Seals:
import 'package:flutter/material.dart';
import 'package:flutter_app_seals/model/seals_list/SealsListGet.dart';
import 'package:flutter_app_seals/model/seals_list/ServicesSeals.dart';
class JsonParseSeals extends StatefulWidget {
//
JsonParseSeals() : super();
#override
_JsonParseSealsState createState() => _JsonParseSealsState();
}
class _JsonParseSealsState extends State <StatefulWidget> {
//
List<SealList> _seals;
bool _loading;
#override
void initState(){
super.initState();
_loading = true;
Services.getSeals().then((seals) {
_seals =seals;
_loading = false;
}
);
}
#override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text('Список пломби'),
),
body: ListView.builder(
physics: BouncingScrollPhysics(),
padding: EdgeInsets.all(40),
itemCount: null == _seals ? 0 :_seals.length,
itemBuilder: (_,index) => Card(
color: Colors.red[300],
margin: EdgeInsets.symmetric(vertical: 7),
child:ListTile(
title: Text(_seals[index].sealNumber,
style: TextStyle(fontSize: 30),
),
subtitle: Text(
"${_seals[index].used}" ),
leading: Icon(Icons.local_activity,
size: 40,
color: Colors.black87,
),
),
),
),
);
}
}
My code :
Code after change:
Try to wrap your screen with data in FutureBuilder (you can read more about this widget here):
class _JsonParseSealsState extends State <StatefulWidget> {
#override
Widget build(BuildContext context) {
return FutureBuilder<List<SealList>>(
future: Services.getSeals(),
builder: (context, snapshot) {
// Data is loading, you should show progress indicator to a user
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(),
);
}
// Data is loaded, handle it
return ListView.builder(
physics: BouncingScrollPhysics(),
padding: EdgeInsets.all(40),
itemCount: snapshot.data.length,
itemBuilder: (_, index) {
final item = snapshot.data[index];
return Card(
color: Colors.red[300],
margin: EdgeInsets.symmetric(vertical: 7),
child: ListTile(
title: Text(
item.sealNumber,
style: TextStyle(fontSize: 30),
),
subtitle: Text("${item.used}"),
leading: Icon(
Icons.local_activity,
size: 40,
color: Colors.black87,
),
),
);
},
),
}
);
}
}

Flutter ListView scroll animation overlapping sibling widget

Hoping someone can help with this and it's not a bug and it's just me being silly.
There is very strange behavior from listview when it's not taking the full length of the screen and in a column.
When you scroll down, the animation at max extent persists and overlaps. I'm assuming this is a bug and not by design.
Here's the simple code to reproduce.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp(
items: List<MessageItem>.generate(
33,
(i) => MessageItem("Sender $i", "Message body $i"),
),
));
}
class MyApp extends StatelessWidget {
final List<MessageItem> items;
MyApp({Key key, #required this.items}) : super(key: key);
#override
Widget build(BuildContext context) {
final title = 'Mixed List';
return MaterialApp(
title: title,
home: Scaffold(
appBar: AppBar(
title: Text(title),
),
body: Column(
children: [
Expanded(
child: Container(),
),
Expanded(
child: ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
final item = items[index];
return ListTile(
title: item.buildTitle(context),
subtitle: item.buildSubtitle(context),
);
},
),
),
],
),
),
);
}
}
/// A ListItem that contains data to display a message.
class MessageItem {
final String sender;
final String body;
MessageItem(this.sender, this.body);
Widget buildTitle(BuildContext context) => Text(sender);
Widget buildSubtitle(BuildContext context) => Text(body);
}
So final code will be. I have added the scroll phisycs BouncingScrollPhysics.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp(
items: List<MessageItem>.generate(
33,
(i) => MessageItem("Sender $i", "Message body $i"),
),
));
}
class MyApp extends StatelessWidget {
final List<MessageItem> items;
MyApp({Key key, #required this.items}) : super(key: key);
#override
Widget build(BuildContext context) {
final title = 'Mixed List';
return MaterialApp(
title: title,
home: Scaffold(
appBar: AppBar(
title: Text(title),
),
body: Column(
children: [
Expanded(
child: Container(
),
),
Expanded(
child: ListView.builder(
physics: BouncingScrollPhysics(
parent: AlwaysScrollableScrollPhysics()),
itemCount: 50,
itemBuilder: (context, index) {
return ListTile(
title: Text("${index + 1}"),
subtitle: Text("${index + 1}"),
);
},
),
),
],
),
),
);
}
}
/// A ListItem that contains data to display a message.
class MessageItem {
final String sender;
final String body;
MessageItem(this.sender, this.body);
Widget buildTitle(BuildContext context) => Text(sender);
Widget buildSubtitle(BuildContext context) => Text(body);
}
I'm not sure if this is a bug or not. Or if my solution is the correct way of doing it, or not. But this work
#override
Widget build(BuildContext context) {
return NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[
SliverOverlapAbsorber(
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
sliver: SliverAppBar(
backgroundColor: Colors.white,
toolbarHeight: 200,
pinned: true,
forceElevated: innerBoxIsScrolled,
),
),
];
},
body: Container(
child: SafeArea(
top: false,
bottom: false,
child: Builder(
builder: (BuildContext context) {
return CustomScrollView(
key: PageStorageKey<String>("name"),
slivers: <Widget>[
SliverOverlapInjector(
handle:
NestedScrollView.sliverOverlapAbsorberHandleFor(context),
),
SliverPadding(
padding: const EdgeInsets.all(8.0),
sliver: SliverFixedExtentList(
itemExtent: 48.0,
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return ListTile(
title: Text('Item $index'),
);
},
childCount: 30,
),
),
),
],
);
},
),
)),
);
}
The reason I don't like this is that I'm putting non-bar content in an AppBar.
If anyone has a better solution please let me know.

How to prevent Hero animation from covering SliverAppBar?

I have a Hero animation that should animate an image from a ListView to the background of a FlexibleSpaceBar inside of a SliverAppBar.
This works all fine, except that the hero animation takes place on top of the SliverAppBar and when the animation is finished, the SliverAppBarsuddenly pops in on top of the background, which doesn't look so nice.
How can I either a) include the SliverAppBar in the hero transition so that it fades in on top of the image as the transition progresses or b) make the hero transition take place under the SliverAppBar without covering it?
Sample Code:
import 'dart:math';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
initialRoute: '/',
routes: {
'/': (context) => HomePage(),
'/details': (context) => DetailsPage(),
},
);
}
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: PreferredSize(
preferredSize: AppBar().preferredSize,
child: Hero(
tag: 'appbar',
child: AppBar(
title: Text('title'),
actions: <Widget>[
PopupMenuButton<String>(
itemBuilder: (BuildContext context) {
return [
PopupMenuItem<String>(
child: Text('Action'),
)
];
},
),
],
),
),
),
body: ListView.builder(
padding: const EdgeInsets.fromLTRB(10, 10, 10, 0),
itemCount: 10,
itemBuilder: (context, index) => buildListItem(context, index),
),
);
}
Widget buildListItem(BuildContext context, int index) {
return Padding(
padding: const EdgeInsets.only(bottom: 10),
child: InkWell(
onTap: () async {
await Navigator.of(context).pushNamed(
'/details',
arguments: index,
);
},
child: Row(
children: <Widget>[
Hero(
tag: index,
child:
SizedBox(width: 80, height: 80, child: widgetForIndex(index)),
),
],
),
),
);
}
}
Widget widgetForIndex(int index) {
return Container(color: Color.fromARGB(255, max(0, 255 - 20 * index), 0, 0));
}
class DetailsPage extends StatefulWidget {
#override
_DetailsPageState createState() => _DetailsPageState();
}
class _DetailsPageState extends State<DetailsPage> {
#override
Widget build(BuildContext context) {
final int index = ModalRoute.of(context).settings.arguments;
return Scaffold(
body: CustomScrollView(
slivers: [
SliverAppBar(
title: Text('Details'),
expandedHeight: 300,
flexibleSpace: FlexibleSpaceBar(
background: Hero(
tag: index,
child: widgetForIndex(index),
),
),
),
SliverToBoxAdapter(
child: Column(
children: [
Container(
color: Colors.green,
width: 200,
height: 200,
),
],
),
),
],
),
);
}
}

SliverAppBar() not collapsing with ListView in Flutter

I'm trying to display tabs for each main tab (Nested Tab Bar) in SliverAppBar(). It's look like this:
See the image
See the GIF
The content of the exam tab it's in Container() widget (That the error in the image came from).
Now, with the Container() widget the SliverAppBar() will collapse when the user scroll the exam tab content (white screen in the image), everything is fine for now.
So, After I replaced the Container() with ListView.builder() to make the tab content scrollable, now I can't collapse SliverAppBar() from the tab content (white screen in the image). but I can from the SliverAppBar().
See this GIF after I added ListView.builder()
So, How I can make the SliverAppBar scrollable (collapsing ) with Listview?
Can anyone help me? please :(
This example (demo):
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(title: 'SliverAppBar App Demo'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: DefaultTabController(
length: 2,
child: NestedScrollView(
headerSliverBuilder:
(BuildContext context, bool innerBoxIsScrolled) {
return [
SliverOverlapAbsorber(
handle:
NestedScrollView.sliverOverlapAbsorberHandleFor(context),
child: SliverSafeArea(
top: false,
sliver: SliverAppBar(
pinned: true,
title: Text(widget.title),
expandedHeight: 500,
),
),
),
SliverPersistentHeader(
delegate: _SliverAppBarDelegate(
TabBar(tabs: [Tab(text: 'Tab A'), Tab(text: 'Tab B')]),
Colors.blue,
),
pinned: false,
),
];
},
body: TabBarView(
children: <Widget>[
NestedTabs('A'),
NestedTabs('B'),
],
),
),
),
),
);
}
}
// This class is to handle the main tabs (Tab A & Tab B)
class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
_SliverAppBarDelegate(this._tabBar, this._color);
TabBar _tabBar;
final Color _color;
#override
double get minExtent => _tabBar.preferredSize.height;
#override
double get maxExtent => _tabBar.preferredSize.height;
#override
Widget build(
BuildContext context, double shrinkOffset, bool overlapsContent) {
return new Container(
color: _color,
alignment: Alignment.center,
child: _tabBar,
);
}
#override
bool shouldRebuild(_SliverAppBarDelegate oldDelegate) {
return false;
}
}
class NestedTabs extends StatelessWidget {
final String mainTabName;
NestedTabs(this.mainTabName);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: PreferredSize(
preferredSize: Size.fromHeight(20),
child: Container(
color: Colors.blue,
alignment: Alignment.bottomCenter,
child: TabBar(
tabs: [
Tab(text: 'Tab $mainTabName-1'),
Tab(text: 'Tab $mainTabName-2')
],
),
),
),
body: TabBarView(
children: [
ListView.builder(
padding: const EdgeInsets.all(8),
itemCount: 500,
itemBuilder: (BuildContext context, int index) {
return Container(
height: 50,
width: 200,
color: Colors.black45,
child: Center(child: Text('Index ${index}')));
},
),
ListView.builder(
padding: const EdgeInsets.all(8),
itemCount: 500,
itemBuilder: (BuildContext context, int index) {
return Container(
height: 50,
width: 200,
color: Colors.black45,
child: Center(child: Text('Index ${index}')));
},
)
],
),
);
}
}
Thank you :)
Use SliverList() instead of SliverFillRemaining for ListView

The getter 'bloc' called on null

I tried to create listview using bloc.
this is my bloc class
MainPageList model looks like this
class MainPageList { List items; List icons;
MainPageList(this.items, this.icons); }
class MainPageBloc extends BlocBase {
MainPageList _mainPageList;
StreamController<MainPageList> _mainPageController =
StreamController<MainPageList>.broadcast();
StreamSink<MainPageList> get _inMainPage => _mainPageController.sink;
Stream<MainPageList> get outMainPage => _mainPageController.stream;
MainPageBloc(context) {
init(context);
}
void init(BuildContext context) async {
_mainPageList.items = [
AppTranslations.of(context).text("submit_request"),
AppTranslations.of(context).text("signout")
];
_mainPageList.icons = [
"lib/assets/images/submit_req.svg",
"lib/assets/images/sign_out.svg"
];
_inMainPage.add(_mainPageList);
}
#override
void dispose() {
_mainPageController.close();
}
}
In widget class I tried to call bloc.
#override
Widget build(BuildContext context) {
final MainPageBloc mainBloc = BlocProvider.of<MainPageBloc>(context);
return WillPopScope(
onWillPop: () async => false,
child: Scaffold(
body: StreamBuilder<MainPageList>(
assign stream,
stream: mainBloc.outMainPage,
builder: (context, snapshot) {
Container(
child: Scaffold(
body: Container(
child: ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: snapshot.data.items.length,
itemBuilder: (BuildContext context, int index) {
return Card(
child: Container(
child: ListTile(
contentPadding: EdgeInsets.symmetric(
horizontal: 5.0, vertical: 0.0),
assign to icons
leading: Container(
child: SvgPicture.asset(
snapshot.data.icons[index],
width: 40.0,
color: const Color(0xFFE27023),
),
),
assign to items
title: Text(
snapshot.data.items[index],
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold),
),
You are not providing enough code to know the context of your build method but it seems that you are using a BlocProvider. You should know that in order to have the bloc in the context of your widget you have to call it this way:
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'My App',
home: BlocProvider<MyBloc>(
bloc: MyBloc(),
child: MyHome(),
),
);
}
}
class MyHome extends StatelessWidget{
#override
Widget build(BuildContext context) {
myBloc = BlocProvider.of<MyBloc>(context);
return Container();
}
}
As you can see, home of my app is not directly MyHome but a BlocProvider widget.