Flutter仿QQ討論組頭像

前言

上篇文章分享了Flutter仿微信/微博九宮格。已實現(xiàn)類似微信/微博展示圖片九宮格,拖拽排序,微信群組頭像,釘釘群組頭像。
本次分享Flutter實現(xiàn)仿QQ討論組頭像.

參考資料

計算圓的半徑,這里直接參考的YiiGuxing的CompositionAvatar項目,文章。
View寬D,藍色小圓半徑r,紅色大圓半徑R,Y軸上偏移量dy,頭像數(shù)量n。

正文

一、計算每個小圓的中心坐標

  1. 首先需要得到大圓中心坐標。這里頭像數(shù)量n為3為例。
//中心坐標x。
double centerX = width / 2;
//中心坐標y, 因為3和5在y軸上有偏移量,需要單獨計算。
double centerY = width / 2;
//小圓半徑。
double r;
//大圓中心到小圓中心的半徑。
double r1;
switch (n) {
  case 3:
    r = width / (2 + 4 * math.sin(math.pi * (n - 2) / (2 * n)));
    r1 = r / math.cos(math.pi * (n - 2) / (2 * n));
    double R = r * (1 + math.sin(math.pi / n)) / math.sin(math.pi / n);
    double dy = 0.5 * (width - R - r * (1 + 1 / math.tan(math.pi / n)));
    centerY = dy + r + r1;
    break;    
}
  1. 圓心坐標通用公式,當n為2和4的時候初始角度為-45度。
for (int i = 0; i < n; i++) {
  double degree1 = (n == 2 || n == 4) ? (-math.pi / 4) : 0;
  double x = centerX + r1 * math.sin(degree1 + i * 2 * math.pi / n);
  double y = centerY - r1 * math.cos(degree1 + i * 2 * math.pi / n);
}

二、如何實現(xiàn)圓弧缺口

使用ClipPath組件,自定義clipper。

class QQClipper extends CustomClipper<Path> {
  QQClipper({
    this.total,
    this.index,
    this.initIndex: 1,
    this.previousX,
    this.previousY,
    this.degree,
    this.arcAngle: 60,
  }) : assert(arcAngle != null && arcAngle >= 0 && arcAngle <= 180);
  //頭像數(shù)量。
  final int total;
  //頭像index。
  final int index;
  //頭像initIndex。
  final int initIndex;
  //上一個圓心坐標x。
  final double previousX;
  //上一個圓心坐標y。
  final double previousY;
  //圓弧中心角度。
  final double degree;
  //圓弧角度。
  final double arcAngle;

  @override
  Path getClip(Size size) {
    double r = size.width / 2;
    Path path = Path();
    List<Offset> points = List();
    //頭像數(shù)量為2,頭像index為initIndex時,保持整圓。
    if (total == 2 && index == initIndex) {
      path.addOval(Rect.fromLTRB(0, 0, size.width, size.height));
    } else {
      //圓弧路徑坐標。
      double spaceA = arcAngle / 2;
      double startA = degree + spaceA;
      double endA = degree - spaceA;
      for (double i = startA; i <= 360 + endA; i = i + 1) {
        double x1 = r + r * math.sin(d2r(i));
        double y1 = r - r * math.cos(d2r(i));
        points.add(Offset(x1, y1));
      }

      //圓弧缺口路徑坐標。
      double spaceB = math.atan(
              r * math.sin(d2r(spaceA)) / (2 * r - r * math.cos(d2r(spaceA)))) /
          math.pi *
          180;
      double r1 = (2 * r - r * math.cos(d2r(spaceA))) / math.cos(d2r(spaceB));
      double startB = degree - 180 - spaceB;
      double endB = degree - 180 + spaceB;
      List<Offset> pointsB = List();
      for (double i = startB; i < endB; i = i + 1) {
        double x1 = previousX + r1 * math.sin(d2r(i));
        double y1 = previousY - r1 * math.cos(d2r(i));
        pointsB.add(Offset(x1, y1));
      }
      points.addAll(pointsB.reversed);
      path.addPolygon(points, true);
    }
    return path;
  }

  /// degree to radian.
  double d2r(double degree) {
    return degree / 180 * math.pi;
  }

  @override
  bool shouldReclip(CustomClipper<Path> oldClipper) {
    return this != oldClipper;
  }
}

Screenshots

GitHub

nine_grid_view

關于作者

GitHub : Sky24n
掘金 ????: Sky24n
簡書 ????: Sky24n

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內容