I want to add my ListView.seperated
into Column, so that I can add CircularProgressIndicator below this ListvView when loading more items. I have used advices from How to add a ListView to a Column in Flutter? so that I made structure Column -> Expanded -> ListVie, but I got errors and list cannot be loaded:
======== Exception caught by rendering library =====================================================
RenderBox was not laid out: RenderRepaintBoundary#e8fad NEEDS-LAYOUT NEEDS-PAINT
'package:flutter/src/rendering/box.dart':
Failed assertion: line 1929 pos 12: 'hasSize'
The relevant error-causing widget was:
The relevant error-causing widget was:
Column file:///C://lib/ui/pages/home/page/HomePage.dart:125:16
When the exception was thrown, this was the stack:
#0 RenderFlex.performLayout.<anonymous closure> (package:flutter/src/rendering/flex.dart:926:9)
#1 RenderFlex.performLayout (package:flutter/src/rendering/flex.dart:929:6)
#2 RenderObject.layout (package:flutter/src/rendering/object.dart:1781:7)
#3 ChildLayoutHelper.layoutChild (package:flutter/src/rendering/layout_helper.dart:54:11)
#4 RenderFlex._computeSizes (package:flutter/src/rendering/flex.dart:829:43)
Column file:///C:/.../.../lib/ui/pages/home/page/HomePage.dart:125:16
Could you tell me what have I done wrong? This AdvertisementTile
builds new widgets, but it is built onto another column. Maybe this is wrong?
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:.../ui/pages/home/page/AdvertisementCard.dart';
import 'package:.../ui/pages/home/page/model/AdvertisementList.dart';
import '../../SizedBox.dart';
import 'AdvertisementProdRepository.dart';
import 'BottomAppBar.dart';
import 'FAB.dart';
import 'model/AdvertisementList.dart';
class HomePage extends StatefulWidget {
final String jwt;
const HomePage(this.jwt);
@override
_HomePage createState() => _HomePage();
factory HomePage.fromBase64(String jwt) => HomePage(jwt);
}
class _HomePage extends State<HomePage> {
late final String jwt;
late Future<AdvertisementList> _listOfItems;
final searchTextController = TextEditingController();
@override
void initState() {
super.initState();
jwt = widget.jwt;
_listOfItems = AdvertisementProdRepository.fetchAdvertisements(1);
}
@override
Widget build(BuildContext context) => Scaffold(
body: Scaffold(
backgroundColor: const Color(0xFEF9F9FC),
floatingActionButtonLocation:
FloatingActionButtonLocation.centerDocked,
floatingActionButton: buildFAB(),
bottomNavigationBar: BuildBottomAppBar(),
body: Container(
padding: EdgeInsets.only(left: 25.0, right: 25, top: 25),
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: Column(
children: [
TextFormField(
controller: searchTextController,
decoration: InputDecoration(
prefixIcon: Icon(Icons.search),
border: OutlineInputBorder(),
hintText: 'Szukaj',
fillColor: Color(0xffeeeeee),
filled: true),
),
buildSizedBox(20.0),
Padding(
padding: const EdgeInsets.only(left: 4),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(
'Najnowsze ogłoszenia',
style: TextStyle(
fontSize: 20, fontWeight: FontWeight.bold),
textAlign: TextAlign.left,
),
],
),
),
buildSizedBox(10.0),
FutureBuilder<AdvertisementList>(
future: _listOfItems,
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(child: CircularProgressIndicator());
} else {
return AdvertisementTile(advertisements: snapshot.data!);
}
},
),
],
),
),
),
);
}
class AdvertisementTile extends StatefulWidget {
final AdvertisementList advertisements;
AdvertisementTile({Key? key, required this.advertisements}) : super(key: key);
@override
State<StatefulWidget> createState() => AdvertisementTileState();
}
class AdvertisementTileState extends State<AdvertisementTile> {
AdvertisementLoadMoreStatus loadMoreStatus =
AdvertisementLoadMoreStatus.STABLE;
final ScrollController scrollController = new ScrollController();
late List<Advertisement> advertisements;
late int currentPageNumber;
bool _loading = false;
@override
void initState() {
advertisements = widget.advertisements.items;
currentPageNumber = widget.advertisements.pageNumber;
super.initState();
}
@override
void dispose() {
scrollController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return NotificationListener(
onNotification: onNotification,
child: Column(
children: <Widget>[
Expanded(
child: ListView.separated(
padding: EdgeInsets.zero,
scrollDirection: Axis.vertical,
controller: scrollController,
itemCount: advertisements.length,
physics: const AlwaysScrollableScrollPhysics(),
itemBuilder: (_, index) {
return AdvertisementCard(data: advertisements[index]);
},
separatorBuilder: (BuildContext context, int index) {
return SizedBox(
height: 10,
);
},
),
),
],
),
);
}
/*child: Padding(
padding: const EdgeInsets.only(bottom: 28.0),*/
bool onNotification(ScrollNotification notification) {
if (notification is ScrollUpdateNotification) {
if (scrollController.position.maxScrollExtent > scrollController.offset &&
scrollController.position.maxScrollExtent - scrollController.offset <=
50) {
if (loadMoreStatus == AdvertisementLoadMoreStatus.STABLE) {
loadMoreStatus = AdvertisementLoadMoreStatus.LOADING;
_loading = true;
AdvertisementProdRepository.fetchAdvertisements(currentPageNumber + 1)
.then((advertisementObject) {
currentPageNumber = advertisementObject.pageNumber;
loadMoreStatus = AdvertisementLoadMoreStatus.STABLE;
setState(() => advertisements.addAll(advertisementObject.items));
_loading = false;
});
}
}
}
return true;
}
}
enum AdvertisementLoadMoreStatus { LOADING, STABLE }