Flutter图片验证码本地封装

实现效果

Flutter图片验证码本地封装_第1张图片
点击图片重置字母

初始化代码

CodeReview(
//设置初始字符串,此处有个坑,很是郁闷,暂缓解决方案
// initState 中设置回调后不可以调用 setState 方法否则报错,否则运行出错
// widget.onTap(randString);

                text:   randomAlphaNumeric(4),
                onTap: (text) {
// 点击后变化的字符串
                },
              ),

插件呢只用了一个

random_string: ^1.1.0

现学现卖,果然还是有部分问题

实现思路,字母展示很简单,随机字母大小,随机pandding的高度,在row中展示即可。背景实现我用的事线条绘制,但遇到一些问题,暂时没有解决,只能单色线条了。 实际使用中,一般是后台生成图片进行校正,我这只是自娱自乐,还没有乐起来,着实伤心。。。

flutter 好一点的事计算文字,完全可以按照文字大小设置承载组建的size。因为很简单然后我就直接上代码了。

import 'dart:math';
import 'dart:ui';

import 'package:flutter/material.dart';
import 'package:no_alone/code_paint.dart';
import 'package:no_alone/tools/dzy_theme.dart';
import 'package:random_string/random_string.dart';

// 当前存在的问题是,必须在外部调用的时候给一个初始值
class CodeReview extends StatefulWidget {
  CodeReview({Key key, this.text, this.onTap}) : super(key: key);
  final String text;
  final onTap;
  _CodeReviewState createState() => _CodeReviewState();
}

class _CodeReviewState extends State {
  String _ranStr;
  int _textLength;
  double _width;
  double _height;
  List _lineOffsets = [];
  Color _ranColor = DzyTheme.randomColor();

  void _randLines() {
    _lineOffsets.clear();
    for (var i = 0; i < _textLength; i++) {
      double fromX = randomBetween(10, 20).toDouble();
      double fromY = randomBetween(3, 33).toDouble();
      Offset from = Offset(fromX, fromY);
      _lineOffsets.add(from);

      double endX = randomBetween(60, _width.toInt() - 10).toDouble();
      double endY = randomBetween(3, 33).toDouble();
      Offset end = Offset(endX, endY);
      _lineOffsets.add(end);
    }
    _ranColor = DzyTheme.randomColor();
  }

  @override
  void initState() {
    super.initState();
    _textLength = widget.text.length ?? 4;
    _width = _textLength.toDouble() * 22;
    _height = 36;
    _ranStr = widget.text;
    _randLines();

    // initState 中设置回调后不可以调用 setState 方法否则报错,否则运行出错
    // widget.onTap(_ranDtr);
    // _changeCode();
  }

  void _changeCode() {
    _ranStr = randomAlphaNumeric(_textLength);
    widget.onTap(_ranStr);
    setState(() {
      _randLines();
    });
  }

  Container _subString(index) {
    // 首次返回对应字母
    // widget.currentStr(_ranDtr);
    return Container(
      padding: EdgeInsets.only(
          left: 2, right: 2, top: randomBetween(0, 14).toDouble()),
      child: Transform.rotate(
        angle: pi / randomBetween(3, 30) * randomBetween(-1, 1),
        child: Text(_ranStr[index],
            style: TextStyle(
                fontSize: randomBetween(16, 18).toDouble(),
                color: DzyTheme.randomColor())),
      ),
    );
  }

  Container _backLines() {
    // 父类模块和子类模块最少有一个设置大小

    return Container(
      width: _width,
      height: _height,
      child: CustomPaint(
        // size: Size(_width, _height),
        painter: CodePaint(_lineOffsets, _ranColor),
        foregroundPainter: CodePaint(_lineOffsets, _ranColor),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      width: _width,
      height: _height,
      color: Colors.grey[200],
      child: Stack(
        alignment: Alignment.center,
        children: [
          _backLines(),
          _backLines(),
          GestureDetector(
            behavior: HitTestBehavior.opaque,
            onTap: _changeCode,
            child: Container(
              width: _width,
              height: _height,
              child: Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: List.generate(_textLength, (int index) {
                  return _subString(index);
                }),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

背景实现的线条方案,此处的坑未解决,暂时留作记录就是会调用任何重绘组建的方法,判断监听的类别没有找到对应方法,所以实现的不是很好,只做一个好的问题记录

import 'dart:ui';
import 'package:flutter/material.dart';

class CodePaint extends CustomPainter {
  // 暂时没有找获取焦点后页面重绘的监听方法,所以外部传递
  final List lineOffsets;
  final Color ranColor;
  CodePaint(this.lineOffsets, this.ranColor);

  @override
  void paint(Canvas canvas, Size size) {
    debugPrint(canvas.runtimeType.toString());
    canvas.save();
    Paint _paint = Paint()
      ..color = ranColor //画笔颜色
      ..strokeCap = StrokeCap.round //画笔笔触类型
      ..isAntiAlias = true //是否启动抗锯齿
      ..blendMode = BlendMode.exclusion //颜色混合模式
      ..style = PaintingStyle.fill //绘画风格,默认为填充
      ..colorFilter = ColorFilter.mode(ranColor,
          BlendMode.exclusion) //颜色渲染模式,一般是矩阵效果来改变的,但是flutter中只能使用颜色混合模式
      ..maskFilter = MaskFilter.blur(BlurStyle.inner, 1.0) //模糊遮罩效果,flutter中只有这个
      ..filterQuality = FilterQuality.high //颜色渲染模式的质量
      // ..strokeWidth = randomBetween(1, 3).toDouble(); // 暂时固定
      ..strokeWidth = 1;

    final pointMode = PointMode.lines;
    canvas.drawPoints(pointMode, lineOffsets, _paint);
    canvas.restore();
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return false;
    // oldDelegate.points != points;
  }
}

最后还是放上一个懒人包
中间的两个问题,希望得到大牛的回复

你可能感兴趣的:(Flutter图片验证码本地封装)