Custom ListView.builder -Flutter - flutter

I would like to do Custom ListView builder as U see below, but I have a problem with index in Widget where I use it. "Missing parameter type of index", could U tell me how to handle with it?
And how else could I make a Custom Widget that I could use in several places.
Any help will be greatly appreciated.
class BuilderNews extends StatelessWidget {
final double height;
final ItemBuilder itemBuilder;
final ScrollPhysics physics;
final int itemcount;
BuilderNews({
required this.height,
required this.itemBuilder,
required this.physics,
required this.itemcount});
ApiService client = ApiService();
late final Article article;
#override
Widget build(BuildContext context) {
return Container(
height: height,
child: FutureBuilder(
future: client.getArticle(),
builder:
(BuildContext context, AsyncSnapshot<List<Article>> snapshot) {
if (snapshot.hasData) {
var article = snapshot.data!;
return ListView.builder(
// scrollDirection: scrollDirection,
physics: physics,
shrinkWrap: true,
itemCount: itemcount,
itemBuilder: itemBuilder);
}
return const Center(
child: CircularProgressIndicator(),
);
}));
}
}

Define it like this, not ItemBuilder:
Widget Function(BuildContext, int) test = (context,index)=> Text('testing ItemBuilder');
.
.
.
.
ListView.builder(
physics: physics,
shrinkWrap: true,
itemCount: itemcount,
itemBuilder:test

Would you change itemBuilder's definition type from 'ItemBuilder' to 'IndexedWidgetBuilder'?
Because at the flutter 'scroll_view.dart' file, itemBuilder parameter type at ListView is 'IndexedWidgetBuilder'.
class BuilderNews extends StatelessWidget {
final double height;
final IndexedWidgetBuilder itemBuilder;
final ScrollPhysics physics;
final int itemcount;
...
<'scroll_view.dart' File>
ListView.builder({
Key key,
Axis scrollDirection = Axis.vertical,
bool reverse = false,
ScrollController controller,
bool primary,
ScrollPhysics physics,
bool shrinkWrap = false,
EdgeInsetsGeometry padding,
this.itemExtent,
#required IndexedWidgetBuilder itemBuilder,
...

Related

Dynamic Row height in GridView.builder (Flutter)

I'm trying to use a GridView.builder with dynamic height depending on the largest item in each row. A Wrap is not ok for this, because it renders all items at once. the builder is only rendering the visible items. I won't calculate a childAspectRatio manually for each row.
Any ideas?
I've made a WrapBuilder which sort of like a Wrap but uses a builder. The caveat though is that you need to know the width of the items beforehand. If that's okay you can try using this class:
import 'dart:math';
import 'package:flutter/cupertino.dart';
typedef ValueWidgetBuilder<T> = Widget Function(T value);
class WrapBuilder extends StatelessWidget {
final double itemWidth;
final List items;
final ValueWidgetBuilder itemBuilder;
const WrapBuilder(
{Key? key,
required this.itemWidth,
required this.items,
required this.itemBuilder})
: super(key: key);
#override
Widget build(BuildContext context) {
return LayoutBuilder(builder: (context, constraints) {
var itemsPerRow = max(1, constraints.maxWidth ~/ itemWidth);
return ListView.builder(
shrinkWrap: true,
controller: ScrollController(),
itemCount: (items.length / itemsPerRow).ceil(),
itemBuilder: (BuildContext context, int index) {
var rowItems = items.sublist(itemsPerRow * index,
min(itemsPerRow * (index + 1), items.length));
return Row(children: [
for (final item in rowItems)
SizedBox(
width: itemWidth,
child: itemBuilder(item))
]);
},
);
});
}
}
You might need to tweak it for your use case. In my case I have a list that is some data and the itemBuilder takes one of this data as parameter.
you can pass height as variable in list and then set height for the row from list

Flutter: Jump to specific item by item data in ListView.builder

It's possible to jump to specific item by item data in ListView?
class Test extends StatelessWidget {
Test({Key? key}) : super(key: key);
final _list = <String>[
"INFWARS_CH01_EP01",
"INFWARS_CH01_EP02",
"INFWARS_CH01_EP03",
"INFWARS_CH01_EP04",
"INFWARS_CH01_EP05",
];
void _scrollToItem() {
final specificItem = "INFWARS_CH01_EP04";
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder(
itemCount: _list.length,
itemBuilder: (context, index) {
final data = _list[index];
return Text(data);
},
),
floatingActionButton: FloatingActionButton(
onPressed: () => _scrollToItem(),
),
);
}
}
as you can see, I want to jump to specific item in ListView by specific data "INFWARS_CH01_EP04" using _scrollToItem function, not by index or by position.
So the item ListView for INFWARS_CH01_EP04 will be in the top (scrolled). For now in the top is INFWARS_CH01_EP01.
It's possible to do it?
I fix it using this package: https://pub.dev/packages/scroll_to_index
So you can scroll / jump to specific item by index / by item data in ListView.
class Test extends StatelessWidget {
Test({Key? key}) : super(key: key);
AutoScrollController _scrollController = AutoScrollController();
final _list = <String>[
"INFWARS_CH01_EP01",
"INFWARS_CH01_EP02",
"INFWARS_CH01_EP03",
"INFWARS_CH01_EP04",
];
void _scrollToItem() async {
final specificItem = "INFWARS_CH01_EP04";
final index = _list.indexOf(specificItem);
await _scrollController.scrollToIndex(
index,
preferPosition: AutoScrollPosition.begin,
);
await _scrollController.highlight(index);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder(
controller: _scrollController,
itemCount: _list.length,
itemBuilder: (context, index) {
final data = _list[index];
return AutoScrollTag(
key: ValueKey(index),
controller: _scrollController,
index: index,
child: Text(data),
);
},
),
floatingActionButton: FloatingActionButton(
onPressed: () => _scrollToItem(),
),
);
}
}
To scroll to a specific item you can:
Find the specific item using the indexOf() method:
Use the scrollable_positioned_list package to scroll to that item.
Here is a complete working example:
class Test extends StatelessWidget {
Test({Key? key}) : super(key: key);
ItemScrollController _scrollController = ItemScrollController();
final _list = <String>[
"INFWARS_CH01_EP01",
"INFWARS_CH01_EP02",
"INFWARS_CH01_EP03",
"INFWARS_CH01_EP04",
];
void _scrollToItem() {
final specificItem = "INFWARS_CH01_EP04";
_scrollController.jumpTo(index: _list.indexOf(specificItem));
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: ScrollablePositionedList.builder(
itemScrollController: _scrollController,
itemCount: _list.length,
itemBuilder: (context, index) {
final data = _list[index];
return Text(data);
},
),
floatingActionButton: FloatingActionButton(
onPressed: () => _scrollToItem(),
),
);
}
}
See also: flutter ListView scroll to index not available
You can use the flutter_scrollview_observer lib to implement your desired functionality without invasivity
Create and use instance of ScrollController normally.
ScrollController scrollController = ScrollController();
ListView _buildListView() {
return ListView.separated(
controller: scrollController,
...
);
}
Create an instance of ListObserverController pass it to ListViewObserver
ListObserverController observerController = ListObserverController(controller: scrollController);
ListViewObserver(
controller: observerController,
child: _buildListView(),
...
)
Now you can scroll to the specified index position
// Find the specific item index.
final targetIndex = _list.indexOf(specificItem);
// Jump to the specified index position without animation.
observerController.jumpTo(index: targetIndex)
// Jump to the specified index position with animation.
observerController.animateTo(
index: targetIndex,
duration: const Duration(milliseconds: 250),
curve: Curves.ease,
);

Flutter web ignore resize

I would like to make my web app does not resize/responsive when the screen become smaller. For example when i decrease my browser size, instead of its adapting to the width and height, i want the web app to ignore it and user can just scroll up, down, left and right to view the web.
I suggest you to use a LayoutBuilder and eventually add a SingleChildScrollView when the size becomes lower than your app expects.
This MinSize widget accomplishes it.
/// Starts scrolling [child] vertically and horizontally when the widget sizes
/// reaches below [minWidth] or [minHeight]
class MinSize extends StatefulWidget {
const MinSize({
Key? key,
this.minWidth,
this.minHeight,
required this.child,
}) : super(key: key);
final Widget child;
final double? minWidth;
final double? minHeight;
#override
State<MinSize> createState() => _MinSizeState();
}
class _MinSizeState extends State<MinSize> {
late final _verticalController = ScrollController();
late final _horizontalController = ScrollController();
#override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
final shouldScrollVertical = widget.minHeight != null &&
constraints.maxHeight <= widget.minHeight!;
final contentHeight =
shouldScrollVertical ? widget.minHeight : constraints.maxHeight;
final verticalPhysics = shouldScrollVertical
? const AlwaysScrollableScrollPhysics()
: const NeverScrollableScrollPhysics();
final shouldScrollHorizontal =
widget.minWidth != null && constraints.maxWidth <= widget.minWidth!;
final contentWidth =
shouldScrollHorizontal ? widget.minWidth : constraints.maxWidth;
final horizontalPhysics = shouldScrollHorizontal
? const AlwaysScrollableScrollPhysics()
: const NeverScrollableScrollPhysics();
return Scrollbar(
controller: _verticalController,
thumbVisibility: shouldScrollVertical,
child: SingleChildScrollView(
controller: _verticalController,
scrollDirection: Axis.vertical,
physics: verticalPhysics,
child: Scrollbar(
interactive: true,
controller: _horizontalController,
thumbVisibility: shouldScrollHorizontal,
child: SingleChildScrollView(
controller: _horizontalController,
scrollDirection: Axis.horizontal,
physics: horizontalPhysics,
child: UnconstrainedBox(
child: SizedBox(
height: contentHeight,
width: contentWidth,
child: widget.child,
),
),
),
),
),
);
},
);
}
}
Alternatively, try the InteractiveViewer to freely move the content in the app window.
Use a SizedBox with a fixed height/width property

How can I automatically add widgets to the body of my scaffold?

I'm trying to have the body of my scaffold return list Tiles that are built automatically, much like posts on a social media app. However, it only returns and empty container, with only its background colour.
Widget _buildListingWidgets(List<Widget> listing) {
return ListView.builder(
itemBuilder: (BuildContext context, int index) => listing[index],
itemCount: listing.length,
);
}
#override
Widget build(BuildContext context) {
final listing = <Listing>[];
for (var i = 0; i < _listingNames.length; i++) {
listing.add(Listing(
describe: _describe[i],
building: _building[i],
location: _location[i],
availability: _availability[i],
));
}
final listView = Container(
color: Colors.black,
padding: EdgeInsets.symmetric(horizontal: 8.0),
child: _buildListingWidgets(listing),
);
...
return Scaffold(
appBar: appBar,
body: listView,
...
);
Keep you code as it now, and modify the ListViewBuilder to look like this:
Widget _buildListingWidgets(List<Widget> listing) {
return ListView.builder(
itemCount: listing.length,
itemBuilder: (BuildContext context, int index) {
return Container(child:
Text(listing[index].describe),
);
}
);
}
It should work.
You seem to have overly complicated how to build your ListView, without using it's inherent functionality. You can do it this way:
class Issue66841743 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
color: Colors.black,
padding: EdgeInsets.symmetric(horizontal: 8.0),
child: MyList(listingNames: listing,),
);
}
}
class MyList extends StatelessWidget {
final List listingNames;
const MyList({Key key, this.listingNames}) : super(key: key);
#override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: listingNames.length,
itemBuilder: (context, index) {
return Listing(
describe: _describe[i],
building: _building[i],
location: _location[i],
availability: _availability[i],
);
}
);
}
}
Have in mind that you did not provide us with the other Lists, _describe, _building, _location and _availability. These also signal me that there are further issues in your code. As you very well could have a class with all the properties pertaining to a certain listing.

Flutter/Dart - Get index number of PageView.Builder for use in a Text Widget?

I've got a PageView.builder within a StatelessWidget. I need to get the current index number of the currently viewed page to appear in a text widget in my build.
Was hoping I could simply use currentIndex.toString() as a variable in the text widget but Android Studio underlines it in red and warns me of undefined name currentIndex. How can I get the correct variable?
class StageBuilder extends StatelessWidget {
final List<SpeakContent> speakcrafts;
StageBuilder(this.speakcrafts);
final PageController controller = PageController(initialPage: 0);
#override
Widget build(context) {
return PageView.builder(
controller: controller,
itemCount: speakcrafts.length,
itemBuilder: (context, int currentIndex) {
return createViewItem(speakcrafts[currentIndex], context);
},
);
}
Widget createViewItem(SpeakContent speakcraft, BuildContext context) {
return Container(
child: Text(currentIndex.toString()),
)
}
}
You need to pass the currentIndex into your createViewItem
class StageBuilder extends StatelessWidget {
final List<SpeakContent> speakcrafts;
StageBuilder(this.speakcrafts);
final PageController controller = PageController(initialPage: 0);
#override
Widget build(context) {
return PageView.builder(
controller: controller,
itemCount: speakcrafts.length,
itemBuilder: (context, int currentIndex) {
return createViewItem(speakcrafts[currentIndex], context, currentIndex);
},
);
}
Widget createViewItem(SpeakContent speakcraft, BuildContext context, int currentIndex) {
return Container(
child: Text(currentIndex.toString()),
);
}
}