【问题标题】:How do I reuse listview in tabs?如何在选项卡中重用列表视图?
【发布时间】:2019-08-19 03:26:00
【问题描述】:

我想在具有两个选项卡的更扁平布局中重用 ListView。例如,我想用它来显示旧约中的所有书籍和新约中的书籍,即使用相同的 ListView 在不同的选项卡上显示两个列表。我该如何做到这一点? 以下是我到目前为止提出的代码。我正在考虑使用选项卡控制器来访问当前的索引并使用它来显示正确的列表。但是,我无法做到这一点,而且我似乎无法想出这样做的逻辑。谢谢。

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,
    );
  }
}

【问题讨论】:

    标签: listview dart flutter tabs


    【解决方案1】:

    如果我理解正确,您想重用相同的 Listview 来显示书籍列表(一个选项卡中的旧约和另一个选项卡中的新约)。 我建议您创建一个仅包含 Listview.builder 和 ListTile 模型的小部件,它将书籍列表作为构造函数的参数。

    从 ListTab 中分离 ListView 小部件后,新的小部件类将如下所示:

    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: () {},
                  ),
                ),
              );
            },
          ),
        );
      }
    }

    您的 ListTab 小部件将如下所示:

    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),
        );
      }
    }

    通过这种方式,您可以在任何您想要的选项卡中重复使用 BookList 小部件。

    【讨论】:

    • 是的,您正确理解了我,谢谢。如果我可能会问,这两个小部件是否放在一个文件中?
    • 我会将它们保存在不同的文件中。通常我每个小部件做 1 个文件。
    猜你喜欢
    • 1970-01-01
    • 2012-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多