Flutter - 3 : 绘制

Flutter - 3 : 绘制

自定义控件所必须的一个部分就是绘制了,flutter相关的API跟Android的基本大差不差。会Android的话,相对而言,可能会轻松不少。
下面是效果图:

第一步 :

首先需要一组基础控件,最后放一个CustomPaint(),它的参数painter就是需要自定义的部分,child可以继续添加控件,这里就不放child了。

class TestPage extends StatelessWidget {
  final RepaintListener listener = new RepaintListener();
  final String letter = "A";
  @override
  Widget build(BuildContext context) {
    return new Material(
      color: Colors.blue,
      child: new Center(
        child: SizedBox(
          width: 120.0,
          height: 60.0,
          child: new InkWell(
            child: CustomPaint(painter: new _Painter(listener, letter)),
            onTap: () {
              listener.changeState();
            },
          ),
        ),
      ),
    );
  }
}
第二步 :

然后,需要自己定义一个类RepaintListener,去实现Listenable接口,来管理自定义的部分的绘制,这个接口可以接收到一个VoidCallBack类型的参数,用于控制重绘,我们只要在需要的时候调用它,就能让Painter重新进行绘制。

class RepaintListener extends Listenable {
  bool _pressed = false;
  VoidCallback _listener;

  @override
  void addListener(VoidCallback listener) {
    this._listener = listener;
  }

  @override
  void removeListener(VoidCallback listener) {
    this._listener = listener;
  }

  bool getState() {
    return _pressed;
  }

  void changeState(bool value) {
    _pressed = value;
    // 调用方法,触发重绘
    _listener();
  }
}
第三步 :

接下来就是整个过程当中的核心部分了,自定义一个类实现CustomPainter,实现其中必须实现的两个方法,如果需要添加重绘事件,就需要把刚才自定义的RepaintListener传递进来,然后将它传递给父类的repaint参数(super(repaint: listener)),这样在我们需要让它执行重绘时,就能达到想要的效果了,当然如果想要做动画效果,也可以传一个Animation<T>进去,这样就能将重绘行为,与动画相绑定了,毕竟Animation<T>也是实现了Listenable接口的。

另外,文字(以及图片)的绘制,都需要借助Dart中的相关方法去实现
import 'dart:ui' as ui;),
flutter本身却没有提供相应的方法。代码中的fontFamily请自动忽略。

class _Painter extends CustomPainter {
  final RepaintListener listener;

  String letter;

  final Color normal_color = Color(0xFFdddddd);
  final Color press_color = Colors.grey;

  final Color text_color = Colors.blue;

  final Paint painter = new Paint();

  ui.ParagraphBuilder _paragraph_builder;
  ui.Paragraph _paragraph;

  _Painter(this.listener, this.letter) : super(repaint: listener);

  @override
  void paint(Canvas canvas, Size size) {
    //剪切画布
    Rect rect = Offset.zero & size;
    canvas.clipRect(rect);

    if (listener.getState()) {
      painter.style = PaintingStyle.fill;
      painter.color = press_color;
      letter = letter.toLowerCase();
    } else {
      painter.style = PaintingStyle.fill;
      painter.color = normal_color;
      letter = letter.toUpperCase();
    }

    //  绘制背景
    RRect key = RRect.fromRectAndRadius(rect, Radius.circular(2.0));
    canvas.drawRRect(key, painter);

    //  绘制文字
    _paragraph_builder = ui.ParagraphBuilder(
      ui.ParagraphStyle(
        fontFamily: "hwxw",
        textAlign: TextAlign.center,
        fontSize: 22,
        fontWeight: FontWeight.bold,
        textDirection: TextDirection.ltr,
        maxLines: 1,
      ),
    );

    _paragraph_builder.pushStyle(ui.TextStyle(
        color: text_color, textBaseline: ui.TextBaseline.alphabetic));

    _paragraph_builder.addText(letter);
    _paragraph = _paragraph_builder.build();

    _paragraph.layout(ui.ParagraphConstraints(width: 10.0));
    canvas.drawParagraph(
        _paragraph,
        Offset((size.width - _paragraph.width) / 2,
            (size.height - _paragraph.height) / 2));
  }

  @override
  bool shouldRepaint(_Painter old) => false;
}

最后,flutter中Canvas能画的形状,可以从网上找一个,比如 :
点击跳转至某位大神的Canvas方法总结

本集完!

猜你喜欢

转载自blog.csdn.net/weixin_42572156/article/details/85016369