How do I reuse listview in tabs?

1,843

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.

Share:
1,843
funnybunny
Author by

funnybunny

Still a baby bird stretching its wings.

Updated on December 10, 2022

Comments

  • funnybunny
    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
    funnybunny about 5 years
    Yes you understood me correctly and thank you. If I may ask, do the two widgets go on one file?
  • Andrei
    Andrei about 5 years
    I would keep them in different files. Usually I do 1 file per widget.