Flutter炫酷ui

ui.png

在閑暇沖浪的時候宵呛,無意間看到了這張設(shè)計圖,眼睛一亮夕凝,感覺這個設(shè)計和創(chuàng)意非潮λ耄酷,打算著手實現(xiàn)一下码秉。關(guān)于設(shè)計圖的作者沒找到逮矛,如果有人知道的話,請告知我转砖,我會添加設(shè)計引用的须鼎,歡迎來我的Github

源碼Github

視頻地址

實戰(zhàn)抖音

分析設(shè)計,我們分兩部分來實現(xiàn):1.表盤部分 2.下部的開關(guān)部分府蔗。以下為了省略的邏輯代碼晋控,需要完整的代碼的請移步Github

1.表盤部分

1.1 觀察表盤的樣式,把需要做的任務(wù)劃分

  • 漸變的背景姓赤,用作秒針
  • 繪制白色的小圓點
  • 繪制帶陰影的黃色大圓點赡译,用作時針
  • 繪制時間文字
  • 開啟定時器,讓時鐘動起來
    表盤部分很多都是需要我們自己繪制的不铆,這里我們可以使用CustomPaint來實現(xiàn)所有的繪制蝌焚。
    CustomPaint提供了自定義widget的能力,它會暴露一個canvas誓斥,可以通過這個canvas來繪制widget只洒,有沒有很熟悉,跟原生android的canvas是不是很相似劳坑。
    我們這里將表盤作為背景來繪制毕谴,也就是painter屬性,自定義CustomPainter,重寫paint(Canvas canvas,Size size)和shouldRepaint(covariant CustomPainter oldDelegate)函數(shù)析珊,來完成我們所有的繪制操作羡鸥。好的,讓我們愉快的開始吧o( ̄▽ ̄)ブ忠寻。

1.2 漸變的背景惧浴,用作秒針

從圖中我們可以知道,漸變色是掃描漸變奕剃,并布滿屏幕衷旅,同時位置在整個屏幕的上半部分。首先創(chuàng)建掃描漸變對象纵朋,這個掃描漸變可以創(chuàng)建出一個著色器柿顶,然后我們將這個著色器附著在一個畫筆上,通過畫布去繪制操软。注意畫布繪制時canvas.save()和canvas.restore()在對應(yīng)時機的調(diào)用嘁锯。要讓秒針動起來,需要開啟一個Timer定時任務(wù)聂薪,每一秒刷新一下視圖家乘。

    var circle = Rect.fromCircle(center: Offset(0, 0), radius: _screenHeight);
    //掃面漸變
    var sweepGradient = SweepGradient(
      colors: [
        _startColor,
        _endColor
      ],
    );
    //畫筆對象
   Paint  _paintGradient = Paint()
      ..isAntiAlias = true
      ..shader = sweepGradient.createShader(circle)
      ..style = PaintingStyle.fill;

    //獲取當前的時間
    DateTime dateTime = DateTime.now();
    var hour = dateTime.hour;
    var minute = dateTime.minute;
    var second = dateTime.second;
    //畫布位移
    canvas.translate(_screenWidth / 2, _screenHeight / 100 * 35);
    //繪制漸變背景
    canvas.save();
    //每秒旋轉(zhuǎn)對應(yīng)角度,模擬秒針移動
    canvas.rotate(_getRotate(second));
    canvas.drawCircle(Offset(0, 0), _screenHeight, _paintGradient);
    canvas.restore();
漸變的背景.gif

1.3 繪制白色的小圓點

這里需要繪制24個白色小圓點藏澳,平均分360度,通過畫布的旋轉(zhuǎn)來繪制不同角度的白色小圓點仁锯。

for (double i = 0; i < _numPoint; i++) {
      canvas.save();
      //
      double deg = 360 / _numPoint * i;
      canvas.rotate(deg / 180 * pi);
        _paintDial.color = Colors.white;
       //繪制白色小圓點
       canvas.drawCircle(Offset(_radius, 0), 3, _paintDial);
       canvas.restore();

      ......
      canvas.restore();
    }
繪制小圓點.png

1.4 繪制帶陰影的黃色大圓點,用作時針

黃色的大圓點作為時針來處理翔悠,因為時針和畫布的角度不是吻合的业崖,需要換算,另外我們?yōu)榇髨A點添加陰影蓄愁。

for (double i = 0; i < _numPoint; i++) {
      canvas.save();
      double deg = 360 / _numPoint * i;
      canvas.rotate(deg / 180 * pi);
      _paintDial.color = Colors.white;
      canvas.drawCircle(Offset(_radius, 0), 3, _paintDial);
      //isShowBigCircle(hour, i)是判斷當前圓點是不是當前的時針位置
      if (isShowBigCircle(hour, i)) {
        //繪制陰影
        Path path = Path()
          ..addArc(Rect.fromCircle(center: Offset(_radius, 0), radius: 8), 0,
              pi * 2);
        canvas.drawShadow(path, Colors.yellow, 4, true);
        //繪制小時的圓點
        _paintDial.color = Colors.yellow;
        canvas.drawCircle(Offset(_radius, 0), 8, _paintDial);
      } else {
        _paintDial.color = Colors.white;
        canvas.drawCircle(Offset(_radius, 0), 3, _paintDial);
      }
      canvas.restore();
      ......
    }

1.5 繪制時間文字

畫布繪制文字調(diào)用canvas.drawParagraph(Paragraph Offset)函數(shù)双炕,Paragraph 對象通過ParagraphBuilder來創(chuàng)建,字體樣式可以通過ParagraphBuilder來設(shè)置

   //設(shè)置文字樣式
    _timeParagraphBuilder = ParagraphBuilder(ParagraphStyle(
        textAlign: TextAlign.center,
        fontSize: 70,
        maxLines: 1,
        fontWeight: FontWeight.bold));
   //獲取當前的時間
   DateTime dateTime = DateTime.now();
    var hour = dateTime.hour;
    var minute = dateTime.minute;
    var second = dateTime.second;
      //繪制文字
      canvas.save();
      _timeParagraphBuilder.addText(_getTimeStr(hour, minute));
      Paragraph paragraph = _timeParagraphBuilder.build();
      paragraph.layout(ParagraphConstraints(width: 230));
      canvas.drawParagraph(paragraph, Offset(-115,-42));
      canvas.restore();

2. 開關(guān)部分

整體布局分析涝登,開關(guān)部分的UI相對于整個屏幕來講位于底部雄家,使用 Stack 和 Align就可以實現(xiàn)這種布局樣式。

  //整體布局
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: Stack(
      children: [
        CustomPaint(painter: DialPlate(context,Color.fromARGB(255, 70, 0, 144),Color.fromARGB(255, 121, 83, 254))),
        _getAlarms(),
      ],
    ));
  }
//下部視圖
  _getAlarms() {
    return Align(
      alignment: Alignment.bottomLeft,
      child: Container(
        margin: EdgeInsets.only(left: 16, right: 16),
        height: 200,
        width: double.infinity,
        child: Column(
          children: [
            _getRow1(),
            _getRow2(),
            _getRow3(),
          ],
        ),
      ),
    );
  }
//_getRow1()胀滚、_getRow2()、_getRow3()類似
 _getRow1() {

    return Container(
      alignment: Alignment.centerLeft,
      width: double.infinity,
      height: 50,
      child: Row(
        children: [
          Text(
            '06:45',
            style: TextStyle(
                
                fontSize: 25,
                color: _firstSwitch == true ? _colorOn : _colorOff),
          ),
          Padding(
            padding: EdgeInsets.only(left: 18),
            child: Text(
              'Wake up',
              style: TextStyle(
                  
                  fontSize: 18,
                  color: _firstSwitch == true ? _colorOn : _colorOff),
            ),
          ),
          Expanded(child: SizedBox()),
          Container(
            width: 90,
            height: 10,
            child: Switch(
                value: _firstSwitch,
                onChanged: (onChanged) {
                  setState(() {_firstSwitch = onChanged;});
                },
                activeColor: _switchActiveColor,
                activeTrackColor: Colors.black.withAlpha(100),
                inactiveThumbColor: _switchInActiveColor,
                inactiveTrackColor: Colors.black.withAlpha(20),
            ),

          )
        ],
      ),
    );
  }

整體效果圖如下:


效果圖.gif
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末乱投,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌灵份,老刑警劉巖墨吓,帶你破解...
    沈念sama閱讀 212,816評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡施掏,警方通過查閱死者的電腦和手機钮惠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來七芭,“玉大人素挽,你說我怎么就攤上這事±瓴担” “怎么了预明?”我有些...
    開封第一講書人閱讀 158,300評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長耙箍。 經(jīng)常有香客問我撰糠,道長,這世上最難降的妖魔是什么辩昆? 我笑而不...
    開封第一講書人閱讀 56,780評論 1 285
  • 正文 為了忘掉前任阅酪,我火速辦了婚禮,結(jié)果婚禮上汁针,老公的妹妹穿的比我還像新娘术辐。我一直安慰自己,他們只是感情好扇丛,可當我...
    茶點故事閱讀 65,890評論 6 385
  • 文/花漫 我一把揭開白布术吗。 她就那樣靜靜地躺著,像睡著了一般帆精。 火紅的嫁衣襯著肌膚如雪较屿。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,084評論 1 291
  • 那天卓练,我揣著相機與錄音隘蝎,去河邊找鬼。 笑死襟企,一個胖子當著我的面吹牛嘱么,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播顽悼,決...
    沈念sama閱讀 39,151評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼曼振,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了蔚龙?” 一聲冷哼從身側(cè)響起冰评,我...
    開封第一講書人閱讀 37,912評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎木羹,沒想到半個月后甲雅,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體解孙,經(jīng)...
    沈念sama閱讀 44,355評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,666評論 2 327
  • 正文 我和宋清朗相戀三年抛人,在試婚紗的時候發(fā)現(xiàn)自己被綠了弛姜。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,809評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡妖枚,死狀恐怖廷臼,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情盅惜,我是刑警寧澤中剩,帶...
    沈念sama閱讀 34,504評論 4 334
  • 正文 年R本政府宣布,位于F島的核電站抒寂,受9級特大地震影響结啼,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜屈芜,卻給世界環(huán)境...
    茶點故事閱讀 40,150評論 3 317
  • 文/蒙蒙 一郊愧、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧井佑,春花似錦属铁、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至盒发,卻和暖如春例嘱,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背宁舰。 一陣腳步聲響...
    開封第一講書人閱讀 32,121評論 1 267
  • 我被黑心中介騙來泰國打工拼卵, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人蛮艰。 一個月前我還...
    沈念sama閱讀 46,628評論 2 362
  • 正文 我出身青樓腋腮,卻偏偏與公主長得像,于是被迫代替她去往敵國和親壤蚜。 傳聞我的和親對象是個殘疾皇子即寡,可洞房花燭夜當晚...
    茶點故事閱讀 43,724評論 2 351

推薦閱讀更多精彩內(nèi)容