【Flutter 實戰】各類各樣形狀的組件

老孟導讀:Flutter中不少組件都有一個叫作shape的屬性,類型是ShapeBorder,好比Button類、Card等組件,shape表示控件的形狀,系統已經爲咱們提供了不少形狀,對於沒有此屬性的組件,可使用 Clip 類組件進行裁減。git

BeveledRectangleBorder

斜角矩形邊框,用法以下:微信

RaisedButton(
  shape: BeveledRectangleBorder(
      side: BorderSide(width: 1, color: Colors.red),
      borderRadius: BorderRadius.circular(10)),
  child: Text('老孟'),
  onPressed: () {},
)

image-20200522172909192

若是設置的半徑比控件還大,就會變成菱形ide

3RaisedButton(
  shape: BeveledRectangleBorder(
      side: BorderSide(width: 1, color: Colors.red),
      borderRadius: BorderRadius.circular(100)),
  child: Text('老孟'),
  onPressed: () {},
)

image-20200522173147073

同理,若是半徑設置爲0,就是矩形。性能

RaisedButton(
  shape: BeveledRectangleBorder(
      side: BorderSide(width: 1, color: Colors.red),
      borderRadius: BorderRadius.circular(0)),
  child: Text('老孟'),
  onPressed: () {},
)

image-20200522173458904

Border

Border容許單獨設置每個邊上的線條樣式.動畫

RaisedButton(
  shape: Border(
    top: BorderSide(color: Colors.red,width: 2)
  ),
  child: Text('老孟'),
  onPressed: () {},
)

image-20200522173801387

設置所有ui

RaisedButton(
        shape: Border(
          top: BorderSide(color: Colors.red,width: 10),
          right: BorderSide(color: Colors.blue,width: 10),
          bottom: BorderSide(color: Colors.yellow,width: 10),
          left: BorderSide(color: Colors.green,width: 10),
        ),
        child: Text('老孟'),
        onPressed: () {},
      )

image-20200522182443777

BorderDirectional

BorderDirectionalBorder基本同樣,區別就是BorderDirectional帶有閱讀方向,大部分國家閱讀是從左到右,但有的國家是從右到左的,好比阿拉伯等。this

RaisedButton(
  shape: BorderDirectional(
    start: BorderSide(color: Colors.red,width: 2),
    end: BorderSide(color: Colors.blue,width: 2),
  ),
  child: Text('老孟'),
  onPressed: () {},
)

image-20200522182150780

CircleBorder

圓形code

RaisedButton(
  shape: CircleBorder(side: BorderSide(color: Colors.red)),
  child: Text('老孟'),
  onPressed: () {},
)

image-20200522182549205

ContinuousRectangleBorder

連續的圓角矩形,直線和圓角平滑連續的過渡,和RoundedRectangleBorder相比,圓角效果會小一些。blog

RaisedButton(
  shape: ContinuousRectangleBorder(
      side: BorderSide(color: Colors.red),
      borderRadius: BorderRadius.circular(20)),
  child: Text('老孟'),
  onPressed: () {},
)

image-20200522182922984

RoundedRectangleBorder

圓角矩形ip

RaisedButton(
  shape: RoundedRectangleBorder(
      side: BorderSide(color: Colors.red),
      borderRadius: BorderRadius.circular(10)),
  child: Text('老孟'),
  onPressed: () {},
)

image-20200522183032650

StadiumBorder

相似足球場的形狀,兩邊圓形,中間矩形

RaisedButton(
  shape: StadiumBorder(
      side: BorderSide(color: Colors.red),),
  child: Text('老孟'),
  onPressed: () {},
)

image-20200522183814823

OutlineInputBorder

帶外邊框

RaisedButton(
  shape: OutlineInputBorder(
    borderSide: BorderSide(color: Colors.red),
    borderRadius: BorderRadius.circular(10),
  ),
  child: Text('老孟'),
  onPressed: () {},
)

image-20200522184044810

UnderlineInputBorder

下劃線邊框

RaisedButton(
  shape: UnderlineInputBorder(
    borderSide: BorderSide(color: Colors.red),
  ),
  child: Text('老孟'),
  onPressed: () {},
)

image-20200522184216659

ClipRect

ClipRect組件使用矩形裁剪子組件,一般狀況下,ClipRect做用於CustomPaintCustomSingleChildLayoutCustomMultiChildLayoutAlignCenterOverflowBoxSizedOverflowBox組件,例如ClipRect做用於Align,能夠僅顯示上半部分,代碼以下:

ClipRect(
  child: Align(
    alignment: Alignment.topCenter,
    heightFactor: 0.5,
    child: Container(
      height: 150,
      width: 150,
      child: Image.asset(
        'images/1.png',
        fit: BoxFit.cover,
      ),
    ),
  ),
)

全圖效果:

裁剪效果:

clipper參數定義裁剪規則,下面具體介紹。

clipBehavior參數定義了裁剪的方式,只有子控件超出父控件的範圍纔有裁剪的說法,各個方式說明以下:

  • none:不裁剪,系統默認值,若是子組件不超出邊界,此值沒有任何性能消耗。
  • hardEdge:裁剪但不該用抗鋸齒,速度比none慢一點,但比其餘方式快。
  • antiAlias:裁剪並且抗鋸齒,此方式看起來更平滑,比antiAliasWithSaveLayer快,比hardEdge慢,一般用於處理圓形和弧形裁剪。
  • antiAliasWithSaveLayer:裁剪、抗鋸齒並且有一個緩衝區,此方式很慢,用到的狀況比較少。

ClipRRect

ClipRRect組件能夠對子組件進行圓角裁剪,默認圓角半徑爲0,注意ClipRRect有2個R,不是上面介紹的ClipRect。

用法以下:

ClipRRect(
  borderRadius: BorderRadius.circular(20),
  child: Container(
    height: 150,
    width: 150,
    child: Image.asset(
      'images/1.png',
      fit: BoxFit.cover,
    ),
  ),
)

效果如圖:

ClipOval

ClipOval裁剪爲橢圓形,橢圓形的大小爲正切父組件,所以若是父組件爲正方形,切出來是圓形,用法以下:

ClipOval(
  child: Container(
    height: 150,
    width: 250,
    child: Image.asset(
      'images/1.png',
      fit: BoxFit.cover,
    ),
  ),
)

效果以下:

ClipPath

ClipPath組件根據路徑進行裁剪,咱們自定義裁剪路徑也可使用系統提供的,用法以下:

ClipPath.shape(
  shape: StadiumBorder(),
  child: Container(
    height: 150,
    width: 250,
    child: Image.asset(
      'images/1.png',
      fit: BoxFit.cover,
    ),
  ),
)

shape參數是ShapeBorder類型,系統已經定義了不少形狀,介紹以下:

  • RoundedRectangleBorder:圓角矩形

  • ContinuousRectangleBorder:直線和圓角平滑連續的過渡,和RoundedRectangleBorder相比,圓角效果會小一些。

  • StadiumBorder:相似於足球場的形狀,兩端半圓。

  • BeveledRectangleBorder:斜角矩形。效果如圖:

  • CircleBorder:圓形。

CustomClipper

CustomClipper並非一個組件,而是一個abstract(抽象)類,使用CustomClipper能夠繪製出任何咱們想要的形狀,好比三角形,代碼以下:

@override
Widget build(BuildContext context) {
  return Center(
    child: ClipPath(
      clipper: TrianglePath(),
      child: Container(
        height: 150,
        width: 250,
        child: Image.asset(
          'images/1.png',
          fit: BoxFit.cover,
        ),
      ),
    ),
  );
}

自定義TrianglePath代碼以下:

class TrianglePath extends CustomClipper<Path>{
  @override
  Path getClip(Size size) {
    var path = Path();
    path.moveTo(size.width/2, 0);
    path.lineTo(0, size.height);
    path.lineTo(size.width, size.height);
    return path;
  }

  @override
  bool shouldReclip(CustomClipper<Path> oldClipper) {
    return true;
  }
}

效果以下:

咱們還能夠繪製五角星,代碼以下:

class StarPath extends CustomClipper<Path> {
  StarPath({this.scale = 2.5});

  final double scale;

  double perDegree = 36;

  /// 角度轉弧度公式
  double degree2Radian(double degree) {
    return (pi * degree / 180);
  }

  @override
  Path getClip(Size size) {
    var R = min(size.width / 2, size.height / 2);
    var r = R / scale;
    var x = size.width / 2;
    var y = size.height / 2;

    var path = Path();
    path.moveTo(x, y - R);
    path.lineTo(x - sin(degree2Radian(perDegree)) * r,
        y - cos(degree2Radian(perDegree)) * r);
    path.lineTo(x - sin(degree2Radian(perDegree * 2)) * R,
        y - cos(degree2Radian(perDegree * 2)) * R);
    path.lineTo(x - sin(degree2Radian(perDegree * 3)) * r,
        y - cos(degree2Radian(perDegree * 3)) * r);
    path.lineTo(x - sin(degree2Radian(perDegree * 4)) * R,
        y - cos(degree2Radian(perDegree * 4)) * R);
    path.lineTo(x - sin(degree2Radian(perDegree * 5)) * r,
        y - cos(degree2Radian(perDegree * 5)) * r);
    path.lineTo(x - sin(degree2Radian(perDegree * 6)) * R,
        y - cos(degree2Radian(perDegree * 6)) * R);
    path.lineTo(x - sin(degree2Radian(perDegree * 7)) * r,
        y - cos(degree2Radian(perDegree * 7)) * r);
    path.lineTo(x - sin(degree2Radian(perDegree * 8)) * R,
        y - cos(degree2Radian(perDegree * 8)) * R);
    path.lineTo(x - sin(degree2Radian(perDegree * 9)) * r,
        y - cos(degree2Radian(perDegree * 9)) * r);
    path.lineTo(x - sin(degree2Radian(perDegree * 10)) * R,
        y - cos(degree2Radian(perDegree * 10)) * R);
    return path;
  }

  @override
  bool shouldReclip(StarPath oldClipper) {
    return oldClipper.scale != this.scale;
  }
}

scale參數表示間隔的點到圓心的縮放比例,五角星效果以下:

下面用動畫動態設置scale,代碼以下:

class StartClip extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _StartClipState();
}

class _StartClipState extends State<StartClip>
    with SingleTickerProviderStateMixin {
  AnimationController _controller;
  Animation _animation;

  @override
  void initState() {
    _controller =
        AnimationController(duration: Duration(seconds: 2), vsync: this)
          ..addStatusListener((status) {
            if (status == AnimationStatus.completed) {
              _controller.reverse();
            } else if (status == AnimationStatus.dismissed) {
              _controller.forward();
            }
          });
    _animation = Tween(begin: 1.0, end: 4.0).animate(_controller);
    _controller.forward();
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Center(
      child: AnimatedBuilder(
          animation: _animation,
          builder: (context, child) {
            return ClipPath(
              clipper: StarPath(scale: _animation.value),
              child: Container(
                height: 150,
                width: 150,
                color: Colors.red,
              ),
            );
          }),
    );
  }
}

效果以下:

交流

老孟Flutter博客地址(330個控件用法):http://laomengit.com

歡迎加入Flutter交流羣(微信:laomengit)、關注公衆號【老孟Flutter】:

相關文章
相關標籤/搜索