
image.png
首頁 ui是這樣
技術(shù)點(diǎn)分析

首頁.gif
可以看到首頁需要這種可以滾動(dòng)分頁切換的 采用
tabbar+TabBarView
問題:但是tabbar 下面的indicator(指示器)默認(rèn)不是圓角的 而且不能自定義 寬度 系統(tǒng)默認(rèn)只提供了2種
//根據(jù)文字寬度
TabBarIndicatorSize.label
//根據(jù)tab的寬度
TabBarIndicatorSize.tab
1. flutter 自定義 indicator(指示器)
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
// 默認(rèn)高度從46改為40
const double _kTabHeight = 40.0;
const double _kTextAndIconTabHeight = 72.0;
class RoundUnderlineTabIndicator extends Decoration {
/// Create an underline style selected tab indicator.
///
/// The [borderSide] and [insets] arguments must not be null.
const RoundUnderlineTabIndicator({
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 UnderlineTabIndicator) {
return UnderlineTabIndicator(
borderSide: BorderSide.lerp(borderSide, b.borderSide, t),
insets: EdgeInsetsGeometry.lerp(insets, b.insets, t),
);
}
return super.lerpTo(b, t);
}
@override
_UnderlinePainter createBoxPainter([ VoidCallback onChanged ]) {
return _UnderlinePainter(this, onChanged);
}
}
class _UnderlinePainter extends BoxPainter {
_UnderlinePainter(this.decoration, VoidCallback onChanged)
: assert(decoration != null),
super(onChanged);
final RoundUnderlineTabIndicator 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);
// return Rect.fromLTWH(
// indicator.left,
// indicator.bottom - borderSide.width,
// indicator.width,
// borderSide.width,
// );
//希望的寬度
double wantWidth = 25;
//取中間坐標(biāo)
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);
}
}
Copy一份系統(tǒng)的 從新命名一個(gè) RoundUnderlineTabIndicator 類 修改 修改參數(shù)即可
使用方式
TabBar(
..............
indicator: RoundUnderlineTabIndicator(
borderSide: BorderSide(
width: 3.5,
color: ColorsUtils.main_color,
)),
......
)
問題2

image.png
上面區(qū)域有陰影,可以自己寫,我這是用的ui給的一張背景圖,這時(shí)候就涉及到 圖片拉伸的問題
需要指定區(qū)域拉伸, 就和iOS原生的Show Slicing,android 的.9處理 是一樣的效果,當(dāng)然你可以選擇用card組件去實(shí)現(xiàn)
使用image的centerSlice 拉伸指定區(qū)域 這里需要 Rect.fromLTRB 或者 Rect.fromLTWH,這里需要注意的是
1.組件不能比你圖片大
2.fromLTRB 和 fromLTWH 指定位置的問題
return Container(
width: 300,
height: 195,
decoration: BoxDecoration(
image: DecorationImage(
centerSlice: Rect.fromLTRB(60, 60, 71, 71),
image: AssetImage("assets/images/beijing.png"),
fit: BoxFit.fill),
color: Colors.red),
child: Text("哈哈"));
上圖 Rect.fromLTRB(60, 60, 71, 71) 我以為 會(huì)是這樣的
image.png
但實(shí)際上卻不是這樣的 實(shí)際上是這樣的
image.png
為啥會(huì)是這樣呢Rect.fromLTRB ltrb都是距離左上角的距離
fromLTWH 這個(gè)就更好理解一點(diǎn)了

image.png
問題3

指示器.gif
這里的搭配
pageView+Indicator可以看出指示器需要自定義 而且?guī)?dòng)畫的
flutter 自定義指示器(Indicator)
/// An indicator showing the currently selected page of a PageController
class CSTIndicator extends AnimatedWidget {
CSTIndicator({
this.controller,
this.itemCount,
this.onPageSelected,
this.color:ColorsUtils.yelllow_color ,
}) : super(listenable: controller);
/// The PageController that this DotsIndicator is representing.
final PageController controller;
/// The number of items managed by the PageController
final int itemCount;
/// Called when a dot is tapped
final ValueChanged<int> onPageSelected;
/// The color of the dots.
///
/// Defaults to `Colors.white`.
final Color color;
// The base size of the dots
static const double _kDotSize = 8.0;
// The increase in the size of the selected dot
static const double _kMaxZoom = 2.5;
// The distance between the center of each dot
static const double _kDotSpacing = 25.0;
Widget _buildDot(int index) {
double selectedness = Curves.easeOut.transform(
max(
0.0,
1.0 - ((controller.page ?? controller.initialPage) - index).abs(),
),
);
double zoom = 1.0 + (_kMaxZoom - 1.0) * selectedness;
return new Container(
width: _kDotSpacing,
child: new Center(
child: new Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(_kDotSize/2),
color: color,
),
width: _kDotSize * zoom,
height: _kDotSize ,
child: new InkWell(
onTap: () => onPageSelected(index),
),
),
),
);
}
Widget build(BuildContext context) {
return new Row(
mainAxisAlignment: MainAxisAlignment.center,
children: new List<Widget>.generate(itemCount, _buildDot),
);
}
}
使用方式
CSTIndicator(
controller: pageCtr, //注意這個(gè)controller是 PageController
itemCount: 3,
/*
如需要點(diǎn)擊 指示器切換pageView 需要實(shí)現(xiàn)此事件,我上面用不上,所以不實(shí)現(xiàn)
onPageSelected: (int page) {
pageCtr.animateToPage(
page,
duration:time,
curve:curve,
);
*/
)
以上理解如有誤請(qǐng)大佬能夠指出,3q
ok,以夢為馬,不負(fù)韶華

image.png

