Flutter 構建布局

2020-08-27 14:46 更新

第0步: 設置

首先, 獲取代碼:

  • 確保您已經(jīng)安裝好了 set up 您的Flutter環(huán)境.
  • 創(chuàng)建一個基本的Flutter應用程序.

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

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


第一步: 繪制布局圖

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

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

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

diagramming the rows in the lakes screenshot

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

diagramming the widgets in the Title section

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

diagramming the widgets in the button section

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


Step 2: 實現(xiàn)標題行

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

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

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

這是實現(xiàn)標題行的代碼。

Note: If you have problems, you can check your code against lib/main.dart on GitHub.

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    Widget titleSection = new Container(
      padding: const EdgeInsets.all(32.0),
      child: new Row(
        children: [
          new Expanded(
            child: new Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                new Container(
                  padding: const EdgeInsets.only(bottom: 8.0),
                  child: new Text(
                    'Oeschinen Lake Campground',
                    style: new TextStyle(
                      fontWeight: FontWeight.bold,
                    ),
                  ),
                ),
                new Text(
                  'Kandersteg, Switzerland',
                  style: new TextStyle(
                    color: Colors.grey[500],
                  ),
                ),
              ],
            ),
          ),
          new Icon(
            Icons.star,
            color: Colors.red[500],
          ),
          new Text('41'),
        ],
      ),
    );
  //...
}

提示: 將代碼粘貼到應用程序中時,縮進可能會變形。您可以通過右鍵單擊,選擇 Reformat with dartfmt 來在IntelliJ中修復此問題?;蛘撸诿钚兄?,您可以使用 dartfmt。

提示: 為了獲得更快的開發(fā)體驗,請嘗試使用Flutter的熱重載功能。 熱重載允許您修改代碼并查看更改,而無需完全重新啟動應用程序。 IntelliJ的Flutter插件支持熱重載,或者您可以從命令行觸發(fā)。 有關更多信息,請參閱Hot Reloads vs 應用程序重新啟動。


第3步: 實現(xiàn)按鈕行

按鈕部分包含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,
      ),

    //...
}

由于構建每個列的代碼幾乎是相同的,因此使用一個嵌套函數(shù),如buildButtonColumn,它會創(chuàng)建一個顏色為primary color,包含一個Icon和Text的 Widget 列。

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

    Column buildButtonColumn(IconData icon, String label) {
      Color color = Theme.of(context).primaryColor;

      return new Column(
        mainAxisSize: MainAxisSize.min,
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          new Icon(icon, color: color),
          new Container(
            margin: const EdgeInsets.only(top: 8.0),
            child: new Text(
              label,
              style: new TextStyle(
                fontSize: 12.0,
                fontWeight: FontWeight.w400,
                color: color,
              ),
            ),
          ),
        ],
      );
    }
  //...
}

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

通過調(diào)用函數(shù)并傳遞icon和文本來構建這些列。然后在行的主軸方向通過 MainAxisAlignment.spaceEvenly 平均的分配每個列占據(jù)的行空間。

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

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


第4步:實現(xiàn)文本部分

將文本放入容器中,以便沿每條邊添加32像素的填充。softwrap屬性表示文本是否應在軟換行符(例如句點或逗號)之間斷開。

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

    Widget textSection = new Container(
      padding: const EdgeInsets.all(32.0),
      child: new 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,
      ),
    );
  //...
}


第5步:實現(xiàn)圖像部分

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

body: new ListView(
  children: [
    new Image.asset(
      'images/lake.jpg',
      height: 240.0,
      fit: BoxFit.cover,
    ),
    // ...
  ],
)

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


Step 6: 整合

在最后一步,你將上面這些組裝在一起。這些widget放置到ListView中,而不是列中,因為在小設備上運行應用程序時,ListView會自動滾動。

//...
body: new ListView(
  children: [
    new Image.asset(
      'images/lake.jpg',
      width: 600.0,
      height: 240.0,
      fit: BoxFit.cover,
    ),
    titleSection,
    buttonSection,
    textSection,
  ],
),
//...


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號