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