Flutter 组件:列表复用,支持 TabBar 不可点击状态

一、需求

工作中常遇到列表界面复用,每次敲重复代码有点繁琐,随顺手封装,方便复用;
值得注意的是flutter 中不可点击状态不是通过属性设置的,而是通过 IgnorePointer 组件实现的;

///TabBar+TabBarView
class TabBarTabBarView extends StatefulWidget {

/// TabBar + PageViewW
class TabBarPageView extends StatefulWidget {

二、screenshots

三、源码

TabBarTabBarView

//
//  TabBarPageView.dart
//  fluttertemplet
//
//  Created by shang on 10/22/21 5:03 PM.
//  Copyright © 10/22/21 shang. All rights reserved.
//

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:fluttertemplet/dartExpand/ddlog.dart';
import 'package:tuple/tuple.dart';


import 'package:flutter/material.dart';

///TabBar+TabBarView
class TabBarTabBarView extends StatefulWidget {

  final List<Tuple2<String, Widget>> items;

  final Color? indicatorColor;

  final Color? labelColor;

  final PageController? pageController;

  final TabController? tabController;

  final ValueChanged<int> onPageChanged;

  final bool Function(int)? canPageChanged;

  final bool isTabBarTop;

  TabBarTabBarView({
    Key? key,
    this.isTabBarTop = true,
    required this.items,
    this.indicatorColor,
    this.labelColor,
    this.pageController,
    this.tabController,
    required this.onPageChanged,
    this.canPageChanged,
  }) : super(key: key);


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

class _TabBarTabBarViewState extends State<TabBarTabBarView> with TickerProviderStateMixin {

  late TabController _tabController;
  late TabController _tabController1 = TabController(length: widget.items.length, vsync: this);

  ///是否允许滚动
  bool get canScrollable {
    if (widget.canPageChanged != null && widget.canPageChanged!(_tabController.index) == false) {
      return false;
    }
    return true;
  }

  @override
  void initState() {
    _tabController = widget.tabController ?? TabController(length: widget.items.length, vsync: this)
    ..addListener(() {
      // ddlog(_tabController.index);
      setState(() {
        _tabController1.animateTo( _tabController.index);
      });
      widget.onPageChanged(_tabController.index);
    });

    super.initState();
  }

  @override
  void dispose() {
    _tabController.dispose();

    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final list = [
      _buildTabBar(),
      _buildTabBarView(),
    ];
    return Column(
      mainAxisSize: MainAxisSize.min,
      children: widget.isTabBarTop ? list : list.reversed.toList(),
    );
  }

  Widget _buildTabBar() {
    final textColor = widget.labelColor ?? Theme
        .of(context)
        .colorScheme
        .secondary;
    final bgColor = widget.indicatorColor ?? Colors.white;

    // final bgColor = Theme.of(context).colorScheme.secondary;
    // final textColor = Colors.white;

    BoxDecoration indicatorTop = BoxDecoration(
      border: Border(
        top: BorderSide(
          // color: textColor ,
            color: textColor,
            width: 3.0
        ),
      ),
    );

    BoxDecoration indicatorBom = BoxDecoration(
      border: Border(
        bottom: BorderSide(
          // color: textColor ,
            color: textColor,
            width: 3.0
        ),
      ),
    );


    final tabBar = TabBar(
      controller: _tabController1,
      tabs: widget.items.map((e) => Tab(text: e.item1)).toList(),
      labelColor: textColor,
      indicator: widget.isTabBarTop ? indicatorBom : indicatorTop,
      onTap: (index) {
        // ddlog([index, _tabController.index]);
        setState(() {
          _tabController.animateTo( _tabController1.index);
        });
        // widget.onPageChanged(_tabController.index);
      },
    );

    if (!canScrollable) {
      return IgnorePointer(
        child: tabBar,
      );
    }

    if (widget.isTabBarTop) {
      return tabBar;
    }

    return Material(
        color: bgColor,
        child: SafeArea(
          child: tabBar,
        )
    );
  }

  Widget _buildTabBarView() {
    return Expanded(
      child: TabBarView(
        controller: _tabController,
        physics: canScrollable ? BouncingScrollPhysics() : NeverScrollableScrollPhysics(),
        children: widget.items.map((e) => e.item2).toList(),
      ),);
  }

}

TabBarPageView

//
//  TabBarPageView.dart
//  fluttertemplet
//
//  Created by shang on 10/22/21 5:03 PM.
//  Copyright © 10/22/21 shang. All rights reserved.
//

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:fluttertemplet/dartExpand/ddlog.dart';
import 'package:tuple/tuple.dart';

/// TabBar + PageViewW
class TabBarPageView extends StatefulWidget {

  final List<Tuple2<String, Widget>> items;

  final Color? indicatorColor;

  final Color? labelColor;

  final PageController? pageController;

  final TabController? tabController;

  final ValueChanged<int> onPageChanged;

  final bool Function(int)? canPageChanged;

  final bool isTabBarTop;

  TabBarPageView({
    Key? key,
    this.isTabBarTop = true,
    required this.items,
    this.indicatorColor,
    this.labelColor,
    this.pageController,
    this.tabController,
    required this.onPageChanged,
    this.canPageChanged,
  }) : super(key: key);

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

class _TabBarPageViewState extends State<TabBarPageView> with SingleTickerProviderStateMixin {

  late TabController _tabController;
  late PageController _pageController;

  ///是否允许滚动
  bool get canScrollable {
    if (widget.canPageChanged != null && widget.canPageChanged!(_tabController.index) == false) {
      return false;
    }
    return true;
  }

  @override
  void initState() {
    _tabController = widget.tabController ?? TabController(length: widget.items.length, vsync: this);
    _pageController = widget.pageController ?? PageController(initialPage: 0, keepPage: true);
    // ..addListener(() {
    //   ddlog(_pageController.page);
    //
    // });

    super.initState();
  }

  @override
  void dispose() {
    _tabController.dispose();
    _pageController.dispose();

    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final list = [
      _buildTabBar(),
      _buildPageView(),
    ];
    return Column(
      mainAxisSize: MainAxisSize.min,
      children: widget.isTabBarTop ? list : list.reversed.toList(),
    );
  }

  Widget _buildTabBar() {
    final textColor = widget.labelColor ?? Theme
        .of(context)
        .colorScheme
        .secondary;
    final bgColor = widget.indicatorColor ?? Colors.white;

    // final bgColor = Theme.of(context).colorScheme.secondary;
    // final textColor = Colors.white;

    BoxDecoration indicatorTop = BoxDecoration(
      border: Border(
        top: BorderSide(
          // color: textColor ,
            color: textColor,
            width: 3.0
        ),
      ),
    );

    BoxDecoration indicatorBom = BoxDecoration(
      border: Border(
        bottom: BorderSide(
          // color: textColor ,
            color: textColor,
            width: 3.0
        ),
      ),
    );


    final tabBar = TabBar(
      controller: _tabController,
      tabs: widget.items.map((e) => Tab(text: e.item1)).toList(),
      labelColor: textColor,
      indicator: widget.isTabBarTop ? indicatorBom : indicatorTop,
      onTap: (index) {
        // ddlog(index);
        setState(() {
          _pageController.jumpToPage(index);
        });
      },
    );

    if (!canScrollable) {
      return IgnorePointer(
        child: tabBar,
      );
    }

    if (widget.isTabBarTop) {
      return tabBar;
    }

    return Material(
        color: bgColor,
        child: SafeArea(
          child: tabBar,
        )
    );
  }

  Widget _buildPageView() {
    return Expanded(
      child: PageView(
        controller: _pageController,
        physics: canScrollable ? BouncingScrollPhysics() : NeverScrollableScrollPhysics(),
        children: widget.items.map((e) => e.item2).toList(),
        onPageChanged: (index) {
          widget.onPageChanged(index);
          setState(() {
            _tabController.animateTo(index);
          });
        },
      ));
  }
}

源代码:githubicon-default.png?t=M5H6https://github.com/shang1219178163/flutter_templet_project/blob/main/lib/pages/tabBar_reuse_page_demo.dart

猜你喜欢

转载自blog.csdn.net/jdsjlzx/article/details/125340702