Basic page implementation

TabBar + TabBarView implements page switching linkage (similar to Android TabLayout + ViewPage)

  • Go straight to code
List <String>_titles=['the lakers'.'the warriors'.'the bucks'.'the clippers'.'Celtic'.'the spurs'.'76'.'the raptors']; TabController _tabController; Class MyHomePage extends StatefulWidget {MyHomePage({Key Key, this.title}) : super(Key: Key); final String title; / / / omit part of the code class _MyHomePageState extends the State < MyHomePage > with SingleTickerProviderStateMixin {@ override voidinitState() { super.initState(); _tabController = new TabController(length: _titles. Length,vsync: this); } @override Widget build(BuildContext context) {return Scaffold(
      appBar: AppBar(
        leading: Icon(Icons.menu),
        title: buildTabBar(),
        //bottom: buildTabBar(),
      ),
      body: TabBarViewLayout()
    );
  }

  Widget buildTabBar() {
    returnTabBar(// Construct Tab collection tabs: _title.map ((String title){returnTab( text: title, ); }). ToList (), /// omit some code controller: _tabController,); } } // TabBarView Widget class TabBarViewLayout extends StatelessWidget { @override Widget build(BuildContext context) {print("TabBarViewLayout build.......");
    return TabBarView(
      controller: _tabController,
      children: _titles.map((String title){
        returnTabPageView(title); }).toList(), ); }}Copy the code
  • If you code, you can see that TabBar is added to the title property of the AppBar widget, which is displayed in the Title module of the AppBat widget, or to the bottom property of the AppBar widget. Note that TabBar and TabBarView use the same controller for menu switching and sliding state synchronization. The final result is as follows: TabBar is set to title and bottom

Pull-down refresh, pull-up load more refreshIndicators

  • The drop down refresh of the Flutter SDK already provides a RefreshIndicator, so use the RefreshIndicator to wrap the ListView, swipe to listen to the ScrollController, and set the header. More tail loading interface, you can complete a general drop-down refresh, pull up to load more general controls. Start by looking at the RefreshIndicator constructor
Const RefreshIndicator({Key Key, @required this.child, // Wrapper a scrollable widget this.displacement = 40.0, @required this.onRefresh, // Trigger the refresh call method this.color, // indicator color this.backgroundColor, this.notificationPredicate = defaultScrollNotificationPredicate, this.semanticsLabel, this.semanticsValue, })Copy the code
  • RefreshIndicator wraps a scrollable widget, where ListView is used
@override
  Widget build(BuildContext context) {
    returnRefreshIndicator(Child: ListView.builder(/// keep the ListView scrolling in any case, resolve the compatibility issue on the RefreshIndicator. physics: const AlwaysScrollableScrollPhysics(), itemBuilder: (context,index){return_getItem(index); }, itemCount: _getListCount(), /// slide listener controller: _scrollController,), onRefresh: _handleRefresh, color: Theme. Of (context). PrimaryColor, // indicator color); }Copy the code
  • ItemBuilder builds each page of the list item, and itemCount builds the number of pages on that item. First look at the itemCount method
// return the actual number of lists based on the configuration status_getListCount() {/// whether a header is requiredif (widget.isHaveHeader) {
      return (items.length > 0) ? items.length + 2 : items.length + 1;
    } else {
      if (items.length == 0) {
        return 1;
      }
      return(items.length > 0) ? items.length + 1 : items.length; }}Copy the code
  • If a header is needed, use the Widget of Item 0 as the header of the ListView. If the number of lists is greater than 0, because more options are loaded in the header and bottom, add +2 to the total number of list data. If no header is needed, add +2 to the total number of list data when the data fetch is zero. Fixed return number 1 for empty page rendering or error page; If there is data, plus more options for external loading, add +1 to the total list data. Then look at the _getItem() method, which returns the corresponding rendered page.
Render Item _getItem(int index) {if(! widget.isHaveHeader && index == items.length && items.length ! = 0) {return _buildProgressIndicator();
    } else if(widget.isHaveHeader && index == _getListCount()-1 && items.length ! = 0) {return _buildProgressIndicator();
    } else if(widget.isHaveHeader && index == 0 && items.length ! = 0) {return widget.headerView();
    } else if(! Widget.ishaveheader && Items. Length == 0) {/// Render the empty page if the header is not needed and the data is 0if(isLoading){
        return _buildIsLoading();
      }else{
        return_buildEmpty(); }}else if(widget.isHaveHeader && items.length == 0){
      if(isLoading){
        return _buildIsLoading();
      }else{
        return_buildEmpty(); }}else {
      returnwidget.renderItem(index, items[widget.isHaveHeader ? index-1 : index]); }}Copy the code
  • In this method, if the header is not set and the data is not 0, the render loads more pages when index equals the data length (because index starts at 0); If the header page is set and the data is not 0, the render will load more pages when index is equal to the actual render length -1. Next, if the header widget is set and the data is not 0, render the header widget when index = 0; If the header is not set and the data is 0, the Loading page will be rendered if the Loading page is being refreshed, otherwise the empty page or Error page will be rendered. Similarly, if the header is set, the data is 0, and the Loading page is being refreshed, otherwise the Loading page or Error page is rendered. If this is not the case, render the Item normally. If necessary, return the index of the relative position directly. If there is a header index minus one, do not ignore the data with index = 0.

  • It then encapsulates a unified network request method, in which the external request installs a fixed format Map and returns the data to the drop-down refresh drop-down to load more widgets for general purpose.

Future<List> makeHttpRequest(bool isRefresh) async {if (widget.requestApi is Function) {
      Map listObj = new Map<String, dynamic>();
      if(isRefresh){// Pull down refresh listObj = await Widget.requestAPI ({'pageIndex': 0});
      }elseListObj = await Widget.requestAPI ({// pull up load more listObj = await Widget.requestAPI ({'pageIndex': _pageIndex});
      }
      _pageIndex = listObj['pageIndex'];
      _pageTotal = listObj['total'];
      return listObj['list'];
    } else {
      return Future.delayed(Duration(seconds: 2), () {
        return[]; }); }}Copy the code
  • Flutter_spinkit is recommended to use a loading library, flutter_spinkit
  • Loading code (see the demo address code at the end of this article for more details)
Widget _buildIsLoading() {
    returnContainer(width: mediaQuery.of (context).size. Width, height: mediaQuery.of (context).size. new Center( child: Column( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: <Widget>[SpinKitCircle(size: 55.0, color: Theme. Of (context).primarycolor),],), Padding(Child: Text()"Loading...", style: TextStyle(color: color.black54, fontSize: 15.0)), padding: edgeinset.all (15.0),)); }Copy the code
  • Finally, through the constructor Settings to set the need to load the item value and whether to support the pull down refresh and load more, flexible configuration control
// module item final renderItem; // Final requestApi; // Final headerView; // Whether to add headers Final bool isHaveHeader; // Whether pull-down refresh is supported Final bool isCanRefresh; Final bool isCanLoadMore; final bool isCanLoadMore; const RefreshPage({@required this.requestApi, @required this.renderItem, this.headerView, this.isHaveHeader =false,
                     this.isCanRefresh = true,
                     this.isCanLoadMore = true })
                     : assert(requestApi is Function),
                       assert(renderItem is Function),
                      super();
Copy the code

Final Demo

The Demo address

  • Github.com/maoqitian/f…

  • Flutter complete Open Source project: github.com/maoqitian/f…

About me

Blog:

  • Personal blog
  • The Denver nuggets
  • Jane’s book
  • Github

Mail: