flutter TabBar指示器

在这里插入图片描述

第一层tabView

import 'package:jade/configs/PathConfig.dart';
import 'package:jade/customWidget/MyCustomIndicator.dart';
import'package:jade/homePage/promotion/promotionPost/MyPromotionListMainDesc.dart';
import 'package:jade/homePage/promotion/promotionPost/MyPromotionListSecond.dart';
import 'package:atui/jade/utils/JadeColors.dart';
import 'package:atui/util/navigator_util.dart';
import 'package:atui/widget/custom_appbar.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';

class MyPromotionListMain extends StatefulWidget{
  
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return _MyPromotionListMain();
  }
}

class _MyPromotionListMain extends State<MyPromotionListMain> with TickerProviderStateMixin{

  List<String> _tabs = ['我发布的','我推享的','我的阿推码'];
  TabController _tabController;
  
  void initState() {
    // TODO: implement initState
    super.initState();
    _tabController = TabController(
       // initialIndex: widget.initialIndex??0,
        length: _tabs.length,vsync: this);
  }

  
  void dispose() {
    // TODO: implement dispose
    _tabController.dispose();
    super.dispose();
  }
  
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      backgroundColor: Colors.white,
      appBar: CustomAppBar(
        backgroundColor: Colors.white,
        elevation: 0,
        leading: GestureDetector(
          onTap: () {
            Navigator.pop(context);
          },
          child: Icon(Icons.arrow_back_ios),
        ),
        iconTheme: IconThemeData(color: Color(0xff999999)),
        title: Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: [
            Container(),
            Container(
              margin: EdgeInsets.only(right: 34.w),
              child: Text(
                '推享赚',
                style: TextStyle(color: Colors.black),
              ),
            ),
            GestureDetector(
              child: Container(
                color: Colors.transparent,
                padding: EdgeInsets.all(4),
                child: Image.asset(PathConfig.iconQuestion,height: 40.w),
              ),
              onTap: () {
                NavigatorUtil.push(MyPromotionListMainDesc());
              },
            )
          ],
        ),
        centerTitle: true,
      ),
      body: _body()
    );
  }

  _body(){
    return Column(
      children: [
        _tabBarView(),
        Container(
          height: 2.w,
          width: double.infinity,
          color: JadeColors.lightGrey,
          margin: EdgeInsets.symmetric(vertical: 20.w),
        ),
        Expanded(child: _tabView())
      ],
    );
  }

  _tabBarView(){
    return TabBar(
      isScrollable: false,
      labelPadding: EdgeInsets.symmetric(horizontal: 0),
      indicator: MyCustomIndicator(),
      labelColor: Color(0xff333333),
      labelStyle: TextStyle(
        fontSize: 30.sp,
        fontWeight: FontWeight.w600,
      ),
      unselectedLabelColor: JadeColors.grey,
      unselectedLabelStyle: TextStyle(
        fontSize: 30.sp,
        fontWeight: FontWeight.w300
      ),
      indicatorSize: TabBarIndicatorSize.label,
      controller: _tabController,
      tabs: _tabs
          .map((value) => Container(padding: EdgeInsets.symmetric(horizontal: 20.w),child: Text(value))).toList(),
      onTap: (index) {},
    );
  }

  _tabView(){
    return TabBarView(
      //physics: const NeverScrollableScrollPhysics(),
        controller: _tabController,
        children: [
          MyPromotionListSecond(type: 0),
          MyPromotionListSecond(type: 1),
          MyPromotionListSecond(type: 2)
        ]
    );
  }
}

第二层tabView

import 'package:-jade/homePage/promotion/promotionPost/MyPromotionList.dart';
import 'package:jade/utils/JadeColors.dart';
import 'package:util/tab/customize_dicator.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';

/*
* 状态这一级的tabBar页面
* */

class TabTypeMode {
  int status;
  String title;

  TabTypeMode({
    this.status,
    this.title,
  });
}

class MyPromotionListSecond extends StatefulWidget{
  final int type; //0我发布的  1我推享的  2我的阿推码
  const MyPromotionListSecond({ this.type});

  
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return _MyPromotionListSecond();
  }
}

class _MyPromotionListSecond extends State<MyPromotionListSecond> with TickerProviderStateMixin{

  List<TabTypeMode> _tabs = [];
  TabController _tabController;

  
  void initState() {
    // TODO: implement initState
    if(widget.type == 2){
      _tabs = [
        TabTypeMode(status: 0,title: '全部'),
        TabTypeMode(status: 1,title: '待使用'),
        TabTypeMode(status: 2,title: '已使用'),
        TabTypeMode(status: 3,title: '已失效')
      ];
    }else{
      _tabs = [
        TabTypeMode(status: 0,title: '全部'),
        TabTypeMode(status: 1,title: '进行中'),
        TabTypeMode(status: 2,title: '已结束')
      ];
    }

    super.initState();

    _tabController = TabController(
      // initialIndex: widget.initialIndex??0,
        length: _tabs.length,vsync: this);
  }

  
  void dispose() {
    // TODO: implement dispose
    _tabController.dispose();
    super.dispose();
  }

  
  Widget build(BuildContext context) {
    // TODO: implement build
    return _body();
  }

  _body(){
    return Column(
      children: [
        Container(
          margin: EdgeInsets.only(bottom: 20.w),
          alignment: Alignment.centerLeft,
          child: _tabBarView(),
        ),
        Expanded(child: _tabView())
      ],
    );
  }

  _tabBarView(){
    return TabBar(
      isScrollable: true,
      labelPadding: EdgeInsets.symmetric(horizontal: 0),
      indicator: MyUnderlineTabIndicator(
          borderSide:
          BorderSide(width: 2, color:  JadeColors.yellow),
          insets: EdgeInsets.only(bottom: 5)),
      labelColor: Color(0xff333333),
      labelStyle: TextStyle(
        fontSize: 30.sp,
        fontWeight: FontWeight.w600,
      ),
      unselectedLabelColor: JadeColors.grey,
      unselectedLabelStyle: TextStyle(
        fontSize: 30.sp,
        fontWeight: FontWeight.w300
      ),
      indicatorWeight: 20.w,
      indicatorSize: TabBarIndicatorSize.label,
      controller: _tabController,
      tabs: _tabs
          .map((value) => Container(padding: EdgeInsets.symmetric(horizontal: 20.w),child: Text(value.title))).toList(),
      onTap: (index) {},
    );
  }
  _tabView(){
    return TabBarView(
      //physics: const NeverScrollableScrollPhysics(),
        controller: _tabController,
        children: _tabs.map((value) {
          return MyPromotionList(widget.type,value.status);
        }).toList()
    );
  }
}

指示器:

import 'package:flutter/material.dart';

class MyCustomIndicator extends Decoration {

  final double indWidth;
  final double indHeight;
  final double radius;

  MyCustomIndicator({this.indWidth = 70.0, this.indHeight = 12.0, this.radius = 5});

  
  BoxPainter createBoxPainter([VoidCallback onChanged]) {
    return _CustomBoxPainter(this, onChanged, indWidth, indHeight, radius);
  }
}

class _CustomBoxPainter extends BoxPainter {
  final MyCustomIndicator decoration;
  final double indWidth;
  final double indHeight;
  final double radius;

  _CustomBoxPainter(this.decoration, VoidCallback onChanged, this.indWidth, this.indHeight, this.radius)
      : super(onChanged);

  
  void paint(Canvas canvas, Offset offset, ImageConfiguration configuration) {
    final size = configuration.size;
    final newOffset = Offset(offset.dx + (size.width - indWidth) / 2, size.height - indHeight);
    final Rect rect = newOffset & Size(indWidth, indHeight);
    final Paint paint = Paint();
    paint.color = Colors.yellow;
    paint.style = PaintingStyle.fill;
    canvas.drawRRect(
      RRect.fromRectAndRadius(rect, Radius.circular(radius)), // 圆角半径
      paint,
    );
  }
}

// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import ‘package:flutter/material.dart’;
import ‘package:flutter/widgets.dart’;

/// Used with [TabBar.indicator] to draw a horizontal line below the
/// selected tab.
///
/// The selected tab underline is inset from the tab’s boundary by [insets].
/// The [borderSide] defines the line’s color and weight.
///
/// The [TabBar.indicatorSize] property can be used to define the indicator’s
/// bounds in terms of its (centered) widget with [TabIndicatorSize.label],
/// or the entire tab with [TabIndicatorSize.tab].
class MyUnderlineTabIndicator extends Decoration {
/// Create an underline style selected tab indicator.
///
/// The [borderSide] and [insets] arguments must not be null.
const MyUnderlineTabIndicator({
this.borderSide = const BorderSide(width: 2.0, color: Colors.white),
this.insets = EdgeInsets.zero,
}) : assert(borderSide != null),
assert(insets != null);

/// The color and weight of the horizontal line drawn below the selected tab.
final BorderSide borderSide;

/// Locates the selected tab’s underline relative to the tab’s boundary.
///
/// The [TabBar.indicatorSize] property can be used to define the
/// tab indicator’s bounds in terms of its (centered) tab widget with
/// [TabIndicatorSize.label], or the entire tab with [TabIndicatorSize.tab].
final EdgeInsetsGeometry insets;

@override
Decoration lerpFrom(Decoration a, double t) {
if (a is UnderlineTabIndicator) {
return UnderlineTabIndicator(
borderSide: BorderSide.lerp(a.borderSide, borderSide, t),
insets: EdgeInsetsGeometry.lerp(a.insets, insets, t),
);
}
return super.lerpFrom(a, t);
}

@override
Decoration lerpTo(Decoration b, double t) {
if (b is MyUnderlineTabIndicator) {
return MyUnderlineTabIndicator(
borderSide: BorderSide.lerp(borderSide, b.borderSide, t),
insets: EdgeInsetsGeometry.lerp(insets, b.insets, t),
);
}
return super.lerpTo(b, t);
}

@override
_MyUnderlinePainter createBoxPainter([ VoidCallback onChanged ]) {
return _MyUnderlinePainter(this, onChanged);
}
}

class _MyUnderlinePainter extends BoxPainter {
_MyUnderlinePainter(this.decoration, VoidCallback onChanged)
: assert(decoration != null),
super(onChanged);

final MyUnderlineTabIndicator decoration;

BorderSide get borderSide => decoration.borderSide;
EdgeInsetsGeometry get insets => decoration.insets;

Rect _indicatorRectFor(Rect rect, TextDirection textDirection) {
assert(rect != null);
assert(textDirection != null);
final Rect indicator = insets.resolve(textDirection).deflateRect(rect);

//希望的宽度
double wantWidth = 14;
//取中间坐标
double cw = (indicator.left + indicator.right) / 2;
return Rect.fromLTWH(cw - wantWidth / 2,
    indicator.bottom - borderSide.width, wantWidth, borderSide.width);

}

@override
void paint(Canvas canvas, Offset offset, ImageConfiguration configuration) {
assert(configuration != null);
assert(configuration.size != null);
final Rect rect = offset & configuration.size;
final TextDirection textDirection = configuration.textDirection;
final Rect indicator = _indicatorRectFor(rect, textDirection).deflate(borderSide.width / 2.0);
// final Paint paint = borderSide.toPaint()…strokeCap = StrokeCap.square;
// 改为圆角
final Paint paint = borderSide.toPaint()…strokeCap = StrokeCap.round;
canvas.drawLine(indicator.bottomLeft, indicator.bottomRight, paint);
}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/153669.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

CANoe-Trace窗口介绍

1、什么是Trace窗口 Trace窗口的目的是在测量期间(CANoe运行时)记录总线活动。在测试设置(Measurement Setup)中的Trace窗口的输入处接收到的所有消息都在Trace输出窗口中显示为文本。 当然,除了总线报文数据外,还有一系列的其他事件可以输出到Trace窗口,例如: 错误事…

【网络基础实战之路】基于不同协议间使用重发布路由策略

系列文章传送门&#xff1a; 【网络基础实战之路】设计网络划分的实战详解 【网络基础实战之路】一文弄懂TCP的三次握手与四次断开 【网络基础实战之路】基于MGRE多点协议的实战详解 【网络基础实战之路】基于OSPF协议建立两个MGRE网络的实验详解 【网络基础实战之路】基于…

香港优才计划获批概率跌破20%,拿香港身份越来越难了?

香港优才计划获批概率跌破20%&#xff0c;拿香港身份越来越难了&#xff1f; 截止10月31日&#xff0c;香港各类人才引进计划共收到18万4538宗申请&#xff0c;获批11万5741宗&#xff0c;整体“获批率”为62.72%。 具体到项目获批率&#xff1a; ①优才计划共收到63979宗申请&…

自动化测试介绍和分类,看这一篇就够了

&#x1f4e2;专注于分享软件测试干货内容&#xff0c;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01;&#x1f4e2;交流讨论&#xff1a;欢迎加入我们一起学习&#xff01;&#x1f4e2;资源分享&#xff1a;耗时200小时精选的「软件测试」资…

中小商家,也能在抖音电商找到星辰大海

“你这背景太假了&#xff01;” 横穿中国&#xff0c;从江苏闯荡到新疆创业卖蜂蜜的刘元杰&#xff0c;怎么也没有预料到这句话会成为热梗。他本人在直播间各种和网友之间“极限拉扯”&#xff0c;用扔水桶、扔石头、召唤新疆大叔骑马打招呼等操作自证背景的真实性。这让他的…

git宝藏干货

git命令 怎样删除gitee仓库 Gitee上传代码 在Gitee上创建该项目的远程仓库 进入你想要上传的文件目录下&#xff0c;右键单击空白处&#xff0c;点击Git Bash Here 命令行输入下列命令&#xff0c;初始化本地仓库 git init 添加项目目录下所有文件至本地仓库 git add . …

2019年五一杯数学建模C题科创板拟上市企业估值解题全过程文档及程序

2019年五一杯数学建模 C题 科创板拟上市企业估值 原题再现 科创板在首届中国国际进口博览会开幕式上宣布设立&#xff0c;是独立于现有主板市场的新设板块。设立科创板并试点注册制是提升服务科技创新企业能力、增强市场包容性、强化市场功能的一项资本市场重大改革举措&…

MTK联发科MT8766核心板 4G智能模块安卓开发板方案定制

MT8766 是一款基于 MTK 平台工业级高性能、可运行 android12.0 操作系统的 4G智能模块,三款模块硬件是相互兼容&#xff0c;支持 LTE-FDD&#xff08;CAT-7&#xff09;/LTE-TDD&#xff08;CAT-7&#xff09;/WCDMA/TD-SCDMA/EVDO/GSM 等多种制式&#xff1b;支持 WiFi5 802.1…

景联文科技入选量子位智库《中国AIGC数据标注产业全景报告》数据标注行业代表机构

量子位智库《中国AIGC数据标注产业全景报告》中指出&#xff0c;数据标注处于重新洗牌时期&#xff0c;更高质量、专业化的数据标注成为刚需。未来五年&#xff0c;国内AI基础数据服务将达到百亿规模&#xff0c;年复合增长率在27%左右。 基于数据基础设施建设、大模型/AI技术理…

释放机器人潜力,INDEMIND深耕底层技术

市场转暖&#xff0c;但攘外需要同时安内。 市场降温之后&#xff0c;正迎来拐点 疫情之后&#xff0c;经济逐渐下行&#xff0c;服务机器人的“好日子”也随之结束&#xff0c;整个行业都在动荡中经历渡劫。根据TE智库报告显示&#xff0c;从2022年开始&#xff0c;我国服务…

纺织机械对直线模组的要求有哪些?

直线模组在纺织机械中的应用越来越广泛&#xff0c;对其性能和精度要求也越来越高&#xff0c;那么什么样的纺织机械模组才可以满足纺织机械的使用需求呢&#xff1f; 1、高精度&#xff1a;直线模组需要具备高精度的运动和定位能力&#xff0c;以确保纺织机械能够精确控制纱线…

Notion平替工具AFFINE知识库如何本地部署与公网远程访问

公网访问全能知识库工具AFFINE&#xff0c;Notion的免费开源替代品 前言 AFFiNE 是一个全新的开源项目&#xff0c;旨在克服 Notion 和 Miro 在安全和隐私方面的一些局限性。它的设计目标是帮助用户将会议记录、待办事项、文档中的目标、视频会议白板上的头脑风暴以及客户访谈…

精选112个炫酷大数据可视化大屏模板(含源码),拿走即用

112套大数据可视化炫酷大屏Html5模板&#xff1b;包含行业&#xff1a;智慧社区、智慧物业、政务系统、智慧交通、智慧工程、智慧医疗、智慧金融银行、智慧农业等&#xff0c;全网最新、最多&#xff0c;最全、最酷、最炫大数据可视化模板。 可视化大屏预览及源码获取地址&…

影响气膜建筑坍塌的原因

气膜建筑以其轻盈、透光、环保等特性&#xff0c;逐渐在建筑领域崭露头角。然而&#xff0c;这种建筑形式并非没有缺陷&#xff0c;其安全性与稳定性直接影响到建筑物的使用寿命和人员安全。 一、结构设计不合理 气膜建筑的结构设计是影响其稳定性的关键因素。良好的结构设计能…

K8S篇之实现利用Prometheus监控pod的实时数据指标

一、监控部署 1、将k8s集群中kube-state-metrics指标进行收集&#xff0c;服务进行部署 1.1 pod性能指标&#xff08;k8s集群组件自动集成&#xff09; k8s组件本身提供组件自身运行的监控指标以及容器相关的监控指标。通过cAdvisor 是一个开源的分析容器资源使用率和性能特性的…

vue + andtd 动态增加表单并进行表单校验

<template><a-modalv-model:visible="visible":title="formData.id ? 编辑渠道 : 添加渠道":width="850":mask-closable="false":destroy-on-close="true"@ok="onSubmit"@cancel="onClose"&g…

双十一快递业务量暴增,快递驿站视频智能监控方案保障快递业务顺利开展

一、背景分析 虽然刚刚过去的双十一电商购物狂潮结束&#xff0c;但是快递业务量仍处在高峰期。据数据统计&#xff0c;今年全国邮政快递企业在11月11日当天共揽收快递包裹6.39亿件&#xff0c;是平日业务量的1.87倍&#xff0c;同比增长15.76%。随着电商购物节的不断增多&…

Confluence的安装部署

先介绍一下confluence Confluence是一个专业的企业知识管理与协同软件&#xff0c;也可以用于构建企业wiki。使用简单&#xff0c;但它强大的编辑和站点管理特征能够帮助团队成员之间共享信息、文档协作、集体讨论&#xff0c;信息推送。 confluence是Atlassian公司的&#x…

RDB是什么?·

目录 一、RDB是什么&#xff1f; 二、 RDB触发机制 2.1 手动触发 2.2 自动触发 2.3 RDB执行流程 三、RDB的文件处理 四、RDB的优缺点 一、RDB是什么&#xff1f; RDB是Redis DataBase&#xff0c;是Redis实现数据持久化的一种方式。因为Redis的数据是存储在内存中的&#xff0…

Leetcode2760. 最长奇偶子数组

Every day a Leetcode 题目来源&#xff1a;2760. 最长奇偶子数组 解法1&#xff1a;模拟 代码&#xff1a; class Solution { public:int longestAlternatingSubarray(vector<int> &nums, int threshold){int n nums.size();int ans 0;for (int i 0; i <…