(兩百三十四)學習Flutter 開發文檔 - Widgets介紹(一)

Widgets 介紹

Flutter 從 React 中吸取靈感,通過現代化框架創建出精美的組件。它的核心思想是用 widget 來構建你的 UI 界面。 Widget 描述了在當前的配置和狀態下視圖所應該呈現的樣子。當 widget 的狀態改變時,它會重新構建其描述(展示的 UI),框架則會對比前後變化的不同,以確定底層渲染樹從一個狀態轉換到下一個狀態所需的最小更改。

待續

如果你想通過深入瞭解一些代碼來更好地掌握 Flutter,請查閱 Codelab: Flutter 佈局基礎教程Flutter 中的佈局爲你的 Flutter 應用加入交互體驗 這三篇文章。

 

Hello world

創建一個最小的 Flutter 應用簡單到僅需調用 runApp() 方法並傳入一個 widget 即可:

import 'package:flutter/material.dart';

void main() {
  runApp(
    Center(
      child: Text(
        'Hello, world!',
        textDirection: TextDirection.ltr,
      ),
    ),
  );
}

runApp() 函數會持有傳入的 Widget,並且使它成爲 widget 樹中的根節點。在這個例子中,Widget 樹有兩個 widgets, Center widget 及其子 widget ——Text 。框架會強制讓根 widget 鋪滿整個屏幕,也就是說“Hello World”會在屏幕上居中顯示。在這個例子我們需要指定文字的方向,當使用 MaterialApp widget 時,你就無需考慮這一點,之後我們會進一步的描述。

在寫應用的過程中,取決於是否需要管理狀態,你通常會創建一個新的組件繼承 StatelessWidgetStatefulWidget。 Widget 的主要工作是實現 build方法,該方法根據其它較低級別的 widget 來描述這個 widget。框架會逐一構建這些 widget,直到最底層的描述 widget 幾何形狀的 RenderObject

 

comment:這個佈局其實很簡單,對照Android其實就是一個佈局嵌套了一個text

 

基礎 widgets

Flutter 自帶了一套強大的基礎 widgets,下面列出了一些常用的:

Text
Text widget 可以用來在應用內創建帶樣式的文本。

Row, Column
這兩個 flex widgets 可以讓你在水平 (Row) 和垂直(Column) 方向創建靈活的佈局。它是基於 web 的 flexbox 佈局模型設計的。

Stack
Stack widget 不是線性(水平或垂直)定位的,而是按照繪製順序將 widget 堆疊在一起。你可以用 Positioned widget 作爲Stack 的子 widget,以相對於 Stack 的上,右,下,左來定位它們。 Stack 是基於 Web 中的絕對位置佈局模型設計的。

Container
Container widget 可以用來創建一個可見的矩形元素。 Container 可以使用 BoxDecoration 來進行裝飾,如背景,邊框,或陰影等。 Container 還可以設置外邊距、內邊距和尺寸的約束條件等。另外,Container可以使用矩陣在三維空間進行轉換。

下面是一些簡單的 widget,它們結合了上面提到的 widget 和一些其他的 widget:

import 'package:flutter/material.dart';

class MyAppBar extends StatelessWidget {
  MyAppBar({this.title});

  // Fields in a Widget subclass are always marked "final".

  final Widget title;

  @override
  Widget build(BuildContext context) {
    return Container(
      height: 56.0, // in logical pixels
      padding: const EdgeInsets.symmetric(horizontal: 8.0),
      decoration: BoxDecoration(color: Colors.blue[500]),
      // Row is a horizontal, linear layout.
      child: Row(
        // <Widget> is the type of items in the list.
        children: <Widget>[
          IconButton(
            icon: Icon(Icons.menu),
            tooltip: 'Navigation menu',
            onPressed: null, // null disables the button
          ),
          // Expanded expands its child to fill the available space.
          Expanded(
            child: title,
          ),
          IconButton(
            icon: Icon(Icons.search),
            tooltip: 'Search',
            onPressed: null,
          ),
        ],
      ),
    );
  }
}

class MyScaffold extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // Material is a conceptual piece of paper on which the UI appears.
    return Material(
      // Column is a vertical, linear layout.
      child: Column(
        children: <Widget>[
          MyAppBar(
            title: Text(
              'Example title',
              style: Theme.of(context).primaryTextTheme.title,
            ),
          ),
          Expanded(
            child: Center(
              child: Text('Hello, world!'),
            ),
          ),
        ],
      ),
    );
  }
}

void main() {
  runApp(MaterialApp(
    title: 'My app', // used by the OS task switcher
    home: MyScaffold(),
  ));
}

對照界面就看的很明白,其實就是一個水平佈局的actionbar + 一個之前的hello world

不好的地方在於systemUi的狀態欄和這個actionbar重疊了,點擊不了。。。

改了下幾個參數的配置,查看作用,熱加載還是很好用的

      height: 556.0, // in logical pixels
      padding: const EdgeInsets.symmetric(horizontal: 48.0),
      decoration: BoxDecoration(color: Colors.blue[100]),

效果如下

高度和pading很好理解,那個藍色裏面的數字應該是指藍色的深度,越大越深

請確認在 pubspec.yaml 文件中 flutter 部分有 uses-material-design: true 這條,它能讓你使用預置的 Material icons

name: my_app
flutter:
  uses-material-design: true

爲了獲得(MaterialApp)主題的數據,許多 Material Design 的 widget 需要在 MaterialApp 中才能顯現正常。因此,請使用 MaterialApp 運行應用。

MyAppBar widget 創建了一個高 56 獨立像素,左右內邊距 8 像素的 Container。在容器內,MyAppBarRow 佈局來組織它的子元素。中間的子 widget(title widget),被標記爲 Expanded,這意味着它會擴展以填充其它子 widget 未使用的可用空間。你可以定義多個Expanded 子 widget,並使用 flex 參數確定它們佔用可用空間的比例。

MyScaffold widget 將其子 widget 組織在垂直列中。在列的頂部,它放置一個 MyAppBar 實例,並把 Text widget 傳給它來作爲應用的標題。把 widget 作爲參數傳遞給其他 widget 是一個很強大的技術,它可以讓你以各種方式創建一些可重用的通用組件。最後,MyScaffold 使用 Expanded 來填充剩餘空間,其中包含一個居中的消息。

有關更多信息,請參閱 佈局

 

使用 Material 組件

Flutter 提供了許多 widget,可幫助你構建遵循 Material Design 的應用。 Material 應用以 MaterialApp widget 開始,它在你的應用的底層下構建了許多有用的 widget。這其中包括 Navigator,它管理由字符串標識的 widget 棧,也稱爲“routes”。 Navigator 可以讓你在應用的頁面中平滑的切換。使用 MaterialApp widget 不是必須的,但這是一個很好的做法。

import 'package:flutter/material.dart';

void main() {
  runApp(MaterialApp(
    title: 'Flutter Tutorial',
    home: TutorialHome(),
  ));
}

class TutorialHome extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // Scaffold is a layout for the major Material Components.
    return Scaffold(
      appBar: AppBar(
        leading: IconButton(
          icon: Icon(Icons.menu),
          tooltip: 'Navigation menu',
          onPressed: null,
        ),
        title: Text('Example title'),
        actions: <Widget>[
          IconButton(
            icon: Icon(Icons.search),
            tooltip: 'Search',
            onPressed: null,
          ),
        ],
      ),
      // body is the majority of the screen.
      body: Center(
        child: Text('Hello, world!'),
      ),
      floatingActionButton: FloatingActionButton(
        tooltip: 'Add', // used by assistive technologies
        child: Icon(Icons.add),
        onPressed: null,
      ),
    );
  }
}

效果

現在我們已經從 MyAppBarMyScaffold 切換到了 material.dart 中的 AppBarScaffold widget,我們的應用更“Material”了一些。例如,標題欄有了陰影,標題文本會自動繼承正確的樣式,此外還添加了一個浮動操作按鈕。

注意,widget 作爲參數傳遞給了另外的 widget。 Scaffold widget 將許多不同的 widget 作爲命名參數,每個 widget 都放在了 Scofford 佈局中的合適位置。同樣的,AppBar widget 允許我們給 leadingtitle widget 的 actions 傳遞 widget。這種模式在整個框架會中重複出現,在設計自己的 widget 時可以考慮這種模式。

有關更多信息,請參閱 Material 組件

備忘

Material 是 Flutter 中兩個自帶的設計之一,如果想要以 iOS 爲主的設計,可以參考 Cupertino components,它有自己版本的 CupertinoAppCupertinoNavigationBar.。

 

處理手勢

大多數應用都需要通過系統來處理一些用戶交互。構建交互式應用程序的第一步是檢測輸入手勢,這裏通過創建一個簡單的按鈕來了解其工作原理:

class MyButton extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
        print('MyButton was tapped!');
      },
      child: Container(
        height: 36.0,
        padding: const EdgeInsets.all(8.0),
        margin: const EdgeInsets.symmetric(horizontal: 8.0),
        decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(5.0),
          color: Colors.lightGreen[500],
        ),
        child: Center(
          child: Text('Engage'),
        ),
      ),
    );
  }
}

GestureDetector widget 沒有可視化的展現,但它能識別用戶的手勢。當用戶點擊 Container 時, GestureDetector 會調用其 onTap() 回調,在這裏會向控制檯打印一條消息。你可以使用 GestureDetector 檢測各種輸入的手勢,包括點擊,拖動和縮放。

許多 widget 使用 GestureDetector 爲其他 widget 提供可選的回調。例如,IconButtonRaisedButtonFloatingActionButton widget 都有 onPressed() 回調,當用戶點擊 widget 時就會觸發這些回調。

有關更多信息,請參閱 Flutter 中的手勢

試了下,這個按鈕有圓角,設置了內邊距,點擊終端會打印

I/flutter ( 3206): MyButton was tapped!
I/flutter ( 3206): MyButton was tapped!
I/flutter ( 3206): MyButton was tapped!
I/flutter ( 3206): MyButton was tapped!

 

 

 

 

 

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