Flutter入門進(jìn)階之旅 - Flutter課程表View

前言

上一節(jié)中我們一塊學(xué)習(xí)Flutter生命周期相關(guān)的基本知識,了解到了在flutter中生命周期函數(shù)存在的意義以及各個不同生命周期函數(shù)的回調(diào)時機(jī)拓哺,到目前為止我們已經(jīng)完成了對Flutter所有入門相關(guān)的課程學(xué)習(xí),掌握了各種常用組件的使用方法以及使用路由來完成頁面切換傳遞數(shù)據(jù)荧恍,還學(xué)習(xí)了在flutter中的數(shù)據(jù)存儲菲语,網(wǎng)絡(luò)請求等一系列的相關(guān)課程拴驮。本次課程作為基礎(chǔ)到進(jìn)階到過度篇唤反,咱們來一塊利用所學(xué)知識做一個課程表View凳寺,對Flutter相關(guān)知識點加以鞏固提高,做到活學(xué)活用彤侍。

1.課程目標(biāo)

  • 分析課表view組成部分肠缨,拆解繪制流程
  • 課表view繪制,數(shù)據(jù)準(zhǔn)備
  • 自行利用所學(xué)Widget組合課表view

2.效果圖

我們先來看下已經(jīng)繪制好的課程表View效果圖盏阶,然后對效果圖上的具體實現(xiàn)流程做拆解分析晒奕,一步步來完成Flutter課程表view的實現(xiàn)。

syllabus.gif

從上面的效果圖我們可以分析得出般哼,該課表view可分解成下面幾個部分吴汪,我用不同的顏色塊標(biāo)記出

在這里插入圖片描述

整體可分為三個大塊

  • 1 頂部藍(lán)色框框圈住的日期星期區(qū)域
  • 2 左側(cè)灰色框框圈住的課程節(jié)次索引區(qū)域
  • 3 中間綠色框框圈起來的課程信息區(qū)域

下面我們來追一看不同區(qū)域的具體實現(xiàn)代碼

3. View拆分

3.1 頂部日期星期View

在這里插入圖片描述

頂部日期View可以拆解為GridView+Column組成惠窄,之所以選擇GridView是因為我們要做到Column里的數(shù)據(jù)每一個item都均分顯示蒸眠,GridView設(shè)置單行顯示,Colum設(shè)置上面view是星期杆融,下面view是日期楞卡,利用小算法計算出當(dāng)前日期,然后給當(dāng)前日期設(shè)置不同的樣式脾歇,來提示用戶蒋腮。

分析了實現(xiàn)思路,具體代碼我就不詳細(xì)講解了貼上頂部日期星期的具體實現(xiàn)代碼供讀者參考

星期日期View代碼:

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_app/pages/custom_widget/widget/SpaceWidget.dart';

/**
 * desc:
 * author: xiedong
 * date: 4/25/21
 **/
class SyllabusPage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => PageState();
}

class PageState extends State<SyllabusPage> {
  var weekList = ['周一', '周二', '周三', '周四', '周五', '周六', '周日'];

  var dateList = [];
  var currentWeekIndex = 0;

  @override
  void initState() {
    super.initState();

    var monday = 1;
    var mondayTime = DateTime.now();

    //獲取本周星期一是幾號
    while (mondayTime.weekday != monday) {
      mondayTime = mondayTime.subtract(new Duration(days: 1));
    }

    mondayTime.year; //2020 年
    mondayTime.month; //6(這里和js中的月份有區(qū)別藕各,js中是從0開始池摧,dart則從1開始,我們無需再進(jìn)行加一處理) 月
    mondayTime.day; //6 日
    // nowTime.hour ;//6 時
    // nowTime.minute ;//6 分
    // nowTime.second ;//6 秒
    for (int i = 0; i < 7; i++) {
      dateList.add(
          mondayTime.month.toString() + "/" + (mondayTime.day + i).toString());
      if ((mondayTime.day + i) == DateTime.now().day) {
        setState(() {
          currentWeekIndex = i + 1;
        });
      }
    }
    // print('Recent monday '+DateTime.now().day.toString());
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("我的課表"),
        centerTitle: true,
      ),
      body: Column(
        mainAxisAlignment: MainAxisAlignment.start,
        children: [
          SizedBox(
            child: GridView.builder(
                shrinkWrap: true,
                physics: NeverScrollableScrollPhysics(),
                itemCount: 8,
                gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                    crossAxisCount: 8, childAspectRatio: 1 / 1),
                itemBuilder: (BuildContext context, int index) {
                  return Container(
                    color: index == this.currentWeekIndex
                        ? Color(0xf7f7f7)
                        : Colors.white,
                    child: Center(
                      child: index == 0
                          ? Column(
                              mainAxisAlignment: MainAxisAlignment.center,
                              children: [
                                Text("星期",
                                    style: TextStyle(
                                        fontSize: 14, color: Colors.black87)),
                                SpaceWidget(height: 5),
                                Text("日期", style: TextStyle(fontSize: 12)),
                              ],
                            )
                          : Column(
                              mainAxisAlignment: MainAxisAlignment.center,
                              children: [
                                Text(weekList[index - 1],
                                    style: TextStyle(
                                        fontSize: 14,
                                        color: index == currentWeekIndex
                                            ? Colors.lightBlue
                                            : Colors.black87)),
                                SpaceWidget(height: 5),
                                Text(dateList[index - 1],
                                    style: TextStyle(
                                        fontSize: 12,
                                        color: index == currentWeekIndex
                                            ? Colors.lightBlue
                                            : Colors.black87)),
                              ],
                            ),
                    ),
                  );
                }),
          ),
        ],
      ),
    );
  }
}

運行代碼后激况,效果如下圖所示:


在這里插入圖片描述

3.2 中間課表view

在這里插入圖片描述

中間課表view跟左側(cè)課程節(jié)次指引是在一個大View里處理的作彤,考慮到有些手機(jī)可能一屏顯示不完整個課程表視圖膘魄,這里我實現(xiàn)的邏輯是

  • 1 先把上圖標(biāo)號為2跟3的區(qū)域包裹在一個SingleChildScrollView里讓整個View支持上下滑動,
  • 2.然后在SingleChildScrollView 里用Row包裹2跟3區(qū)域竭讳,2是一個GridView儡炼,整體布局1列10行娘荡,跟課表view保持高度一樣,
  • 3 .區(qū)域3又分為兩部分,一個是背景格子區(qū)域驶拱,另外一個帶背景顏色的課表區(qū)域 ,整個3區(qū)域我還是利用GridView實現(xiàn)昨登,
  • 4 在這里蕴掏,我默認(rèn)讓每個課程View即圖中標(biāo)號為4 的區(qū)域占兩個課程格子的大小,這樣一周7天思瘟,每天有5大節(jié)課荸百,所以GridView需要設(shè)置為5行7列,供35個item滨攻,然后讓區(qū)域3跟左側(cè)2區(qū)域高度一致够话,
  • 5 區(qū)域3 GridView中的每一個Item采用Stack布局,底下的一層view用Column包括兩個高度一樣的Container光绕,設(shè)置好邊框女嘲,讓他呈現(xiàn)格子的樣式,頂上的一層試圖用來顯示課程信息诞帐,背景顏色利用提前設(shè)置好的顏色數(shù)組值欣尼,每次隨機(jī)取不同的值設(shè)置不同的顏色,再利用Center組件顯示課程具體信息停蕉。
  • 6 左側(cè)區(qū)域2 課程指引view設(shè)置相同的背景即可愕鼓,不需要特殊處理

核心代碼如下:

   Expanded(
            child: SingleChildScrollView(
              child: Row(
                children: [
                  Expanded(
                    flex: 1,
                    child: GridView.builder(
                        shrinkWrap: true,
                        // physics:ClampingScrollPhysics(),
                        itemCount: 10,
                        gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                            crossAxisCount: 1, childAspectRatio: 1 / 2),
                        itemBuilder: (BuildContext context, int index) {
                          return Container(
                            // width: 25,
                            // height:s 80,
                              child: Center(
                                child: Text(
                                  (index + 1).toInt().toString(),
                                  style: TextStyle(fontSize: 15),
                                ),
                              ),
                              decoration: BoxDecoration(
                                color: Color(0xff5ff5),
                                // border: Border.all(color: Colors.black12, width: 0.5),
                                border: Border(
                                  bottom: BorderSide(
                                      color: Colors.black12, width: 0.5),
                                  right: BorderSide(
                                      color: Colors.black12, width: 0.5),
                                ),
                              ));
                        }),
                  ),
                  Expanded(
                    flex: 7,
                    child: GridView.builder(
                        shrinkWrap: true,
                        physics: NeverScrollableScrollPhysics(),
                        itemCount: 35,
                        gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                            crossAxisCount: 7, childAspectRatio: 1 / 4),
                        itemBuilder: (BuildContext context, int index) {
                          return Container(
                            child: Stack(
                              children: [
                                Column(
                                  mainAxisAlignment:
                                  MainAxisAlignment.spaceBetween,
                                  children: [
                                    Flexible(
                                      flex: 1,
                                      child: Container(
                                          width: double.infinity,
                                          height: double.infinity,
                                          decoration: BoxDecoration(
                                            color: Colors.white,
                                            // border: Border.all(color: Colors.black12, width: 0.5),
                                            border: Border(
                                              bottom: BorderSide(
                                                  color: Colors.black12,
                                                  width: 0.5),
                                              right: BorderSide(
                                                  color: Colors.black12,
                                                  width: 0.5),
                                            ),
                                          )),
                                    ),
                                    Flexible(
                                      flex: 1,
                                      child: Container(
                                          width: double.infinity,
                                          height: double.infinity,
                                          decoration: BoxDecoration(
                                            color: Colors.white,
                                            // border: Border.all(color: Colors.black12, width: 0.5),
                                            border: Border(
                                              bottom: BorderSide(
                                                  color: Colors.black12,
                                                  width: 0.5),
                                              right: BorderSide(
                                                  color: Colors.black12,
                                                  width: 0.5),
                                            ),
                                          )),
                                    ),
                                  ],
                                ),
                                if (index % 5 == 0 || index % 5 == 1)
                                  Container(
                                    margin: EdgeInsets.all(0.5),
                                    decoration: BoxDecoration(
                                      borderRadius: BorderRadius.circular(2),
                                      color: colorList[index % 7],
                                    ),
                                    child: Center(
                                      child: Text(
                                        infoList[index % 2],
                                        textAlign: TextAlign.center,
                                        style: TextStyle(
                                            color: Colors.white,
                                            fontSize: 11,
                                            letterSpacing: 1),
                                      ),
                                    ),
                                  )
                              ],
                            ),
                          );
                        }),
                  )
                ],
              ),
            ),
          ),
        

運行代碼后,中間課程信息View的效果如圖

Kapture 2021-04-29 at 12.07.24.gif

完整代碼如下:

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_app/pages/custom_widget/widget/SpaceWidget.dart';

/**
 * desc:
 * author: xiedong
 * date: 4/25/21
 **/
class SyllabusPage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => PageState();
}

class PageState extends State<SyllabusPage> {
  var colorList = [
    Colors.red,
    Colors.lightBlueAccent,
    Colors.grey,
    Colors.cyan,
    Colors.amber,
    Colors.deepPurpleAccent,
    Colors.purpleAccent
  ];
  var infoList = ["高等數(shù)學(xué)-周某某教授@綜合樓201", "大學(xué)英語-王某某講師@行政樓501"];
  var weekList = ['周一', '周二', '周三', '周四', '周五', '周六', '周日'];

  var dateList = [];
  var currentWeekIndex = 0;

  @override
  void initState() {
    super.initState();

    var monday = 1;
    var mondayTime = DateTime.now();

    //獲取本周星期一是幾號
    while (mondayTime.weekday != monday) {
      mondayTime = mondayTime.subtract(new Duration(days: 1));
    }

    mondayTime.year; //2020 年
    mondayTime.month; //6(這里和js中的月份有區(qū)別慧起,js中是從0開始菇晃,dart則從1開始,我們無需再進(jìn)行加一處理) 月
    mondayTime.day; //6 日
    // nowTime.hour ;//6 時
    // nowTime.minute ;//6 分
    // nowTime.second ;//6 秒
    for (int i = 0; i < 7; i++) {
      dateList.add(
          mondayTime.month.toString() + "/" + (mondayTime.day + i).toString());
      if ((mondayTime.day + i) == DateTime.now().day) {
        setState(() {
          currentWeekIndex = i + 1;
        });
      }
    }
    // print('Recent monday '+DateTime.now().day.toString());
  }


  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        mainAxisAlignment: MainAxisAlignment.start,
        children: [
          SizedBox(
            child: GridView.builder(
                shrinkWrap: true,
                physics: NeverScrollableScrollPhysics(),
                itemCount: 8,
                gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                    crossAxisCount: 8, childAspectRatio: 1 / 1),
                itemBuilder: (BuildContext context, int index) {
                  return Container(
                    color: index == this.currentWeekIndex
                        ? Color(0xf7f7f7)
                        : Colors.white,
                    child: Center(
                      child: index == 0
                          ? Column(
                        mainAxisAlignment: MainAxisAlignment.center,
                        children: [
                          Text("星期",
                              style: TextStyle(
                                  fontSize: 14, color: Colors.black87)),
                          SpaceWidget(height: 5),
                          Text("日期", style: TextStyle(fontSize: 12)),
                        ],
                      )
                          : Column(
                        mainAxisAlignment: MainAxisAlignment.center,
                        children: [
                          Text(weekList[index - 1],
                              style: TextStyle(
                                  fontSize: 14,
                                  color: index == currentWeekIndex
                                      ? Colors.lightBlue
                                      : Colors.black87)),
                          SpaceWidget(height: 5),
                          Text(dateList[index - 1],
                              style: TextStyle(
                                  fontSize: 12,
                                  color: index == currentWeekIndex
                                      ? Colors.lightBlue
                                      : Colors.black87)),
                        ],
                      ),
                    ),
                  );
                }),
          ),
          Expanded(
            child: SingleChildScrollView(
              child: Row(
                children: [
                  Expanded(
                    flex: 1,
                    child: GridView.builder(
                        shrinkWrap: true,
                        // physics:ClampingScrollPhysics(),
                        itemCount: 10,
                        gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                            crossAxisCount: 1, childAspectRatio: 1 / 2),
                        itemBuilder: (BuildContext context, int index) {
                          return Container(
                            // width: 25,
                            // height:s 80,
                              child: Center(
                                child: Text(
                                  (index + 1).toInt().toString(),
                                  style: TextStyle(fontSize: 15),
                                ),
                              ),
                              decoration: BoxDecoration(
                                color: Color(0xff5ff5),
                                // border: Border.all(color: Colors.black12, width: 0.5),
                                border: Border(
                                  bottom: BorderSide(
                                      color: Colors.black12, width: 0.5),
                                  right: BorderSide(
                                      color: Colors.black12, width: 0.5),
                                ),
                              ));
                        }),
                  ),
                  Expanded(
                    flex: 7,
                    child: GridView.builder(
                        shrinkWrap: true,
                        physics: NeverScrollableScrollPhysics(),
                        itemCount: 35,
                        gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                            crossAxisCount: 7, childAspectRatio: 1 / 4),
                        itemBuilder: (BuildContext context, int index) {
                          return Container(
                            child: Stack(
                              children: [
                                Column(
                                  mainAxisAlignment:
                                  MainAxisAlignment.spaceBetween,
                                  children: [
                                    Flexible(
                                      flex: 1,
                                      child: Container(
                                          width: double.infinity,
                                          height: double.infinity,
                                          decoration: BoxDecoration(
                                            color: Colors.white,
                                            // border: Border.all(color: Colors.black12, width: 0.5),
                                            border: Border(
                                              bottom: BorderSide(
                                                  color: Colors.black12,
                                                  width: 0.5),
                                              right: BorderSide(
                                                  color: Colors.black12,
                                                  width: 0.5),
                                            ),
                                          )),
                                    ),
                                    Flexible(
                                      flex: 1,
                                      child: Container(
                                          width: double.infinity,
                                          height: double.infinity,
                                          decoration: BoxDecoration(
                                            color: Colors.white,
                                            // border: Border.all(color: Colors.black12, width: 0.5),
                                            border: Border(
                                              bottom: BorderSide(
                                                  color: Colors.black12,
                                                  width: 0.5),
                                              right: BorderSide(
                                                  color: Colors.black12,
                                                  width: 0.5),
                                            ),
                                          )),
                                    ),
                                  ],
                                ),
                                if (index % 5 == 0 || index % 5 == 1)
                                  Container(
                                    margin: EdgeInsets.all(0.5),
                                    decoration: BoxDecoration(
                                      borderRadius: BorderRadius.circular(2),
                                      color: colorList[index % 7],
                                    ),
                                    child: Center(
                                      child: Text(
                                        infoList[index % 2],
                                        textAlign: TextAlign.center,
                                        style: TextStyle(
                                            color: Colors.white,
                                            fontSize: 11,
                                            letterSpacing: 1),
                                      ),
                                    ),
                                  )
                              ],
                            ),
                          );
                        }),
                  )
                ],
              ),
            ),
          ),
          _bottomView
        ],
      ),
    );
  }

  @override
  String pageTitle() => "我的課表";

  Widget _topView = SizedBox(
    height: 30,
    child: Expanded(
      child: ListView.builder(
          scrollDirection: Axis.horizontal,
          itemCount: 7,
          itemBuilder: (BuildContext context, int index) {
            return Text("dd");
          }),
    ),
  );
  Widget _centerView = Expanded(
    child: GridView.builder(
        itemCount: 63,
        gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
          crossAxisCount: 7,
        ),
        itemBuilder: (BuildContext context, int index) {
          return Container(
            // width: 25,
            // height: 80,
              child: Center(
                child: Text(
                  (index + 1).toString(),
                  style: TextStyle(fontSize: 15),
                ),
              ),
              decoration: BoxDecoration(
                color: Color(0xff5ff5),
                border: Border.all(color: Colors.black12, width: 0.5),
              ));
        }),
  );

  Widget _bottomView = SizedBox(
    height: 30,
    child: Row(
      children: [
       //底部view可自行擴(kuò)充
      ],
    ),
  );
}

詳細(xì)代碼已同步更新到我的Flutter入門進(jìn)階之旅專欄上蚓挤,感興趣的讀者可以自行查閱更多相關(guān)代碼:
倉庫地址:本節(jié)Flutter課程吧View課程代碼

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末磺送,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子灿意,更是在濱河造成了極大的恐慌估灿,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,427評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件缤剧,死亡現(xiàn)場離奇詭異馅袁,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)荒辕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評論 3 395
  • 文/潘曉璐 我一進(jìn)店門汗销,熙熙樓的掌柜王于貴愁眉苦臉地迎上來芒粹,“玉大人,你說我怎么就攤上這事大溜』幔” “怎么了?”我有些...
    開封第一講書人閱讀 165,747評論 0 356
  • 文/不壞的土叔 我叫張陵钦奋,是天一觀的道長座云。 經(jīng)常有香客問我,道長付材,這世上最難降的妖魔是什么朦拖? 我笑而不...
    開封第一講書人閱讀 58,939評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮厌衔,結(jié)果婚禮上璧帝,老公的妹妹穿的比我還像新娘。我一直安慰自己富寿,他們只是感情好睬隶,可當(dāng)我...
    茶點故事閱讀 67,955評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著页徐,像睡著了一般苏潜。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上变勇,一...
    開封第一講書人閱讀 51,737評論 1 305
  • 那天恤左,我揣著相機(jī)與錄音,去河邊找鬼搀绣。 笑死飞袋,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的链患。 我是一名探鬼主播巧鸭,決...
    沈念sama閱讀 40,448評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼锣险!你這毒婦竟也來了蹄皱?” 一聲冷哼從身側(cè)響起览闰,我...
    開封第一講書人閱讀 39,352評論 0 276
  • 序言:老撾萬榮一對情侶失蹤芯肤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后压鉴,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體崖咨,經(jīng)...
    沈念sama閱讀 45,834評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,992評論 3 338
  • 正文 我和宋清朗相戀三年油吭,在試婚紗的時候發(fā)現(xiàn)自己被綠了击蹲。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片署拟。...
    茶點故事閱讀 40,133評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖歌豺,靈堂內(nèi)的尸體忽然破棺而出推穷,到底是詐尸還是另有隱情,我是刑警寧澤类咧,帶...
    沈念sama閱讀 35,815評論 5 346
  • 正文 年R本政府宣布馒铃,位于F島的核電站,受9級特大地震影響痕惋,放射性物質(zhì)發(fā)生泄漏区宇。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,477評論 3 331
  • 文/蒙蒙 一值戳、第九天 我趴在偏房一處隱蔽的房頂上張望议谷。 院中可真熱鬧,春花似錦堕虹、人聲如沸卧晓。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽禀崖。三九已至,卻和暖如春螟炫,著一層夾襖步出監(jiān)牢的瞬間波附,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評論 1 272
  • 我被黑心中介騙來泰國打工昼钻, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留掸屡,地道東北人。 一個月前我還...
    沈念sama閱讀 48,398評論 3 373
  • 正文 我出身青樓然评,卻偏偏與公主長得像仅财,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子碗淌,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,077評論 2 355

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