Flutter入門並開發天氣預報APP(6)——天氣預報第一步-界面


經過前面的對於Flutter的介紹,我們現在已經可以開始寫我們的天氣預報APP的界面了。

項目Github地址:a1203991686/CoolWeather_Flutter

1. 大致界面

最終寫成的大致界面如圖:

我們可以把這個界面拆分成如下部分:

可以看到我們APP主要有最上面用來顯示地點和刷新時間的Title、顯示溫度和天氣的兩個Text、顯示3天預報的ListView、顯示空氣質量的GridView、以及最後顯示生活建議的ListView

此處會用到我們前面學過的所有知識,如果有同學沒有看過前面內容的,可以看下本系列前面的文章。

2. 創建項目

首先我們創建一個新的Flutter項目:

  1. 在AndroidStudio點擊File->New Flutter Project
  2. 接着選擇Flutter Application->NEXT。接着填寫你的項目名稱等一系列信息後點擊next
    在這裏插入圖片描述
  3. 接着輸入你的組織/公司名稱作爲包名,最後點擊Finish即可,這樣就新建了一個Flutter項目,並且Flutter會自動爲你生成一個計數器Demo;
    在這裏插入圖片描述
  4. 讓我們把mian.dart裏面的所有註釋以及_MyHomePageState裏面的build方法裏面的代碼都刪掉;
  5. 接着在lib文件夾下新建一個文件夾,名叫view,到時候我們把所有與界面有關的代碼文件都放在這個文件夾下面;
  6. 然後我們在view文件夾下面新建一個dart文件,命名爲main_page。這個就是我們的天氣詳情頁。

3. 設計好天氣詳情頁框架

首先我們需要導入material包,我們項目主要用material風格UI來寫。

在開頭輸入import 'package:flutter/material.dart';,這樣就導入了material包。接着創建我們的界面類MainPage

由於我們在到時候寫好網絡請求後,所有的數據都得從網絡獲取,並且使用了異步的方法,也就是說我們先把頁面加載瞭然後等獲取的數據回來了在通知Flutter更新狀態,所以這塊我們得使用StatefulWidget

class MainPage extends StatefulWidget {
  MainPage({Key key}) : super(key: key);

  @override
  MainPageState createState() => new MainPageState();
}

class MainPageState extends State<MainPage> {
  @override
  Widget build(BuildContext context) {
  
  }
}

接着我們就得開始寫build()裏面的內容了。由於我們需要一個全屏的背景圖片,所以我們就使用Container作爲我們最外層的Widget,並使用BoxDecoration裝飾容器配合DecorationImage來放置圖片:

@override
Widget build(BuildContext context) {
  return Container(
    decoration: BoxDecoration(
      image: DecorationImage(
        image: NetworkImage("http://blog.mrabit.com/bing/today"), //必應每日一圖背景
        fit: BoxFit.cover, // 設置爲全屏
      ),
    ),
    child: _weatherBody(),
  );
}

這個時候我們的運行結果如圖(①你背景圖片多半和我不一樣,因爲上面那個Uri獲取的是必應的每日一圖,每天圖片都不一樣;②運行的時候記得把child: _weatherBody(),給註釋掉,因爲我們還沒有定義_weatherBody()這個方法):

4. 設計title

爲了方便我就直接把剩下的佈局單領出來放到_weatherBody()這個方法:

Widget _weatherBody() {
  return
}

由於我們需要實現一個有Title的頁面,所以最外層我選用了Scaffold:

Widget _weatherBody() {
  return Scaffold(
    backgroundColor: Colors.transparent, //背景透明
    appBar: AppBar(
      centerTitle: true,
      title: Text(
        "北京",
        style: TextStyle(fontSize: 25.0),
      ),
      backgroundColor: Colors.transparent, //背景透明
      actions: <Widget>[ //右側Widget,相當於Android Toolbar中的menu
        Container(
          alignment: Alignment.center, //向中間對齊
          child: Text(
            "12:10",
            textAlign: TextAlign.center, //文字向中間對齊
          ),
        )
      ],
    ),
    body: SingleChildScrollView( // 由於到時候整個頁面一個屏幕可能放不下,就放置了一個滾動佈局
    
    ),
  );
}

這個時候的運行結果是:

5. 設計下面天氣預報頁面

接下來可以開始下下面的天氣顯示頁面了。

當前溫度和天氣情況

首先寫一個縱向線性佈局Column:

body: SingleChildScrollView(
  child: Column(
    children: <Widget>[
      
    ]
  )
),

由於我們要顯示在屏幕最右邊,所以使用Align:

body: SingleChildScrollView(
  child: Column(
    children: <Widget>[
      Align(
        alignment: Alignment.centerRight,
        child:Text(
          "26°C",
          style: TextStyle(
            fontSize: 50.0,
            color: Colors.white,
          ),
        ),
      ),
      Align(
        alignment: Alignment.centerRight,
        child:Text(
          "陰",
          style: TextStyle(
            fontSize: 20.0,
            color: Colors.white,
          ),
        ),
      ),
    ]
  )
),

運行結果是:

接下來我們需要顯示3天天氣預報、天氣質量以及生活建議的三個子控件,同樣爲了方便我們也把他們給單領出來,於是上面的Column接下來可以這樣寫:

body: SingleChildScrollView(
  child: Column(
    children: <Widget>[
      ... //上面的兩個Text
      Padding(
        padding: EdgeInsets.only(
          left: 15.0,
          right: 15.0,
          bottom: 15.0,
        ),
        child: Container(
          color: Colors.black54,
          child: _weatherList(), //3天天氣預報
        ),
      ),
      Padding(
        padding: EdgeInsets.only(
          left: 15.0,
          right: 15.0,
        ),
        child: Container(
          color: Colors.black54,
          child: _atmosphereList(), //空氣質量
        ),
      ),
      Padding(
        padding: EdgeInsets.only(
          top: 15.0,
          left: 15.0,
          right: 15.0,
          bottom: 15.0,
        ),
        child: Container(
          color: Colors.black54,
          child: _lifestyleList(), //生活建議
        ),
      ),
    ]
  )
),

3天天氣預報

對於3天天氣預報我們主要通過ListView來實現,由於到時候數據比較靈活,所以我們就直接使用ListView.Builder來實現:

List<String> dates = ["2019/10/01", "2019/10/02", "2019/10/03"];
List<String> temperatures = ["29/14", "30/18", "29/18"];
List<String> texts = ["陰", "晴", "雨"];

Widget _weatherList() {
    return Column(
        children: <Widget>[
            Align(
                alignment: Alignment.centerLeft,
                child: Text(
                    "預報",
                    style: TextStyle(
                        color: Colors.white,
                        fontSize: 20.0,
                    ),
                ),
            ),
            ListView.builder(
                shrinkWrap: true, //這個是指根據ListView所有子Widget的長度來設定ListView的長度
                physics: NeverScrollableScrollPhysics(), //禁止ListView自己的滑動,因爲我們在外面用了個SingleChildScrollView,我們通過他的滑動就可以了
                itemCount: dates.length, //ListView子項個數
                itemBuilder: (BuildContext context, int index) {
                    return ListTile(
                        title: Row(
                            mainAxisAlignment: MainAxisAlignment.spaceBetween, //這個是Row的主軸的子項的分佈格式,spaceBetween是指平均分佈
                            mainAxisSize: MainAxisSize.max,
                            children: <Widget>[
                                Text(
                                    "${dates[index]}",
                                    style: TextStyle(color: Colors.white),
                                ),
                                Text(
                                    "${temperatures[index]}",
                                    style: TextStyle(color: Colors.white),
                                ),
                                Text(
                                    "${texts[index]}",
                                    style: TextStyle(color: Colors.white),
                                ),
                            ],
                        ),
                    );
                }),
        ],
    );
}

這個時候運行結果是:

空氣質量

這塊我們需要用到GridView,由於只有兩個顯示內容,而且我們後期也沒有需要動態添加的需求,所以我們就直接使用GridView構造方法,而不去使用GridView的builder方法:

List<String> atmospheres = ["16", "56"];

Widget _atmosphereList() {
    return Column(
        children: <Widget>[
            Align(
                alignment: Alignment.centerLeft,
                child: Text(
                    "空氣質量",
                    style: TextStyle(
                        color: Colors.white,
                            fontSize: 20.0,
                    ),
                ),
            ),
            GridView(
                shrinkWrap: true, //見上面3天天氣預報的ListView處
                physics: NeverScrollableScrollPhysics(), //見上面3天天氣預報的ListView處
                gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                    crossAxisCount: 2, //橫軸三個子widget
                    childAspectRatio: 2 //顯示區域寬高相等
                ),
                children: <Widget>[
                    Column(
                        children: <Widget>[
                            Text(
                                "${atmospheres[0]}",
                                style: TextStyle(
                                    color: Colors.white,
                                    fontSize: 40.0,
                                ),
                            ),
                            Text(
                                "能見度",
                                style: TextStyle(
                                    color: Colors.white,
                                    fontSize: 20.0,
                                ),
                            ),
                        ],
                    ),
                    Column(
                        children: <Widget>[
                            Text(
                                "${atmospheres[1]}",
                                style: TextStyle(
                                    color: Colors.white,
                                    fontSize: 40.0,
                                ),
                            ),
                            Text(
                                "溼度",
                                style: TextStyle(
                                    color: Colors.white,
                                    fontSize: 20.0,
                                ),
                            ),
                        ],
                    ),
                ],
            ),
        ],
    );
}

運行後的效果是:

生活建議

這塊和3天天氣預報一樣,而且數據比3天天氣預報更多,所以他更適合用ListView.builder:

List<String> _lifestyleWeatherBrf = [
    "較舒適",
    "較舒適",
    "適宜",
    "適宜",
    "弱",
    "較適宜",
    "中"
];
List<String> _lifestyleWeatherTxt = [
    "白天天氣晴好,早晚會感覺偏涼,午後舒適、宜人。",
    "建議着薄外套、開衫牛仔衫褲等服裝。年老體弱者應適當添加衣物,宜着夾克衫、薄毛衣等。",
    "各項氣象條件適宜,無明顯降溫過程,發生感冒機率較低。",
    "天氣較好,趕快投身大自然參與戶外運動,盡情感受運動的快樂吧。",
    "天氣較好,但絲毫不會影響您出行的心情。溫度適宜又有微風相伴,適宜旅遊。",
    "紫外線強度較弱,建議出門前塗擦SPF在12-15之間、PA+的防曬護膚品。",
    "較適宜洗車,未來一天無雨,風力較小,擦洗一新的汽車至少能保持一天。",
    ",氣象條件對空氣污染物稀釋、擴散和清除無明顯影響,易感人羣應適當減少室外活動時間。"
];

Widget _lifestyleList() {
    return Column(
        children: <Widget>[
            Align(
                alignment: Alignment.centerLeft,
                child: Text(
                    "生活建議",
                    style: TextStyle(
                        color: Colors.white,
                        fontSize: 20.0,
                    ),
                ),
            ),
            ListView.builder(
                shrinkWrap: true,
                physics: NeverScrollableScrollPhysics(),
                itemCount: _lifestyleWeatherBrf.length,
                itemBuilder: (BuildContext context, int index) {
                    return ListTile(
                        title: Column(
                            mainAxisAlignment: MainAxisAlignment.start,
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: <Widget>[
                                Text(
                                    "${_lifestyleWeatherBrf[index]}",
                                    style: TextStyle(
                                        color: Colors.white,
                                    ),
                                ),
                                Text(
                                    "${_lifestyleWeatherTxt[index]}",
                                    style: TextStyle(
                                        color: Colors.white,
                                    ),
                                ),
                            ],
                        ),
                    );
                },
            ),
        ],
    );
}

運行結果是:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章