簡體   English   中英

如何在Flutter中為容器小部件自定義/旋轉BoxDecoration?

[英]How can I customize / rotate a BoxDecoration for a Container widget in Flutter?

我有一個小工具,可為公交車站建立圓形的個人資料圖片,截至目前,它具有圍繞個人資料圖片的圓形邊框。 我想更改為虛線的圓形邊框,並通過以虛線形式在個人資料圖片上畫圈/旋轉來設置動畫。 有沒有簡單的方法可以做到這一點? 非常感謝您提供的任何幫助!

圓形輪廓圖片

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,
      ),
    ),
  ),
);

不幸的是, 簡單的答案是沒有簡單的方法可以做到這一點。 顫抖的人以其無窮的智慧得出的結論是,虛線的性能不足以將其包含在顫振中,因此,沒人會畫出虛線。 (是的,這句話的邏輯上的不連續是故意的。不要誤會我的意思-我喜歡撲撲,開發人員做得很好,但是他們似乎確實是根據性能而不是功能做出了一些半任意的決定。 )。

我所見的原因解釋是,基本上C ++版本會執行與dart代碼類似的操作(除非它直接在GPU上完成),因此他們期望有人最終在dart中實現虛線(可能作為一部分)圖書館?)。 有關進展和討論,請參見此github錯誤 ...,如果您以后希望看到破折號,請對其+1。 如果有足夠的人這樣做,那么最終撲朔迷離的人可能會決定實施它。

但是目前,這意味着沒有簡單的方法可以用虛線制作CircleBorder或任何其他類型的邊框。

但是,只要付出最大的努力 ,就可以准確地實現您想要的=)。 以下是為您提供所需功能的快速代碼。 請注意-它不是非常優化的,並且可能有更簡單的方法來執行此操作,並且您可能會使用裝飾並在其中或其他地方實現繪畫等……但這確實可行。

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);
  }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM