I am trying to build a view/route that will list items fetched from a REST source. I want to show a notification item below the list while the data is being fetched. But my ListView builder is constructed around the fetched data's structure, so I figured just have a ListTile fit some appropriate UX elements below the generated list inside a Column - which was kinda working great - or so I thought - until the list grows to fill the screen causing RenderFlex overflowed error. Wrapping the ListView builder in Expanded fixed that but moved the indicator to the bottom of the screen.
In trying to fix it I seem to have broken more of the plumbing and the boolean variable that should control the idicator widget; isLoading: stockSet.isBusyLoading
doesn't seem to update.
At the moment if I hardcode it as `` it does sit in the appropraite position but I am back with the RenderFlex overflow.
Once all of this is working I'll be wanting to automatically load items untill the screen is full - not sure where I'll be triggering that from yet.
class MyStockSet extends StatefulWidget {
const MyStockSet({super.key});
static const indexStr = 'stocks';
static const labelStr = 'Properties';
@override
State<MyStockSet> createState() => _MyStockSetState();
}
class _MyStockSetState extends State<MyStockSet> {
@override
Widget build(BuildContext context) {
const String imagePath = 'assets/images/${MyStockSet.indexStr}.png';
var assetImage = const AssetImage(imagePath);
//var stockSet = context.watch<StockSet>(); <- didn't work either
var stockSet = Provider.of<StockSet>(context,listen: false);
return Scaffold(
appBar: AppBar(
title: Row(
children: [
AscHero(
assetImage: assetImage,
tag: MyStockSet.indexStr,
title: MyStockSet.labelStr,
radius: 32,
),
const SizedBox(width: 12),
const Text(MyStockSet.labelStr),
],
),
actions: [
IconButton(
onPressed: () {
var stockSet = context.read<StockSet>();
int newNr = stockSet.stocks.length 1;
Stock tmpstock = Stock(
id: newNr,
title: 'test$newNr',
thumbUrl: 'url',
description: 'desc');
stockSet.add(tmpstock);
},
icon: const Icon(Icons.add),
),
IconButton(
onPressed: () {
developer.log('btn before isBusyLoading ${stockSet.isBusyLoading}');
stockSet.fetch();
developer.log('after btn isBusyLoading ${stockSet.isBusyLoading}');
},
icon: const Icon(Icons.handshake),
),
],
),
body: Column(
children: [
Row(
// these will be filters, order toggle etc.
children: [
ElevatedButton(
onPressed: () => developer.log('Btn pressed.'),
child: Text('Btn')),
],
),
Expanded(
child: Column(children: [
_StockListView(),
LoadingStockListItemNotif(
isLoading: true,
),
]),
),
],
),
);
}
}
class _StockListView extends StatefulWidget {
@override
State<_StockListView> createState() => _StockListViewState();
}
class _StockListViewState extends State<_StockListView> {
@override
void didChangeDependencies() {
super.didChangeDependencies();
developer.log('_StockListView didChangeDependencies()');
// developer.log('scroll pos ${_scrollController.position}');
}
@override
Widget build(BuildContext context) {
var stockSet = context.watch<StockSet>();
return ListView.builder(
// controller: _scrollController,
shrinkWrap: true,
itemCount: stockSet.stocks.length,
itemBuilder: (context, index) => InkWell(
child: StockListItem(
stock: stockSet.stocks[index],
),
onTap: () => Navigator.pushNamed(
context,
'/stocks/stock',
arguments: ScreenArguments(stockSet.stocks[index]),
),
),
);
}
void _scrollListener() {
developer.log('_scrollListener');
}
}
and
class StockSet extends ChangeNotifier {
final List<Stock> _stocks = [];
late bool isBusyLoading = false;
List<Stock> get stocks => _stocks;
void add(Stock stock) {
_stocks.add(stock);
developer.log('added stock :${stock.title}');
notifyListeners();
}
void remove(Stock stock) {
_stocks.remove(stock);
notifyListeners();
}
Future<void> fetch() async {
developer.log('fetch() iL T');
isBusyLoading = true;
notifyListeners();
Stock tmpStock = await _fetchAStock();
developer.log('fetch() iL F');
isBusyLoading = false;
notifyListeners();
add(tmpStock);
}
Future<Stock> _fetchAStock() async {
developer.log('fetch stock ');
final response = await http.get(
Uri.https(
//...
),
);
developer.log('response.statusCode:${response.statusCode}');
if (response.statusCode == 200) {
final Map<String, dynamic> map = json.decode(response.body);
return Stock(
id: map['id'] as int,
title: map['title'] as String,
description: map['description'] as String,
thumbUrl: map['thumbUrl'] as String,
);
}
throw Exception('error fetching stocks:');
}
}
Apologies for the convoluted question.
CodePudding user response:
Add mainAxisSize : MainAxisSize.min
for the column inside the expanded widget. The expanded doesn't have any bounds and that's why it throws an error. You can wrap the column with a SingleChildScrollView if you have long content to display
CodePudding user response:
This worked for me!
Just set the shrinkWrap
attribute to true