How do I reuse listview in tabs?
If I understood correctly, you want to reuse the same Listview for displaying a list of books (old testament in one tab and new testament in the other one). What I suggest you to do is to create a widget that contains only the Listview.builder, and the ListTile model, that would take the list of books as an argument for the constructor.
After separating the ListView widget from the ListTab, the new widget class would look like this:
import 'package:flutter/material.dart';
import 'package:navigation_drawer/model/book.dart';
class BookList extends StatelessWidget {
List<Book> _books;
BookList(this._books);
@override
Widget build(BuildContext context) {
return Container(
child: ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: _books.length,
itemBuilder: (BuildContext context, int index) {
return Card(
elevation: 8.0,
margin: new EdgeInsets.symmetric(horizontal: 10.0, vertical: 6.0),
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: new BorderRadius.circular(5.0),
),
child: ListTile(
contentPadding: EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0),
leading: Container(
padding: EdgeInsets.only(right: 12.0),
decoration: new BoxDecoration(
border: new Border(right: new BorderSide(width: 1.0, color: Colors.blue))),
child: Icon(Icons.book, color: Colors.grey),
),
title: Text(
_books[index].title,
style: TextStyle(color: Colors.black, fontWeight: FontWeight.bold),
),
subtitle: Row(
children: <Widget>[
Expanded(
flex: 4,
child: Padding(
padding: EdgeInsets.only(left: 10.0),
child:
Text(_books[index].testament, style: TextStyle(color: Colors.black))),
)
],
),
trailing: Icon(Icons.keyboard_arrow_right, color: Colors.black, size: 30.0),
onTap: () {},
),
),
);
},
),
);
}
}
And your ListTab widget would look like this:
class ListTab extends StatefulWidget {
ListTab({Key key}) : super(key: key);
@override
State<StatefulWidget> createState() => ListTabState();
}
class ListTabState extends State<ListTab> {
List books;
@override
void initState() {
books = getOldTestamentBooks();
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: BookList(books),
);
}
}
In this way, you can reuse the BookList widget in whichever tab you want.
Comments
-
funnybunny over 1 year
I would like to reuse a ListView in my flatter layout with two tabs. For example, I want to use it to display all books in the old testament and books in the new testament i.e., use the same ListView to display the two list on the different tabs. How do I accomplish this? The following is the code I have come up with so far. I was thinking of using the tab controller to access the index of the current and use it to display the correct list. However, I am unable to do this and I can't seem to come up with the logic to do so. Thank you.
import 'package:flutter/material.dart'; import 'package:navigation_drawer/tabs/old_testament.dart'; import 'package:navigation_drawer/tabs/new_testament.dart'; import 'package:navigation_drawer/model/book.dart'; void main() { runApp(new MaterialApp( title: "Testament", home: new HomeTab(), )); } class HomeTab extends StatefulWidget { @override State<StatefulWidget> createState() => new TabState(); } // SingleTickerProviderStateMixin is used for animation class TabState extends State<HomeTab> with SingleTickerProviderStateMixin { // Create a tab controller TabController controller; @override void initState() { super.initState(); // Initialize the Tab Controller controller = new TabController(length: 2, vsync: this); } @override void dispose() { // Dispose of the Tab Controller controller.dispose(); super.dispose(); } TabBar getTabBar() { return new TabBar( tabs: <Tab>[ new Tab( // set icon to the tab icon: new Icon(Icons.brightness_2), text: "Old Testament", ), new Tab( icon: new Icon(Icons.brightness_6), text: "New Testament", ), ], // setup the controller controller: controller, ); } TabBarView getTabBarView(var tabs) { return new TabBarView( // Add tabs as widgets children: tabs, // set the controller controller: controller, ); } @override Widget build(BuildContext context) { return new Scaffold( // Appbar appBar: new AppBar( centerTitle: true, // Title title: new Text("Testament"), // Set the background color of the App Bar backgroundColor: Colors.blue, // Set the bottom property of the Appbar to include a Tab Bar bottom: getTabBar() ), // Set the TabBar view as the body of the Scaffold body: getTabBarView(<Widget>[new OldTestament(), new NewTestament()]) ); } } class ListTab extends StatefulWidget { ListTab({Key key}) : super(key: key); @override State<StatefulWidget> createState() => ListTabState(); } class ListTabState extends State<ListTab> { List books; @override void initState() { books = getOldTestamentBooks(); super.initState(); } @override Widget build(BuildContext context) { // create a list tile for books ListTile makeListTile(Book book) => ListTile( contentPadding: EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0), leading: Container( padding: EdgeInsets.only(right: 12.0), decoration: new BoxDecoration( border: new Border( right: new BorderSide( width: 1.0, color: Colors.blue ) ) ), child: Icon( Icons.book, color: Colors.grey ), ), title: Text( book.title, style: TextStyle( color: Colors.black, fontWeight: FontWeight.bold ), ), subtitle: Row( children: <Widget>[ Expanded( flex: 4, child: Padding( padding: EdgeInsets.only(left: 10.0), child: Text( book.testament, style: TextStyle(color: Colors.black) ) ), ) ], ), trailing: Icon( Icons.keyboard_arrow_right, color: Colors.black, size: 30.0 ), onTap: () {}, ); // create a card view for the list tile Card makeCard(Book book) => Card( elevation: 8.0, margin: new EdgeInsets.symmetric(horizontal: 10.0, vertical: 6.0), child: Container( decoration: BoxDecoration( color: Colors.white, borderRadius: new BorderRadius.circular(5.0), ), child: makeListTile(book), ), ); final makeBody = Container( child: ListView.builder( scrollDirection: Axis.vertical, shrinkWrap: true, itemCount: books.length, itemBuilder: (BuildContext context, int index) { return makeCard(books[index]); }, ), ); return Scaffold( backgroundColor: Colors.white, body: makeBody, ); } }
-
funnybunny about 5 yearsYes you understood me correctly and thank you. If I may ask, do the two widgets go on one file?
-
Andrei about 5 yearsI would keep them in different files. Usually I do 1 file per widget.