Flutter入门进阶之旅 – Flutter课程表View

时间:2021-7-21 作者:qvyue

前言

上一节中我们一块学习Flutter生命周期相关的基本知识,了解到了在flutter中生命周期函数存在的意义以及各个不同生命周期函数的回调时机,到目前为止我们已经完成了对Flutter所有入门相关的课程学习,掌握了各种常用组件的使用方法以及使用路由来完成页面切换传递数据,还学习了在flutter中的数据存储,网络请求等一系列的相关课程。本次课程作为基础到进阶到过度篇,咱们来一块利用所学知识做一个课程表View,对Flutter相关知识点加以巩固提高,做到活学活用。

1.课程目标

  • 分析课表view组成部分,拆解绘制流程
  • 课表view绘制,数据准备
  • 自行利用所学Widget组合课表view

2.效果图

我们先来看下已经绘制好的课程表View效果图,然后对效果图上的具体实现流程做拆解分析,一步步来完成Flutter课程表view的实现。

Flutter入门进阶之旅 - Flutter课程表View
syllabus.gif

从上面的效果图我们可以分析得出,该课表view可分解成下面几个部分,我用不同的颜色块标记出

Flutter入门进阶之旅 - Flutter课程表View
在这里插入图片描述

整体可分为三个大块

  • 1 顶部蓝色框框圈住的日期星期区域
  • 2 左侧灰色框框圈住的课程节次索引区域
  • 3 中间绿色框框圈起来的课程信息区域

下面我们来追一看不同区域的具体实现代码

3. View拆分

3.1 顶部日期星期View

Flutter入门进阶之旅 - Flutter课程表View
在这里插入图片描述

顶部日期View可以拆解为GridView+Column组成,之所以选择GridView是因为我们要做到Column里的数据每一个item都均分显示,GridView设置单行显示,Colum设置上面view是星期,下面view是日期,利用小算法计算出当前日期,然后给当前日期设置不同的样式,来提示用户。

分析了实现思路,具体代码我就不详细讲解了贴上顶部日期星期的具体实现代码供读者参考

星期日期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 createState() => PageState();
}

class PageState extends State {
  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中的月份有区别,js中是从0开始,dart则从1开始,我们无需再进行加一处理) 月
    mondayTime.day; //6 日
    // nowTime.hour ;//6 时
    // nowTime.minute ;//6 分
    // nowTime.second ;//6 秒
    for (int i = 0; i 

运行代码后,效果如下图所示:

Flutter入门进阶之旅 - Flutter课程表View
在这里插入图片描述

3.2 中间课表view

Flutter入门进阶之旅 - Flutter课程表View
在这里插入图片描述

中间课表view跟左侧课程节次指引是在一个大View里处理的,考虑到有些手机可能一屏显示不完整个课程表视图,这里我实现的逻辑是

  • 1 先把上图标号为2跟3的区域包裹在一个SingleChildScrollView里让整个View支持上下滑动,
  • 2.然后在SingleChildScrollView 里用Row包裹2跟3区域,2是一个GridView,整体布局1列10行,跟课表view保持高度一样,
  • 3 .区域3又分为两部分,一个是背景格子区域,另外一个带背景颜色的课表区域 ,整个3区域我还是利用GridView实现,
  • 4 在这里,我默认让每个课程View即图中标号为4 的区域占两个课程格子的大小,这样一周7天,每天有5大节课,所以GridView需要设置为5行7列,供35个item,然后让区域3跟左侧2区域高度一致,
  • 5 区域3 GridView中的每一个Item采用Stack布局,底下的一层view用Column包括两个高度一样的Container,设置好边框,让他呈现格子的样式,顶上的一层试图用来显示课程信息,背景颜色利用提前设置好的颜色数组值,每次随机取不同的值设置不同的颜色,再利用Center组件显示课程具体信息。
  • 6 左侧区域2 课程指引view设置相同的背景即可,不需要特殊处理

核心代码如下:

   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的效果如图

Flutter入门进阶之旅 - Flutter课程表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 createState() => PageState();
}

class PageState extends State {
  var colorList = [
    Colors.red,
    Colors.lightBlueAccent,
    Colors.grey,
    Colors.cyan,
    Colors.amber,
    Colors.deepPurpleAccent,
    Colors.purpleAccent
  ];
  var infoList = ["高等数学-周某某教授@综合楼201", "大学英语-王某某讲师@行政楼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中的月份有区别,js中是从0开始,dart则从1开始,我们无需再进行加一处理) 月
    mondayTime.day; //6 日
    // nowTime.hour ;//6 时
    // nowTime.minute ;//6 分
    // nowTime.second ;//6 秒
    for (int i = 0; i  "我的课表";

  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可自行扩充
      ],
    ),
  );
}

详细代码已同步更新到我的Flutter入门进阶之旅专栏上,感兴趣的读者可以自行查阅更多相关代码:
仓库地址:本节Flutter课程吧View课程代码

声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:qvyue@qq.com 进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。