[-Flutter趣玩篇-] 出神入化的Align

工具的價值在於使用它的人,而非工具自身。會拿筆的人不少,但繪畫宗師寥寥無幾。--張風捷特烈bash


龍少(疑惑):Align這麼簡單,有什麼好講的。
捷特: 你會拿筆嗎?
龍少:你是在懷疑個人智商?我拿給你看:微信

捷特: 既然會拿筆,給我畫一張。
龍少: ...,我懷疑你在水文,並且我證據確鑿。
捷特: 這都被你發現了,水一頁可真不容易。less


1.Align的源碼

捷特: 你平時怎麼用Align?
龍少: 還能怎麼用,用鍵盤敲唄。Align中有一個alignment屬性,經過Alignment枚舉,能夠指定一個組件在容器中的相對位置,雖然挺好用,但也沒什麼要點,你肯定能水一篇?
捷特: 你肯定是枚舉。
龍少: 一共就9種類型,不是枚舉是什麼? (進入Alignment源碼)ide

class AlignTest extends StatelessWidget {
  AlignTest({Key key}) :super(key: key);
  
  @override
  Widget build(BuildContext context) {
    var childBox = Container(//孩子組件
      width: 40,
      height: 40,
      color: Colors.cyanAccent,
    );
    var childLayout = Align(//佈局組件Align
      alignment: Alignment.center,
      child: childBox,
    );
    
    return Container(//父親組件
      width: 110,
      height: 68,
      color: Colors.grey,
      child: childLayout,
    );
  }
}
複製代碼

龍少: 嗯?竟然是一個類,並且那些疑似枚舉的都是靜態常量。
捷特: so,Alignment的能力並不是僅是九種對齊方式,它是一種排布。
龍少: so... what?函數

class Alignment extends AlignmentGeometry {
  ...
  static const Alignment topLeft = Alignment(-1.0, -1.0);
  static const Alignment topCenter = Alignment(0.0, -1.0);
  static const Alignment topRight = Alignment(1.0, -1.0);
  static const Alignment centerLeft = Alignment(-1.0, 0.0);
  static const Alignment center = Alignment(0.0, 0.0);
  static const Alignment centerRight = Alignment(1.0, 0.0);
  static const Alignment bottomLeft = Alignment(-1.0, 1.0);
  static const Alignment bottomCenter = Alignment(0.0, 1.0);
  static const Alignment bottomRight = Alignment(1.0, 1.0);
複製代碼

捷特: 這樣就能很容易操縱元素的位置,如今有個需求,給你一批組件,讓他們安裝指定的函數曲線排布,你該怎麼辦?
龍少: 把刀拿來!我看看是哪一個不走心的提的需求...
捷特: 淡定淡定,先看如何完成sin定位組件位置。這裏用一個Slider演示一下數據變化時的效果工具

捷特: 先準備一個小球組件,可指定大小和顏色:佈局

class Ball extends StatelessWidget {
  Ball({Key key, this.radius=15, this.color=Colors.blue,}) :super(key: key);
  final double radius; //半徑
  final Color color; //顏色

  @override
  Widget build(BuildContext context) {
    return Container(
      width: radius*2,
      height: radius*2,
      decoration: BoxDecoration(
        shape: BoxShape.circle,
        color: color,
      ),
    );
  }
}
複製代碼

龍少: 嗯?有點意思,確實挺巧妙,爲何有種想打你一頓的衝動post

class SinLayout extends StatefulWidget {
  SinLayout({Key key,}) : super(key: key);
  @override
  _SinLayoutState createState() => _SinLayoutState();
}

class _SinLayoutState extends State<SinLayout> {
  var _x=0.0;//Alignment座標系上的x座標

  @override
  Widget build(BuildContext context) {
    var item=   Container(
      width: 300,
      height: 200,
      color: Colors.black.withAlpha(10),
      child: Align(
        child: Ball(color: Colors.orangeAccent,),
        alignment: Alignment(_x,f(_x*pi)), //<--- 根據_x聯動y,肯定位置
      ),
    );

    var slider=Slider(
        max: 180,
        min: -180,
        divisions:360,
        label: "${_x.toStringAsFixed(2)}π",
        value: _x*180,
        onChanged: (v) {
          setState(() {_x=v/180;});//拖動時更新橫座標
        });
    return Column(
      mainAxisSize: MainAxisSize.min,
      children: <Widget>[slider, item],
    );
  }

  double f(x) {//映射函數 -- 可隨意指定
    double y = sin(x);
    return y;
  }
}

複製代碼

如今封裝一個sin圖像的位置擺放組件ui

class SinPlace extends StatelessWidget {
  SinPlace({Key key, this.child,this.t=0}) : super(key: key);

  final Widget child;
  final double t;

  @override
  Widget build(BuildContext context) {
    return   Container(
        child:Align(
          child: child,
          alignment: Alignment(t,g(t*pi)), //<--- 根據——x聯動y,肯定位置
        ));
  }

  double g(t) {//映射函數 -- 可隨意指定
    double y = 0.5*sin(t);
    return y;
  }
}
複製代碼

經過Stack進行擺放this

class SinLayout extends StatelessWidget {
  SinLayout({Key key, this.items}) :super(key: key);
  
  final Map<double,Widget> items;

  @override
  Widget build(BuildContext context) => Stack(
      children: items.keys.toList().map((key)=>
        SinPlace(t: key,child: items[key],)).toList() ,
    );
}
複製代碼

使用items傳入便可

var items=<double,Widget>{
    -0.2:CircleAvatar(backgroundImage:AssetImage("images/caver.jpeg") ,),
    -0.4:CircleAvatar(backgroundImage:AssetImage("images/honor.png") ,),
    -0.6:CircleAvatar(backgroundImage:AssetImage("images/caver.jpeg") ,),
    -0.8:CircleAvatar(backgroundImage:AssetImage("images/leaf.png") ,),
    -1:CircleAvatar(backgroundImage:AssetImage("images/caver.jpeg") ,),
    0:CircleAvatar(backgroundImage:AssetImage("images/icon_head.png") ,),
    0.2:CircleAvatar(backgroundImage:AssetImage("images/caver.jpeg") ,),
    0.4:CircleAvatar(backgroundImage:AssetImage("images/wy_200x300.jpg") ,),
    0.6:CircleAvatar(backgroundImage:AssetImage("images/caver.jpeg") ,),
    0.8:CircleAvatar(backgroundImage:AssetImage("images/icon_head.png") ,),
    1:CircleAvatar(backgroundImage:AssetImage("images/caver.jpeg") ,),
  };

複製代碼

也許你看出來了,其實就是一個函數而已,因此能夠它還能更強大,徹底能夠封成個自定義函數圖像排列。根據參數方程的形式來構造函數,經過f和g

typedef FunNum1=Function(double t );

class MathPlace extends StatelessWidget {
  MathPlace({Key key, this.child,this.t=0,this.f,this.g}) : super(key: key);

  final Widget child;
  final FunNum1 f;
  final FunNum1 g;
  final double t;

  @override
  Widget build(BuildContext context) {

    var result=   Container(
        child:Align(
          child: child,
          alignment: Alignment(f(t),g(t)), //<--- 根據——x聯動y,肯定位置
        ));
    return  result;
  }
}

class MathLayout extends StatelessWidget {
  MathLayout({Key key, this.items,this.f,this.g}) :super(key: key);
  final FunNum1 f;
  final FunNum1 g;
  final Map<double,Widget> items;

  @override
  Widget build(BuildContext context) => Stack(
    children: items.keys.toList().map((key)=>MathPlace(t: key,child: items[key],f: f,g: g,)).toList() ,
  );
}
複製代碼

圓形排布,小意思

Container(
    width: 350,
    height: 350,
    child: MathLayout(
            items: items,
            f: (t) => cos(t * pi),
             g: (t) => sin(t * pi),
))
複製代碼

橢圓排布,好說

Container(
    width: 350,
    height: 350,
    child: MathLayout(
      items: items,
      f: (t) => 0.8*sin(t * pi),
      g: (t) => 0.6*cos(t * pi),
    )),
,
複製代碼

龍少: 好吧,我要去小學從新學數學。(手動笑哭)


本文到此接近尾聲了,若是想快速嚐鮮Flutter,《Flutter七日》會是你的必備佳品;若是想細細探究它,那就跟隨個人腳步,完成一次Flutter之旅。
另外本人有一個Flutter微信交流羣,歡迎小夥伴加入,共同探討Flutter的問題,本人微信號:zdl1994328,期待與你的交流與切磋。

滿紙荒唐言,一把辛酸淚。都言做者癡,誰解其中味。

相關文章
相關標籤/搜索