【问题标题】:How to draw a Widget on a Canvas?如何在画布上绘制小部件?
【发布时间】:2019-10-31 21:55:31
【问题描述】:

我正在尝试自定义滑块小部件以具有自定义拇指形状。 为了做到这一点,我必须扩展SliderComponentShape。 这个类需要我实现自己的paint方法。 paint 方法只给了我一个Canvas 供我使用。 不幸的是,我想使用的拇指形状相当复杂。 手动绘制它会相当乏味,而使用颤振小部件构建它会容易得多。 有没有办法将Widget 绘制成Canvas

【问题讨论】:

    标签: flutter flutter-layout


    【解决方案1】:

    您可以使用图像或矢量可绘制作为拇指图像,并降低绘画的复杂性。

    例如获取如下地图滑块

    您可以使用以下代码,并将图像文件用作拇指图标

     class DistanceSlider extends StatefulWidget {
      const DistanceSlider({
        Key key,
        @required this.imageUrl,
        @required this.minDistance,
        @required this.maxDistance,
      }) : super(key: key);
      final String imageUrl;
      final double maxDistance;
      final double minDistance;
    
      @override
      _DistanceSliderState createState() => _DistanceSliderState();
    }
    
    class _DistanceSliderState extends State<DistanceSlider> {
      double distance = 20;
    
      ui.Image customImage;
      Future<ui.Image> loadImage(String imageUrl) async {
        ByteData data = await rootBundle.load(imageUrl);
        ui.Codec codec = await ui.instantiateImageCodec(data.buffer.asUint8List());
        ui.FrameInfo fi = await codec.getNextFrame();
        return fi.image;
      }
    
      @override
      void initState() {
        loadImage(widget.imageUrl).then((image) {
          setState(() {
            customImage = image;
          });
        });
        super.initState();
      }
    
      @override
      Widget build(BuildContext context) {
        return Container(
          child: SliderTheme(
            data: SliderThemeData(
              trackHeight: 8,
              thumbShape: SliderThumbImage(
                  image: customImage,
                  thumbRadius: 0,
                  max: widget.maxDistance.toInt()),
              overlayColor: kSecondaryColorLight.withAlpha(32),
              overlayShape: RoundSliderOverlayShape(overlayRadius: 28.0),
              activeTrackColor: kSecondaryColorDark,
              inactiveTrackColor: kSecondaryColorLight.withOpacity(0.5),
              valueIndicatorShape: PaddleSliderValueIndicatorShape(),
              valueIndicatorTextStyle: TextStyle(
                color: Colors.white,
              ),
              valueIndicatorColor: Colors.white,
            ),
            child: Stack(
              children: <Widget>[
                Slider(
                  label: distance.abs().toString(),
                  value: distance,
                  min: widget.minDistance,
                  max: widget.maxDistance,
                  onChanged: (value) {
                    setState(() {
                      distance = value;
                    });
                  },
                ),
                Container(
                  margin: EdgeInsets.only(left: 25, right: 25, top: 40),
                  child: Row(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    crossAxisAlignment: CrossAxisAlignment.center,
                    children: <Widget>[
                      Text(widget.minDistance.toInt().toString()),
                      Text(widget.maxDistance.toInt().toString())
                    ],
                  ),
                ),
              ],
            ),
          ),
        );
      }
    }
    
    class SliderThumbImage extends SliderComponentShape {
      final ui.Image image;
      final double thumbRadius;
      final int max;
      SliderThumbImage({this.image, this.thumbRadius, this.max});
    
      @override
      Size getPreferredSize(bool isEnabled, bool isDiscrete) {
        return Size.fromRadius(thumbRadius);
      }
    
      @override
      void paint(PaintingContext context, Offset center,
          {Animation<double> activationAnimation,
          Animation<double> enableAnimation,
          bool isDiscrete,
          TextPainter labelPainter,
          RenderBox parentBox,
          SliderThemeData sliderTheme,
          TextDirection textDirection,
          double value}) {
        final canvas = context.canvas;
        final imageWidth = image?.width ?? 10;
        final imageHeight = image?.height ?? 10;
    
        Offset imageOffset = Offset(
          center.dx - (imageWidth / 2),
          center.dy - (imageHeight / 0.935),
        );
    
        Paint paint = Paint()..filterQuality = FilterQuality.high;
    
        if (image != null) {
          canvas.drawImage(image, imageOffset, paint);
        }
    
        TextSpan span = new TextSpan(
            style: new TextStyle(
                fontSize: imageHeight * .3,
                fontWeight: FontWeight.w700,
                color: sliderTheme.valueIndicatorColor,
                height: 0.9),
            text: '${getValue(value)}');
        TextPainter tp = new TextPainter(
            text: span,
            textAlign: TextAlign.left,
            textDirection: TextDirection.ltr);
        tp.layout();
        Offset textCenter = Offset(
          center.dx - (tp.width / 2),
          center.dy - (tp.height / 0.32),
        );
        tp.paint(canvas, textCenter);
      }
    
      String getValue(double value) {
        return ((max * value).round()).toString();
      }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-16
      • 2021-07-15
      • 2023-03-14
      • 1970-01-01
      相关资源
      最近更新 更多