如何在Flutter中为容器小部件自定义/旋转BoxDecoration? [英] How can I customize / rotate a BoxDecoration for a Container widget in Flutter?

查看:61
本文介绍了如何在Flutter中为容器小部件自定义/旋转BoxDecoration?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个小工具,可为公交车站建立圆形的个人资料图片,截至目前,它具有围绕个人资料图片的圆形边框.我想更改为虚线的圆形边框,并通过以虚线形式在个人资料图片上画圈/旋转来设置动画.有没有简单的方法可以做到这一点?非常感谢您提供的任何帮助!

I have a Widget that builds a circular profile picture for bus stops, and as of right now it has a circular border surrounding the profile picture like such. I want to change the circular border to be dashed instead and to also animate by circling/rotating around the profile picture in its dashed form. Is there any easy way to do that? Thanks so much for any help you can provide!

return new Transform(
  transform: new Matrix4.diagonal3Values(
    animation.avatarSize.value,
    animation.avatarSize.value,
    1.0,
  ),
  alignment: Alignment.center,
  child: new Container(
    width: 110.0,
    height: 110.0,
    decoration: new BoxDecoration(
      shape: BoxShape.circle,
      border: new Border.all(
        color: Colors.white30,
      ),
    ),
    margin: const EdgeInsets.only(
      top: 24.0,
      left: 16.0,
    ),
    padding: const EdgeInsets.all(3.0),
    child: new ClipOval(
      child: new Image.asset(
        stopName.avatar,
      ),
    ),
  ),
);

推荐答案

不幸的是,简单答案是没有简单的方法可以做到这一点.颤抖的人以其无穷的智慧得出的结论是,虚线的性能不足以包含在颤振中,因此没有人会画虚线. (是的,这句话的逻辑上的不连续是故意的.不要误会我的意思-我喜欢扑扑,开发人员做得很好,但是他们似乎确实是根据性能而不是功能做出了一些半任意的决定. ).

Unfortunately the simple answer is that there is no easy way to do that. The flutter people in their infinite wisdom have made the conclusion that dashed lines are not performant enough to be included in flutter and therefore no-one will ever need to draw a dashed line. (Yes, the logical discontinuity in that sentence is intended. Don't get me wrong - I love flutter and the devs have done a great job, but they do seem to have made a few semi-arbitrary decisions based on performance rather than functionality).

我所见的原因解释是,基本上C ++版本会执行与dart代码类似的操作(除非直接在GPU上完成),因此他们希望有人最终在dart中实现虚线(可能作为图书馆的一部分?).有关进展和讨论,请参见此github错误……并根据需要对其进行+1看看将来会有破折号.如果有足够的人这样做,那么最终扑朔迷离的人可能会决定实施它.

The interpretation I've seen of why is that basically the C++ version would be doing something similar to dart code (unless it were done directly on the GPU), and so they expect someone to eventually implement dashed lines in dart instead (possibly as part of a library?). See this github bug for progress and discussion... and +1 it if you want to see dashes in future. If enough people do that then eventually the flutter people may decide to implement it.

但是目前,这意味着没有简单的方法可以用虚线制作CircleBorder或任何其他类型的边框.

But for now, that means that there is no easy way to make CircleBorder, or any other type of border, with a dashed line.

但是,只要付出最大的努力,就可以准确地实现您想要的目标=).以下是为您提供所需功能的快速代码.请注意-它不是非常优化的,并且可能有更简单的方法来执行此操作,并且您可能在这里或其他地方使用装饰并实现绘画等……但这确实可行.

However, with maximum effort, exactly what you want can be achieved =). Below is a quick cut of the code for you that does what you want. Be warned - it isn't very optimized, and there are probably easier ways to do it, and you could probably use a Decoration and implement the paint etc there or something... but this does work.

import 'dart:math';

import 'package:flutter/material.dart';

void main() => runApp(new MyApp());

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: new SafeArea(
        child: Column(
          children: [
            new DashedCircle(
              child: new ClippedDrawing(),
            )
          ],
        ),
      ),
    );
  }
}

class ClippedDrawing extends StatelessWidget {
  @override
  Widget build(BuildContext context) => new ClipOval(
        child: new Container(
          color: Colors.red,
        ),
      );
}

class DashedCircle extends StatefulWidget {
  final Widget child;

  const DashedCircle({Key key, this.child}) : super(key: key);

  @override
  DashedBorderState createState() => new DashedBorderState();
}

class DashedBorderState extends State<DashedCircle> with TickerProviderStateMixin<DashedCircle> {
  AnimationController controller;
  Animation<double> animation;

  @override
  void initState() {
    super.initState();
    controller = new AnimationController(vsync: this, duration: Duration(seconds: 10));
    animation = new Tween(begin: 0.0, end: pi * 2.0).animate(controller);
    controller.repeat();
  }

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: animation,
      builder: (context, child) {
        return new CustomPaint(
          painter: OvalPainter(
              color: Colors.blue, borderWidth: 1.0, dashLength: 5.0, spaceLength: 2.0, offset: animation.value),
          child: child,
        );
      },
      child: Container(
        width: 110.0,
        height: 110.0,
        padding: EdgeInsets.all(3.0),
        child: widget.child,
      ),
    );
  }
}

class OvalPainter extends CustomPainter {
  final Color color;
  final double borderWidth;
  final double dashLength;
  final double spaceLength;
  final double offset;

  OvalPainter(
      {@required this.borderWidth,
      @required this.dashLength,
      @required this.spaceLength,
      @required this.offset,
      @required this.color});

  double lastShortestSide;
  double lastDashLength;
  double lastSpaceLength;

  Path lastPath;

  @override
  void paint(Canvas canvas, Size size) {
    Rect rect = Offset.zero & size;

    var radius = rect.shortestSide / 2;

    canvas.translate(radius, radius);
    canvas.rotate(offset);

    Path path;
    if (lastShortestSide == rect.shortestSide &&
        dashLength == lastDashLength &&
        spaceLength == lastSpaceLength &&
        lastPath != null) {
      path = lastPath;
    } else {
      path = _getDashedCircularPath(rect.shortestSide / 2, dashLength, spaceLength);
      lastPath = path;
      lastShortestSide = rect.shortestSide;
      lastDashLength = dashLength;
      lastSpaceLength = spaceLength;
    }

    canvas.drawPath(
      path,
      new Paint()
        ..style = PaintingStyle.stroke
        ..color = color
        ..strokeWidth = borderWidth,
    );
  }

  @override
  bool shouldRepaint(OvalPainter oldDelegate) {
    return offset != oldDelegate.offset ||
        color != oldDelegate.color ||
        borderWidth != oldDelegate.borderWidth ||
        dashLength != oldDelegate.dashLength ||
        spaceLength != oldDelegate.spaceLength;
  }

  static Path _getDashedCircularPathFromNumber(double radius, int numSections, double dashPercentage) {
    var tau = 2 * pi;
    var actualTotalLength = tau / numSections;
    var actualDashLength = actualTotalLength * dashPercentage;

    double offset = 0.0;
    Rect rect = new Rect.fromCircle(center: Offset.zero, radius: radius);

    Path path = new Path();
    for (int i = 0; i < numSections; ++i) {
      path.arcTo(rect, offset, actualDashLength, true);
      offset += actualTotalLength;
    }

    return path;
  }

  static Path _getDashedCircularPath(double radius, double dashLength, double spaceLength) {
    // first, find number of radians that dashlength + spacelength take
    var tau = 2 * pi;
    var circumference = radius * tau;
    var dashSpaceLength = dashLength + spaceLength;
    var num = circumference / (dashSpaceLength);
    // we'll floor the value so that it's close-ish to the same amount as requested but
    // instead will be the same all around
    var closeNum = num.floor();

    return _getDashedCircularPathFromNumber(radius, closeNum, dashLength / dashSpaceLength);
  }
}

这篇关于如何在Flutter中为容器小部件自定义/旋转BoxDecoration?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆