亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Flutter 仿微信支付界面

 更新時(shí)間:2021年05月31日 10:28:59   作者:島上碼農(nóng)  
網(wǎng)傳微信支付頁(yè)面的第三方鏈接一個(gè)格子需要廣告費(fèi)1一個(gè)億,微信支付頁(yè)非常適合做功能導(dǎo)航,本篇使用 ListView和 GridView 模仿了微信支付的頁(yè)面,同時(shí)介紹了如何裝飾一個(gè)組件的背景和邊緣樣式。

左側(cè)是微信支付的界面,右側(cè)是開(kāi)發(fā)完成后的效果,圖標(biāo)是從 iconfont 上下載的。首先介紹一下本篇涉及到的組件。

帶裝飾效果的 Container

實(shí)際過(guò)程中我們經(jīng)常會(huì)遇到一個(gè)容器需要額外的樣式,例如圓角,背景色等。在 Flutter 中,對(duì)于各種容器都有一個(gè) decoration 的屬性,可以用于裝飾容器。典型的用法有設(shè)置背景色、圓角、邊框和陰影等,其中背景色可以使用漸變色。decoration 是一個(gè) Decoration 對(duì)象,最常用的是 BoxDecoration,BoxDecoration 的屬性如下所示:

const BoxDecoration({
    this.color,
    this.image,
    this.border,
    this.borderRadius,
    this.boxShadow,
    this.gradient,
    this.backgroundBlendMode,
    this.shape = BoxShape.rectangle,
  }) 

其中color為使用顏色填充容器,image 為 使用圖片作為背景,border 為邊框,borderRadius 為邊框圓角,boxShadow 為容器陰影,gradient 使用漸變色作為背景,backgroundBlendMode 是指與容器的混合模型,默認(rèn)是覆蓋,shape 是背景形狀,默認(rèn)是矩形。其中背景部分我們一般只會(huì)選擇一種。這里以上面的綠色圓弧背景為例,還加上了一點(diǎn)點(diǎn)漸變(漸變色支持多個(gè),可以根據(jù)需要調(diào)節(jié)),示例代碼如下:

return Container(
      //......
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(4.0),
        gradient: LinearGradient(
            begin: Alignment.topCenter,
            end: Alignment.bottomCenter,
            colors: [
              Color(0xFF56AF6D),
              Color(0xFF56AA6D),
            ]),
      ),
  		//...
    );

這里設(shè)置了邊角為圓弧,半徑為4,使用漸變色填充,漸變方向?yàn)閺捻敳恐醒氲降撞恐醒耄瑵u變色有兩個(gè)。

Row 行布局和 Column列布局

這個(gè)在之前的第五篇列表篇介紹過(guò),其中 Row 代表行布局(即子元素按一行排布),Column 代表列布局(即子元素按一列排布)。具體可以參考Flutter 入門與實(shí)戰(zhàn)(五):來(lái)一個(gè)圖文并茂的列表。

ListView列表組件

列表視圖,和之前的一篇一樣,只是本篇的用法不同,用于實(shí)現(xiàn)整個(gè)頁(yè)面可以按列表的方式進(jìn)行滾動(dòng),直接將各個(gè)部分組件放入到列表的 children屬性中,而不是使用數(shù)組構(gòu)建列表元素,有點(diǎn)類似滾動(dòng)視圖的用法。

GridView網(wǎng)格組件

GridView 用于將一個(gè)容器按行列劃分,可以指定主軸的元素個(gè)數(shù)(根據(jù)滾動(dòng)方向定),之后自動(dòng)按總元素的個(gè)數(shù)分別填充到網(wǎng)格,例如按縱向滾動(dòng)時(shí),則可以指定行方向一行有多少個(gè)網(wǎng)格,每個(gè)網(wǎng)格一個(gè)元素。超出一行數(shù)量后會(huì)自動(dòng)換另一行。最簡(jiǎn)單的用法是使用 GridView.count 方法構(gòu)建 GridView,用法如下:

GridView.count(
   crossAxisSpacing: gridSpace,
   mainAxisSpacing: gridSpace,
   crossAxisCount: crossAxisCount,
   //設(shè)置以下兩個(gè)參數(shù),禁止GridView的滾動(dòng),防止與 ListView 沖突
   shrinkWrap: true,
   physics: NeverScrollableScrollPhysics(),
   children: buttons.map((item) {
      return _getMenus(item['icon'], item['name'], color: textColor);
    }).toList(),
);

這里 crossAxisSpacing 是與滾動(dòng)方向垂直的元素的間距,如按縱向(默認(rèn)值)滾動(dòng),則是橫向行元素之間的間距。mainAxisSpacing 是與滾動(dòng)方向相同的元素的間距。children 即網(wǎng)格中的元素。這里需要注意的是,由于 本例中GridView是嵌套在 ListView 里面的,兩個(gè)組件都是縱向滾動(dòng),這樣會(huì)引起沖突導(dǎo)致布局無(wú)法滿足約束。因此,在這里設(shè)置了 shrinkWrap 為 true 和 physics 為NeverScrollableScrollPhysics,以禁止 GridView 的滾動(dòng),從而滿足約束。

代碼實(shí)現(xiàn)

首先來(lái)分析布局,所有菜單按鈕其實(shí)都是一樣的布局,可以使用統(tǒng)一的列布局完成菜單按鈕,提高復(fù)用性。菜單按鈕從上到下一次為圖標(biāo)、間距(圖標(biāo)與文字之間)和菜單名稱。實(shí)現(xiàn)代碼如下:

Column _getMenus(String icon, String name, {Color color = Colors.black}) {
  return Column(
    mainAxisAlignment: MainAxisAlignment.center,
    children: <Widget>[
      SizedBox(
        child: Image.asset(icon),
        width: 50,
        height: 50,
      ),
      SizedBox(
        height: 5,
      ),
      Text(name, style: TextStyle(fontSize: 14.0, color: color, height: 2)),
    ],
  );

通過(guò)傳輸一個(gè)圖標(biāo)名稱,菜單名稱和可選的字體顏色(頂部區(qū)域和其他的文字顏色不同)來(lái)實(shí)現(xiàn)單個(gè)菜單。

其次來(lái)看頂部區(qū)域,頂部區(qū)域只有兩個(gè)按鈕,使用帶裝飾的容器實(shí)現(xiàn)背景的裝飾和圓角。再采用行布局將兩個(gè)菜單按鈕在橫向均勻排布。同時(shí),使用 Center 布局將兩個(gè)菜單保持中部居中。這里指定了容器的高度,這是因?yàn)閺拿烙^上看太矮了不太協(xié)調(diào),實(shí)際開(kāi)發(fā)要根據(jù) UI 設(shè)計(jì)稿定。

Widget _headerGridButtons() {
    double height = 144;
    List<Map<String, String>> buttons = GridMockData.headerGrids();
    return Container(
      height: height,
      margin: EdgeInsets.fromLTRB(MARGIN, MARGIN, MARGIN, MARGIN / 2),
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(4.0),
        gradient: LinearGradient(
            begin: Alignment.topCenter,
            end: Alignment.bottomCenter,
            colors: [
              Color(0xFF56AF6D),
              Color(0xFF56AA6D),
            ]),
      ),
      child: Center(
        child: Row(
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
            children: buttons
                .map((item) =>
                    _getMenus(item['icon'], item['name'], color: Colors.white))
                .toList()),
      ),
    );
  }

其他菜單布局都是一樣,只是區(qū)域標(biāo)題,菜單數(shù)量、菜單內(nèi)容不同,因此可以統(tǒng)一封裝一個(gè)通用的方法來(lái)構(gòu)建任意形式的菜單,以及設(shè)置區(qū)域標(biāo)題的字體樣式、圓角背景等屬性。菜單均使用 GridView 實(shí)現(xiàn)網(wǎng)格式布局,同時(shí)由于菜單布局相同,可以封裝一個(gè)通用的方法來(lái)指定網(wǎng)格一行按鈕的數(shù)量,按鈕字體顏色等屬性,實(shí)現(xiàn)代碼的復(fù)用。

Widget _dynamicGridButtons(List<Map<String, String>> buttons, String title,
      {int crossAxisCount = 4}) {
    return Container(
      margin: EdgeInsets.fromLTRB(MARGIN, MARGIN, MARGIN, MARGIN / 2),
      padding: EdgeInsets.all(MARGIN),
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(4.0),
        color: Colors.white,
      ),
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(
            title,
            style: TextStyle(color: Colors.grey[700]),
          ),
          SizedBox(height: 20),
          _gridButtons(buttons, crossAxisCount, textColor: Colors.black),
        ],
      ),
    );
  }

GridView _gridButtons(List<Map<String, String>> buttons, int crossAxisCount,
      {Color textColor = Colors.white}) {
    double gridSpace = 5.0;
    return GridView.count(
      crossAxisSpacing: gridSpace,
      mainAxisSpacing: gridSpace,
      crossAxisCount: crossAxisCount,
      //設(shè)置以下兩個(gè)參數(shù),禁止GridView的滾動(dòng),防止與 ListView 沖突
      shrinkWrap: true,
      physics: NeverScrollableScrollPhysics(),
      children: buttons.map((item) {
        return _getMenus(item['icon'], item['name'], color: textColor);
      }).toList(),
    );
  }
}

ListView 構(gòu)建完整頁(yè)面:實(shí)際的整個(gè)頁(yè)面很簡(jiǎn)單,只需要將各個(gè)區(qū)域放入到 ListView 的 children 屬性即可,從這里也可以看出,將子組件盡可能細(xì)化,不但能夠提高代碼復(fù)用性,還可以降低嵌套層級(jí),提高代碼的可讀性和可維護(hù)性。

@override
  Widget build(BuildContext context) {
    return Scaffold(
      body: ListView(
        children: [
          _headerGridButtons(),
          _dynamicGridButtons(GridMockData.financeGrids(), '金融理財(cái)'),
          _dynamicGridButtons(GridMockData.serviceGrids(), '生活服務(wù)'),
          _dynamicGridButtons(GridMockData.thirdpartyGrids(), '購(gòu)物消費(fèi)'),
        ],
      ),
    );
  }

Mock 數(shù)據(jù)準(zhǔn)備
按鈕數(shù)據(jù)均使用 Mock 數(shù)據(jù),這里只是返回一個(gè) List<Map<String, String>>數(shù)組對(duì)象,對(duì)象里是每個(gè)菜單的圖標(biāo)文件名稱和菜單名稱,下面是金融服務(wù)區(qū)域的菜單 Mock方法。

static List<Map<String, String>> financeGrids() {
    return [
      {'name': '信用卡還款', 'icon': 'images/grid-buttons/grid-1-1.png'},
      {'name': '借錢', 'icon': 'images/grid-buttons/grid-1-2.png'},
      {'name': '理財(cái)', 'icon': 'images/grid-buttons/grid-1-3.png'},
      {'name': '保險(xiǎn)', 'icon': 'images/grid-buttons/grid-1-4.png'},
    ];
  }

其他待改進(jìn)的地方:從代碼中可以看出,訪問(wèn)按鈕的時(shí)候是使用 Map 對(duì)象的鍵來(lái)訪問(wèn)的,需要使用['name']或['icon']來(lái)訪問(wèn),這種方式非常不利于編碼,而且很容易拼寫(xiě)錯(cuò)誤。因此,實(shí)際使用中應(yīng)當(dāng)將 Json 對(duì)象(即 Map)轉(zhuǎn)換為實(shí)體類,這樣就可以通過(guò)訪問(wèn)實(shí)體類的屬性來(lái)設(shè)置菜單的參數(shù),實(shí)際維護(hù)起來(lái)更為方便。

結(jié)語(yǔ):

Flutter 提供的基礎(chǔ) UI 組件庫(kù)能夠滿足絕大部分復(fù)雜頁(yè)面布局,通過(guò)各種布局組件的組合即可完成。因此,熟悉基礎(chǔ)的布局組件的特性十分重要。同時(shí),需要注意組件的拆分和抽離完成子組件的封裝,提高復(fù)用性的同時(shí)也避免了嵌套層級(jí)過(guò)深的問(wèn)題。

以上就是Flutter 仿微信支付界面的實(shí)現(xiàn)的詳細(xì)內(nèi)容,更多關(guān)于Flutter 微信支付界面的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論