How to insert Listview.Builder in Listview.Builder item - flutter

Parent Code
how to insert my listviewBuilder in listViewBuilder item
this is my parent code
Expanded(
child: Container(
padding: EdgeInsets.only(top: 10.0),
decoration: Ui.getBoxDecoration(),
child: ListView.separated(
itemBuilder: (context, index) {
var _comment =
controller.commentWithDetailDtoList.elementAt(index);
return TimelineCommentItemWidget(comment: _comment);
},
separatorBuilder: (context, index) => SizedBox(height: 10.0),
itemCount: controller.commentWithDetailDtoList.length,
),
),
)
Child Code
and this is my child code
Visibility(
child: ListView.separated(
itemBuilder: (context, index) {
var reply = comment.replies.elementAt(index);
return TimelineCommentRepliesItemWidget(comment: reply);
},
separatorBuilder: (context, index) => SizedBox(height: 10.0),
itemCount: comment.replies.length,
),
),

Here is the code.
Please check this out.
import 'package:flutter/material.dart';
const Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: darkBlue,
),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: MyWidget(),
),
),
);
}
}
class MyWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ListView.separated(itemBuilder : (BuildContext context , int i) {
return _innerWidget();
} , itemCount : 2 , shrinkWrap: true,separatorBuilder: (context, index) => SizedBox(height: 10.0), );
}
}
Widget _innerWidget(){
return ListView.builder(itemBuilder : (BuildContext context , int i) {
return Text('hello');
}, itemCount: 2,shrinkWrap: true, physics: NeverScrollableScrollPhysics(),);
}

Related

I want to scroll up after the all childs of ListView have been scrolled up, parent widget of listview is SingleChildScrollView in flutter

I have SingleChildScrollView as a parent and in that, I have two listviews each list view is wrapped with SizedBox with a specific height (like 700), what I want is, when I scroll up all the views that are in the first list, the first Listview should scroll up and then I'll be able to scroll next Listview, Please have a look into the code below.
Your help means a lot to me.
Thank you in advance.
Note: I'm getting this required behavior in chrome but not on a mobile device
SingleChildScrollView( child: Column(children: [
SizedBox(
height: 700,
child:ListView.builder(
itemCount:
20, itemBuilder: (context, index) {
return const ListTile(leading: Icon(Icons.icecream,
color: Colors.amber,), title: Text("Ice Cream"),);
},),
),
SizedBox(
height: 300,
child: ListView.builder(
itemCount: 20, itemBuilder: (context, index) {
return const ListTile(
leading: Icon(Icons.cake, color: Colors.red,),
title: Text("Cake"),);
},),
),
],),)
You Can Do something like this on the Controllers:
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class ScrollingBehaviourInDart extends StatefulWidget {
const ScrollingBehaviourInDart({Key? key}) : super(key: key);
#override
State<ScrollingBehaviourInDart> createState() =>
_ScrollingBehaviourInDartState();
}
class _ScrollingBehaviourInDartState extends State<ScrollingBehaviourInDart> {
late ScrollController _sc1;
late ScrollController _sc2;
late ScrollController _sc3;
#override
void initState() {
_sc1 = ScrollController();
_sc2 = ScrollController();
_sc3 = ScrollController();
var _pr = Provider.of<MyScrollProvider>(context, listen: false);
_sc1.addListener(() {
log("SC1::::::::::: " + _sc1.position.pixels.toString());
if (_sc1.position.pixels == _sc1.position.minScrollExtent) {
print("OK");
_pr.changePhysics(enableScrolling: true);
}
});
_sc2.addListener(() {
if (_sc2.offset == _sc2.position.maxScrollExtent) {
_pr.changePhysics(enableScrolling: false);
log("YAAA");
}
});
_sc3.addListener(() {
log("SC3::::::::::: " + _sc3.position.pixels.toString());
});
super.initState();
}
#override
void dispose() {
_sc1.dispose();
_sc2.dispose();
_sc3.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
var _size = MediaQuery.of(context).size;
return SafeArea(
child: Scaffold(
backgroundColor: Colors.white.withOpacity(0.8),
body: SizedBox(
height: _size.height,
child: Consumer<MyScrollProvider>(
builder: (context, myScrollProvider, _) => SingleChildScrollView(
controller: _sc1,
child: Column(
children: [
SizedBox(
height: _size.height * 0.5,
child: ListView.builder(
controller: _sc2,
physics: myScrollProvider.enablePrimaryScroll
? const AlwaysScrollableScrollPhysics()
: const NeverScrollableScrollPhysics(),
itemCount: 20,
shrinkWrap: true,
itemBuilder: (context, index) {
return const ListTile(
leading: Icon(
Icons.icecream,
color: Colors.amber,
),
title: Text("Ice Cream"),
);
},
),
),
ListView.builder(
itemCount: 20,
controller: _sc3,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) {
return const ListTile(
leading: Icon(
Icons.cake,
color: Colors.red,
),
title: Text("Cake"),
);
},
),
],
),
),
),
),
),
);
}
}
class MyScrollProvider extends ChangeNotifier {
var enablePrimaryScroll = true;
changePhysics({required bool enableScrolling}) {
enablePrimaryScroll = enableScrolling;
notifyListeners();
}
}
maybe you can use Stickyheader.
import 'package:sticky_headers/sticky_headers.dart';
ListView(
shrinkwarp:true,
children:[
StickyHeader(
head: Text('List 1 '),
content : ListView.builder(
physics: const ClampingScrollPhysics(), // use this for clamping scroll
itemBuilder: (context, idx) => Container(),
itemCount:5,
)
StickyHeader(
head: Text('List 2 '),
content : ListView.builder(
physics: const ClampingScrollPhysics(), // use this for clamping scroll
itemBuilder: (context, idx) => Container(),
itemCount:5,
)
]
}
There are many easy ways to handle this situation as stated by many other developers. I have created an Example class with ScrollController and AbsordPointer classes to achieve the required behavior.
Sample
class Example extends StatefulWidget {
const Example({super.key});
#override
State<Example> createState() => _ExampleState();
}
class _ExampleState extends State<Example> {
late ScrollController scrollController;
var reachedAtEnd = false;
#override
void initState() {
super.initState();
scrollController =ScrollController()..addListener(() {
if (scrollController.position.pixels == scrollController.position.maxScrollExtent) {
reachedAtEnd = true;
setState(() {
});
}
},);
}
#override
Widget build(BuildContext context) {
return SingleChildScrollView(
physics: NeverScrollableScrollPhysics(),
child: Column(
children: [
SizedBox(
height: 700,
child: ListView.builder(
controller: scrollController,
itemCount: 20,
itemBuilder: (context, index) {
return const ListTile(
leading: Icon(
Icons.icecream,
color: Colors.amber,
),
title: Text("Ice Cream"),
);
},
),
),
SizedBox(
height: 300,
child: AbsorbPointer(
absorbing: !reachedAtEnd,
child: ListView.builder(
itemCount: 20,
itemBuilder: (context, index) {
return const ListTile(
leading: Icon(
Icons.cake,
color: Colors.red,
),
title: Text("Cake"),
);
},
),
),
),
],
),
);
}
}
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
// this variable determnines whether the back-to-top button is shown or not
bool _showBackToTopButton = false;
// scroll controller
late ScrollController _scrollController;
#override
void initState() {
_scrollController = ScrollController()
..addListener(() {
setState(() {
print(_scrollController.offset);
if (_scrollController.offset >= 400) {
_showBackToTopButton = true;
// _scrollToTop();
// show the back-to-top button
} else {
_showBackToTopButton = false; // hide the back-to-top button
}
});
});
super.initState();
}
#override
void dispose() {
_scrollController.dispose(); // dispose the controller
super.dispose();
}
// This function is triggered when the user presses the back-to-top button
void _scrollToTop() {
_scrollController.animateTo(0,
duration: const Duration(seconds: 3), curve: Curves.linear);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('com'),
),
body: ListView.builder(
controller: _scrollController,
itemCount: 40,
itemBuilder: (context, index) {
print(index);
if (index == 39) {
_scrollToTop();
}
return const ListTile(
leading: Icon(
Icons.icecream,
color: Colors.amber,
),
title: Text(' Ice Cream'),
);
},
),
);
}
}

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, using FutureBuilder within SliverFillRemaining

I am building a FutureBuilder with a Listview within a SliverFillRemaining. And I think since Sliver is already within a CustomScrollView the scroll function doesn't work properly. Once it scrolls down it doesn't scroll back up.
Below is the code.
#override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
slivers: [
SliverAppBar(
expandedHeight: 200.0,
floating: false,
//pinned: false,
flexibleSpace: FlexibleSpaceBar(
background: Image.network("https://i.imgur.com/p3CfZBS.png",
fit: BoxFit.cover),
),
),
SliverFillRemaining(
child: Container(
child: FutureBuilder(
future: _getData(),
builder: (context, snapshot) {
if (snapshot.data == null) {
return Center(child: CircularProgressIndicator());
} else {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
return ListView(
shrinkWrap: true,
children: [
buildlink(
imageName: snapshot.data[index].image,
page: snapshot.data[index].title)
],
);
},
);
}
},
),
),
),
],
),
);
}
}
most likely the 2nd listView is superfluous and probably you want to use physics: NeverScrollableScrollPhysics() with list view, if you use CustomScrollView. Check NestedScrollView may be it would work better in this situation.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
body: SafeArea(
child: MyHomePage(),
),
),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
slivers: [
SliverAppBar(
expandedHeight: 200.0,
floating: false,
pinned: false,
flexibleSpace: FlexibleSpaceBar(
background: Image.network("https://i.imgur.com/p3CfZBS.png",
fit: BoxFit.cover),
),
),
SliverFillRemaining(
child: Container(
child: FutureBuilder(
future: _getData(),
builder: (context, snapshot) {
if (snapshot.data == null) {
return Center(child: CircularProgressIndicator());
} else {
return ListView.builder(
physics: NeverScrollableScrollPhysics(),
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
return buildlink(
imageName: snapshot.data[index].image,
page: snapshot.data[index].title,
);
},
);
}
},
),
),
),
],
),
);
}
Future<List<LinkData>> _getData() async {
await Future.delayed(Duration(seconds: 1));
return [
LinkData(image: "https://i.imgur.com/p3CfZBS.png", title: 'First'),
LinkData(image: "https://i.imgur.com/p3CfZBS.png", title: 'Second'),
LinkData(image: "https://i.imgur.com/p3CfZBS.png", title: 'Third'),
];
}
Widget buildlink({String imageName, String page}) {
return Card(
child: Container(
child: Text(page),
height: 400,
),
);
}
}
class LinkData {
const LinkData({
this.image,
this.title,
});
final String image;
final String title;
}

Set state from FutureBuilder in Flutter

I've been trying to set a property based on a response from a FutureBuilder but can't seem to get it working. How can I set _activityLength after the future resolves without setting during build?
FutureBuilder<QuerySnapshot>(
future: _future,
builder: (BuildContext context,
AsyncSnapshot<QuerySnapshot> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
return Text('Press button to start');
case ConnectionState.waiting:
return Center(
child: CircularProgressIndicator(),
);
default:
if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
final documents = snapshot.data.documents;
_activityLength = documents.length;
return Expanded(
child: ListView.separated(
shrinkWrap: true,
separatorBuilder: (context, index) => Divider(
color: Colors.black,
height: 0,
),
itemCount: documents.length,
itemBuilder: (context, index) => _activityTile(
documents[index],
),
),
);
}
}
},
)
The FutureBuilde is in a Column widget in the body of the Scaffold and the value that I need to set is in the _itemsHeaderText Something like this:
body:
...
child: Column(
children: <Widget>[
Container(
width: double.infinity,
decoration: BoxDecoration(
border: Border(
bottom:
BorderSide(color: Colors.grey, width: 1.0),
),
),
child: Padding(
padding: const EdgeInsets.only(
left: 15.0,
right: 15.0,
top: 10.0,
bottom: 10.0),
child: _itemsHeaderText(),
),
),
_itemsBody(),
],
),
You can copy paste run full demo code below
You can use _future.then((value) in initState() and do job in addPostFrameCallback like setState
And after future resolves, you can get value of _future, you can do further processing if need
In demo code, I get value length and display on screen
You can see working demo, data length change from 0 to 9
code snippet
#override
void initState() {
super.initState();
_future = _getUsers();
_future.then((value) {
print("data length ${value.length}");
WidgetsBinding.instance.addPostFrameCallback((_) {
print("other job");
setState(() {
_dataLength = value.length;
});
});
});
}
working demo
output
I/flutter (18414): data length 9
I/flutter (18414): other job
full code
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
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: CategoryTab(title: 'Flutter Demo Home Page'),
);
}
}
class CategoryTab extends StatefulWidget {
CategoryTab({Key key, this.title}) : super(key: key);
final String title;
#override
_CategoryTabState createState() => _CategoryTabState();
}
class _CategoryTabState extends State<CategoryTab> {
Future<List<CategoryList>> _future;
int _dataLength = 0;
Future<List<CategoryList>> _getUsers() async {
var data = await http
.get("https://appiconmakers.com/demoMusicPlayer/API/getallcategories");
var jsonData = json.decode(data.body);
List<CategoryList> cat = [];
for (var u in jsonData) {
CategoryList categoryList = CategoryList(
u["category_id"],
u["category_name"],
u["parent_category_id"],
u["category_status"],
u["created_date"]);
cat.add(categoryList);
}
return cat;
}
#override
void initState() {
super.initState();
_future = _getUsers();
_future.then((value) {
print("data length ${value.length}");
WidgetsBinding.instance.addPostFrameCallback((_) {
print("other job");
setState(() {
_dataLength = value.length;
});
});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
"Categories",
style: TextStyle(color: Colors.black),
),
backgroundColor: Colors.white,
),
body: Column(
children: [
Text("data length $_dataLength"),
Expanded(
child: Container(
child: FutureBuilder(
future: _future,
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.data == null) {
return Container(child: Center(child: Text("Loading...")));
} else {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
leading: CircleAvatar(),
title: Text(
"${snapshot.data[index].categoryName}",
// subtitle: Text(snapshot.data[index].categoryId
),
);
},
);
}
},
),
),
),
],
),
);
}
}
class CategoryList {
String categoryId;
String categoryName;
String parentCategoryId;
String categoryStatus;
String createdDate;
CategoryList(this.categoryId, this.categoryName, this.parentCategoryId,
this.categoryStatus, this.createdDate);
}
There are a few workarounds to your question.
You could hoist the futureBuilder up the widget tree, instead of setting state the state will be reset once ConnectionState.done.
You could place the future in a function that is called on init state, then the result of the future you set state on it.

Unable to scroll on widget even after wrapping column() with SingleChildScrollView()

Here is the root widget . The widget has a child BuyerPostList() which is a ListView type of widget. I removing the SingleChildScrollView() gives a render exception .After adding it the error no longer appears but the page is still not scrollable.
class PostsPage extends StatelessWidget {
final AuthService _auth = AuthService();
#override
Widget build(BuildContext context) {
return StreamProvider<List<BuyerPost>>.value(
value: BuyerDatabaseService().buyerPosts,
child:Scaffold(
backgroundColor: Colors.white,
appBar: header(context,isAppTitle: true),
body:Container(
child: SingleChildScrollView(
child: Column(
children: <Widget>[
BuyerPostList(),
SizedBox(height: 100,),
],
),
),
),
floatingActionButton: FloatingActionButton.extended(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => NewPost()),
);
},
label: Text(
'New',
style: TextStyle(fontWeight:FontWeight.w900,color:Color.fromRGBO(0, 0, 0, 0.4),),
),
icon: Icon(Icons.add,color:Color.fromRGBO(0, 0, 0, 0.4),),
backgroundColor:Colors.white,
),
),
);
}
}
Here is the List View BuyerPostList widget()
class BuyerPostList extends StatefulWidget {
#override
_BuyerPostListState createState() => _BuyerPostListState();
}
class _BuyerPostListState extends State<BuyerPostList> {
#override
Widget build(BuildContext context) {
final posts = Provider.of<List<BuyerPost>>(context) ?? [];
return ListView.builder(
shrinkWrap: true,
itemCount: posts.length,
itemBuilder: (context, index) {
return BuyerPostTile(post: posts[index]);
},
);
}
}
I hope i've been clear enough by my explanation. How will i make it scrollable?.
Thanks in advance.
Add physics: NeverScrollableScrollPhysics(), inside ListView.builder(
Code:
#override
Widget build(BuildContext context) {
final posts = Provider.of<List<BuyerPost>>(context) ?? [];
return ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: posts.length,
itemBuilder: (context, index) {
return BuyerPostTile(post: posts[index]);
},
);
}