在Flutter中構建布局


這是在Flutter中構建布局的指南。首先,您將構建以下屏幕截圖的布局。然后回過頭, 本指南將解釋Flutter的布局方法,並說明如何在屏幕上放置一個widget。在討論如何水平和垂直放置widget之后,會介紹一些最常見的布局widget:

如果你想對布局機制有一個“全貌”的理解,請參考Flutter的布局方法

第0步:創建應用程序基代碼

1, 獲取代碼: 創建一個基本的“Hello World”Fluuer應用程序。

2.更改應用程序欄標題和應用程序標題,如下所示:

Widget build(BuildContext context) {
  return MaterialApp(
      title: 'Flutter layout demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: new Scaffold(
        appBar: AppBar(
          title: Text('Flutter layout demo'),
        ),
        body: new Center(
          child: new Text('Hello World'),
        ),
      ),
    );
}

接下來,將圖像添加到示例中:

  • 在工程根目錄創建一個 images 文件夾.
  • 添加 lake.jpg. (請注意,wget不能保存此二進制文件。)
  • 更新 pubspec.yaml 文件以包含 assets 標簽. 這樣才會使您的圖片在代碼中可用。

第一步: 繪制布局圖

第一步是將布局拆分成基本的元素:

  • 找出行和列.
  • 布局包含網格嗎?
  • 有重疊的元素嗎?
  • 是否需要選項卡?
  • 注意需要對齊、填充和邊框的區域.

首先,確定更大的元素。在這個例子中,四個元素排列成一列:一個圖像,兩個行和一個文本塊

diagramming the rows in the lakes screenshot

接下來,繪制每一行。第一行稱其為標題部分,有三個子項:一列文字,一個星形圖標和一個數字。它的第一個子項,列,包含2行文字。 第一列占用大量空間,所以它必須包裝在Expanded widget中。

diagramming the widgets in the Title section

第二行稱其為按鈕部分,也有3個子項:每個子項都是一個包含圖標和文本的列。

diagramming the widgets in the button section

一旦拆分好布局,最簡單的就是采取自下而上的方法來實現它。為了最大限度地減少深度嵌套布局代碼的視覺混淆,將一些實現放置在變量和函數中。

第二步: 實現標題行

首先,將在標題部分構建左列。在myapp類的build()方法的頂部添加以下代碼:

Widget titleSection = Container(
  padding: const EdgeInsets.all(32),
  child: Row(
    children: [
      Expanded(
        /*1*/
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            /*2*/
            Container(
              padding: const EdgeInsets.only(bottom: 8),
              child: Text(
                'Oeschinen Lake Campground',
                style: TextStyle(
                  fontWeight: FontWeight.bold,
                ),
              ),
            ),
            Text(
              'Kandersteg, Switzerland',
              style: TextStyle(
                color: Colors.grey[500],
              ),
            ),
          ],
        ),
      ),
      /*3*/
      Icon(
        Icons.star,
        color: Colors.red[500],
      ),
      Text('41'),
    ],
  ),
);

將Column(列)放入Expanded中會拉伸該列以使用該行中的所有剩余空閑空間。 設置crossAxisAlignment屬性值為CrossAxisAlignment.start,這會將該列中的子項左對齊。

將第一行文本放入Container中,然后底部添加8像素填充。列中的第二個子項(也是文本)顯示為灰色。

標題行中的最后兩項是一個紅色的星形圖標和文字“41”。將整行放在容器中,並沿着每個邊緣填充32像素。

將標題部分添加替換到應用程序主體,如下所示:

    return MaterialApp(
      title: 'Flutter layout demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: new Scaffold(
        appBar: AppBar(
          title: Text('Flutter layout demo'),
        ),
        body: Column(
          children: [
            titleSection,
          ],
        ),
      ),
    );

如果有問題,請將代碼與lib/main.dart進行比較。

第3步: 實現按鈕行

按鈕部分包含3個使用相同布局的列 - 上面一個圖標,下面一行文本。該行中的列平均分布行空間, 文本和圖標顏色為主題中的primary color,它在應用程序的build()方法中設置為藍色:

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    //...

    return new MaterialApp(
      title: 'Flutter Demo',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),

    //...
}

由於構建每一列的代碼幾乎相同,因此創建一個嵌套函數,如buildButtonColumn,它會創建一個顏色為primary color,包含一個Icon和Text的 Widget 列。

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // ···
  }

  Column _buildButtonColumn(Color color, IconData icon, String label) {
    return Column(
      mainAxisSize: MainAxisSize.min,
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        Icon(icon, color: color),
        Container(
          margin: const EdgeInsets.only(top: 8),
          child: Text(
            label,
            style: TextStyle(
              fontSize: 12,
              fontWeight: FontWeight.w400,
              color: color,
            ),
          ),
        ),
      ],
    );
  }
}

構建函數將圖標直接添加到列(Column)中。將文本放入容器以在文本上方添加填充,將其與圖標分開。

通過調用函數並傳遞特定於該列的顏色、圖標和文本,生成包含這些列的行。使用mainaxisalignment.space沿主軸對齊各列,使每列前后的自由空間均勻排列。在build()方法內的titleSection聲明下方添加以下代碼:

Color color = Theme.of(context).primaryColor;

Widget buttonSection = Container(
  child: Row(
    mainAxisAlignment: MainAxisAlignment.spaceEvenly,
    children: [
      _buildButtonColumn(color, Icons.call, 'CALL'),
      _buildButtonColumn(color, Icons.near_me, 'ROUTE'),
      _buildButtonColumn(color, Icons.share, 'SHARE'),
    ],
  ),
);

將按鈕部分添加到正文:

    body: Column(
          children: [
            titleSection,
            buttonSection,
          ],
      ),

如果有問題,請將代碼與lib/main.dart進行比較。

第4步:實現文本部分

將文本部分定義為變量。將文本放入容器中,並沿每個邊緣添加填充。在buttonsection聲明的正下方添加以下代碼:

Widget textSection = Container(
  padding: const EdgeInsets.all(32),
  child: Text(
    'Lake Oeschinen lies at the foot of the Blüemlisalp in the Bernese '
        'Alps. Situated 1,578 meters above sea level, it is one of the '
        'larger Alpine Lakes. A gondola ride from Kandersteg, followed by a '
        'half-hour walk through pastures and pine forest, leads you to the '
        'lake, which warms to 20 degrees Celsius in the summer. Activities '
        'enjoyed here include rowing, and riding the summer toboggan run.',
    softWrap: true,
  ),
);

通過將softwrap設置為true,文本行將在換行前填充列寬。

將文本部分添加到正文:

    body: Column(
          children: [
            titleSection,
            buttonSection, //將按鈕部分添加到正文
            textSection, //將文本部分添加到正文
          ],
        ),

如果有問題,請將代碼與lib/main.dart進行比較。

第5步:實現圖像部分

四列元素中的三個現在已經完成,只剩下圖像部分。該圖片可以在Creative Commons許可下在線獲得, 但是它非常大,且下載緩慢。在步驟0中,您已經將該圖像包含在項目中並更新了pubspec文件,所以現在可以從代碼中直接引用它:

    children: [
            Image.asset( 
              'images/lake.jpg',
              width: 600,
              height: 240,
              fit: BoxFit.cover,
            ),  //從代碼中引用圖像
            titleSection,
            buttonSection, //將按鈕部分添加到正文
            textSection, //將文本部分添加到正文
          ],

BoxFit.cover 告訴框架,圖像應該盡可能小,但覆蓋整個渲染框.

如果有問題,請將代碼與lib/main.dart進行比較。

第6步: 整合

在最后一步中,將所有元素排列在ListView中,而不是列中,因為當應用程序在小型設備上運行時,ListView支持應用程序主體滾動。

    body: new ListView(
          children: [
            Image.asset( 
              'images/lake.jpg',
              width: 600,
              height: 240,
              fit: BoxFit.cover,
            ), //從代碼中引用圖像
            titleSection,
            buttonSection, //將按鈕部分添加到正文
            textSection, //將文本部分添加到正文
          ],
        ),

Dart code: main.dart
Image: images
Pubspec: pubspec.yaml

結束了!當您熱重載應用程序時,就會看到和截圖中相同界面。您可以參考 給Flutter APP 添加交互來給您的應用添加交互。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM