122、Flutter 实现类似网易新闻的客户端APP(视屏列表页面的抽象及优化)

这一篇来讲解一下视频列表页面的优化,与上一篇的区别主要是进行的代码的抽象,对可复用部分使用tabCommon类进行了封装。

将主页中的SmallVideoPage.dart页面替换成VideoTabPage2这个界面,因为视频页面也有一级菜单和二级菜单。

这里的TabCommon就是为了多级菜单抽象出来的抽象工具类。

 

VideoTabPage2 是bottomTabBar里面对应的视频页面,

在VideoTabPage2页面里面,引用了tabCommon页面,一个通用的工具类,来创建二级级联的菜单

上面的图示例是tabCommon页面的详细结构,

下面是VideoTabPage2页面的详细代码

import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_news_netbase/part2/TabContentsPage.dart';
import 'package:flutter_news_netbase/part2/SearchBar.dart';
import 'package:flutter_news_netbase/part2/routes/RouteManager.dart';
import 'package:flutter_news_netbase/part2/view/TabCommon.dart';

class VideoTabPage2 extends StatefulWidget {
  @override
  _VideoTabPage2State createState() => _VideoTabPage2State();
}

class _VideoTabPage2State extends State<VideoTabPage2>
    with SingleTickerProviderStateMixin {
  TabController tabController;

  int result = 1;

  List<Tab> tabs = [];
  List<String> tabStrData = <String>[];
  List<Widget> tabWidgets = <Widget>[];
//  Widget titleWidgets;

  TabCommon tabCommon;

  @override
  void initState() {
    super.initState();
    tabWidgets = videoTabData;
    tabStrData = videoTabsLabels;
    //tabCommon = TabCommon(tabStrData, tabWidgets, titleWidgets);
  }

  void onCancelSearch() {}

  void onSearchQueryChanged(String query) {}

  @override
  Widget build(BuildContext context) {
    setState(() {
      tabCommon = TabCommon(tabStrData, tabWidgets,
          isScrollable: true, key: ObjectKey(VideoTabPage2()));
    });

    return tabCommon;
  }

  @override
  void dispose() {
    super.dispose();
  }
}

再下面是tabCommon页面 , 一个工具类用来创建通用的二级菜单的级联页面

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter_news_netbase/part2/TabContentsPage.dart';
import 'package:flutter_news_netbase/part2/SearchBar.dart';
import 'package:flutter_news_netbase/part2/routes/RouteManager.dart';

class TabCommon extends StatefulWidget {
  TabController _tabController;

  int _result = 1;

  List<Tab> _tabs = [];

  List<String> tabStrData = <String>[];

  List<Widget> tabWidgets = <Widget>[];

//  Widget titleWidgets;

  Color indicatorColor;

  double indicatorWeight = 2;

  EdgeInsets indicatorPadding;

  TabBarIndicatorSize indicatorSize;

  Color labelColor;

  TextStyle labelStyle;

  Color unselectedLabelColor;

  DragStartBehavior dragStartBehavior;

  TextStyle unselectedLabelStyle;

  Color backgroundColor;

  bool isShowSearIcon;

  double widths;

  bool showContainer;

  Color containerBorderColor;

  bool isScrollable = true;

  TabCommon(
    this.tabStrData,
    this.tabWidgets, {
    this.backgroundColor,
    this.isShowSearIcon,
    this.indicatorColor,
    this.indicatorWeight,
    this.indicatorPadding,
    this.indicatorSize,
    this.labelColor,
    this.labelStyle,
    this.unselectedLabelColor,
    this.unselectedLabelStyle,
    this.dragStartBehavior,
    Key key,
    this.showContainer = false,
    this.containerBorderColor,
    this.isScrollable,
  }) : super(key: key);

  @override
  _TabCommonState createState() => _TabCommonState();
}

// 通用的一个Tab页面,Tab页面的基类
class _TabCommonState extends State<TabCommon>
    with SingleTickerProviderStateMixin {
  Tab currentTab;

  @override
  void initState() {
    super.initState();
    widget._tabController = TabController(
        length: widget.tabWidgets.length,
        vsync: this,
        initialIndex: widget._result);
    widget._tabs = widget.tabStrData.map((item) {
      if (widget.showContainer == true) {
        return Tab(
          child: Container(
            padding: EdgeInsets.fromLTRB(10, 5, 10, 5),
            decoration: new BoxDecoration(
              border: new Border.all(
                color: widget.containerBorderColor == null
                    ? Colors.grey
                    : widget.containerBorderColor,
                width: 1,
              ),
              borderRadius: BorderRadius.all(
                Radius.circular(20),
              ),
            ),
            child: Text(item),
          ),
        );
      } else {
        currentTab = Tab(
          text: item,
        );
        return currentTab;
      }
    }).toList();
  }

  @override
  Widget build(BuildContext context) {
    widget.widths = MediaQuery.of(context).size.width;

    setState(() {
      widget._tabController.index = widget._result;
    });
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.white,
        elevation: 0,
        title: buildCommonTitle(tabs: widget._tabs, isShowSearIcon: true),
      ),
      body: TabBarView(
        children: widget.tabWidgets == null
            ? buildCommonTitle(tabs: widget._tabs, isShowSearIcon: true)
            : widget.tabWidgets,
        controller: widget._tabController,
      ),
    );
  }

  @override
  void dispose() {
    super.dispose();
    widget._tabController.dispose();
  }

  @override
  onSearchQueryChanged(String query) {
    print('点击 search $query');
  }

  onCancelSearch() {
    onSearchQueryChanged('');
    Navigator.of(context).pop();
  }

  Widget buildTabBar(List<Tab> tabs) {
    return TabBar(
      key: PageStorageKey<Tab>(currentTab),
      tabs: tabs,
      controller: widget._tabController,
      isScrollable: widget.isScrollable,
      indicatorColor:
          widget.indicatorColor == null ? Colors.black : widget.indicatorColor,
      indicatorWeight:
          widget.indicatorWeight == null ? 2.0 : widget.indicatorWeight,
      indicatorPadding: widget.indicatorPadding == null
          ? EdgeInsets.all(0)
          : widget.indicatorPadding,
      indicatorSize: widget.indicatorSize == null
          ? TabBarIndicatorSize.tab
          : widget.indicatorSize,
      labelColor: widget.labelColor == null ? Colors.black : widget.labelColor,
      labelStyle: widget.labelStyle == null
          ? TextStyle(color: Colors.black, fontSize: 14)
          : widget.labelStyle,
      unselectedLabelStyle: widget.unselectedLabelStyle == null
          ? TextStyle(color: Colors.orange, fontSize: 14)
          : widget.unselectedLabelStyle,
      dragStartBehavior: widget.dragStartBehavior == null
          ? DragStartBehavior.start
          : widget.dragStartBehavior,
      onTap: (index) {
        print('点击了 $index');
      },
    );
  }

  Widget buildCommonTitle({
    Key key,
    @required List<Widget> tabs,
    bool isShowSearIcon = false,
    TabController controller,
    bool isScrollable = true,
    Color indicatorColor,
    double indicatorWeight = 2.0,
    EdgeInsetsGeometry indicatorPadding = EdgeInsets.zero,
    Decoration indicator,
    TabBarIndicatorSize indicatorSize,
    Color labelColor,
    TextStyle labelStyle,
    EdgeInsetsGeometry labelPadding,
    Color unselectedLabelColor,
    TextStyle unselectedLabelStyle,
    DragStartBehavior dragStartBehavior = DragStartBehavior.start,
    ValueChanged<int> onTap,
  }) {
    if (isShowSearIcon == true) {
      return Container(
        width: widget.widths,
        height: 50,
        child: Row(
          crossAxisAlignment: CrossAxisAlignment.center,
          children: <Widget>[
            Expanded(
              child: buildTabBar(widget._tabs),
              flex: 9,
            ),
            Expanded(
              child: InkWell(
                onTap: () {
                  routePathAnim(
                      context,
                      SearchBar(
                        Colors.white,
                        onCancelSearch: onCancelSearch,
                        onSearchQueryChanged: onSearchQueryChanged,
                      ),
                      showAnim: true,
                      type: Type.RIGHT_TO_LEFT,
                      duration: 800);
                },
                child: Container(
                  padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
                  child: Icon(
                    Icons.search,
                    size: 25,
                    color: Colors.grey,
                  ),
                ),
              ),
              flex: 1,
            )
          ],
        ),
      );
    } else {
      buildTabBar(widget._tabs);
    }
  }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值