Flutter 之 TabBar 自定义图片指示器。

1,080 阅读2分钟

痛点:

在Flutter 系统给出的组件中,TabBar 是一个非常好用的插件,但是一直困扰我的是他的指示器参数只能写一下颜色 或者圆角之类的,不能满足自定义 图片的内容。

解决方案:

我们看源码中 indicator 的类型是 Decoration 但是,是一个抽象接口 我们需要看 BoxDecoration 我们找到 有 返回 BoxPainter 的方法

@override
BoxPainter createBoxPainter([ VoidCallback? onChanged ]) {
  assert(onChanged != null || image == null);
  return _BoxDecorationPainter(this, onChanged);
}

我们再来看 BoxPainter 。

从字面意思看,大概是盒子绘制者。

我们发现 BoxPainter 是一个抽象层 定义了一个这样的一个绘制的方法。

void paint(Canvas canvas, Offset offset, ImageConfiguration configuration);

接下来我们就可以继承 :BoxDecoration 并实现下面方法:

 BoxPainter createBoxPainter([ VoidCallback? onChanged ]) 

然后,继承 BoxPaiter 虚拟类 并实现如下方法:

paint(Canvas canvas, Offset offset, ImageConfiguration configuration);

在此方法中利用 Canvas 进行我们需要的绘制 。

这里需要说明一下,加载本地图片绘制是异步过程。

下面是如何加载本地assets 资源图片的过程:

import 'dart:async';
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

/// 当使用 CustomPaint 或者自定义 shape 的时候 需要一个 绘制一张图片时候需要这样加载
class PaintImageTool {
  // 通过本地路径拿到图片
 static Future<ui.Image> getAssetImage(String asset,{width,height}) async {
    ByteData data = await rootBundle.load(asset);
    ui.Codec codec = await ui.instantiateImageCodec(data.buffer.asUint8List(),targetWidth: width,targetHeight: height);
    ui.FrameInfo fi = await codec.getNextFrame();
    return fi.image;
  }

 static Future<ui.Image> getAssetImage2(String asset,BuildContext context,{width,height}) async {
    ByteData data = await DefaultAssetBundle.of(context).load(asset);
    ui.Codec codec = await ui.instantiateImageCodec(data.buffer.asUint8List(),targetWidth: width,targetHeight: height);
    ui.FrameInfo fi = await codec.getNextFrame();
    return fi.image;
  }

//方法1:获取网络图片 返回ui.Image
  static Future<ui.Image> getNetImage(String url,{width,height}) async {
    ByteData data = await NetworkAssetBundle(Uri.parse(url)).load(url);
    ui.Codec codec = await ui.instantiateImageCodec(data.buffer.asUint8List(),targetWidth: width,targetHeight: height);
    ui.FrameInfo fi = await codec.getNextFrame();
    return fi.image;
  }
}

最后和TabBarView 配合联动效果如下:

heart.gif

注意事项: 绘图 绘制的都是 1 倍像素的 会看到有毛边现象。

具体解决方法如下:

canvas.drawImageRect(Image image, Rect src, Rect dst, Paint paint)
image 通过上面方法加载的图片内容。 
src 表示图片上的像素点剪切的位置; 使用原始像素范围
dst  表示要绘制到什么位置,以及大小的参数。 压缩原始像素尺寸 例如宽高缩小3倍
paint 绘制参数 

想必看到这里聪明的你应该理解我的意思了,那么赶紧试试吧!希望你能成功。