Flutter 例子1 - 建立一個簡單的靜態界面

爲方便起見,文中有些地方會把widget稱做組件部件android

建立一個靜態界面

效果圖
參考教程 flutter.io/tutorials/l…

添加了一張圖片 canvas

圖片資源存放位置

pubspec.yaml中添加assetsapi

# To add assets to your application, add an assets section, like this:
 assets:
 - images/android_1.jpg
複製代碼

這個地方要注意縮進,不然AS可能會不容許編譯。app

從效果圖中能夠看到,頁面中有一張大圖片,一個小標題欄,有3個按鈕的橫欄,以及下方的大段文字。 整個視圖用一個ListView包含了所需的全部widget。寫這個界面的過程,就像是Android中寫layout文件。less

approach_1.dart代碼。項目中使用的是material design的圖標。ide

import 'package:flutter/material.dart';

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {
  // 應用的根widget
  @override
  Widget build(BuildContext context) {
    // 圖片下方的小標題欄
    Widget titleSection = new Container(
      padding: const EdgeInsets.all(32.0),
      child: new Row(
        children: <Widget>[
          new Expanded(child:
          new Column(crossAxisAlignment: CrossAxisAlignment.start,
            children: <Widget>[
              new Container(padding: const EdgeInsets.only(bottom: 8.0),
                child: new Text('Android Device',
                  style: new TextStyle(fontWeight: FontWeight.bold),),),
              new Text(
                'Rust Fisher', style: new TextStyle(color: Colors.grey[500]),)
            ],
          )),
          new Icon(Icons.star, color: Colors.red,),
          new Text('42')
        ],
      ),
    );

    // 定義在方法裏面的方法 nested function
    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,),
            ),
          ),
        ],
      );
    }

    Widget buttonSection = new Container(
      child: new Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: <Widget>[
          buildButtonColumn(Icons.call, '通話'),
          buildButtonColumn(Icons.near_me, '定位'),
          buildButtonColumn(Icons.share, '分享'),
        ],
      ),);

    Widget textSection = new Container(padding: const EdgeInsets.all(32.0),
      child: new Text(
        '''
Flutter Tutorials

The Flutter Tutorials teach you how to use the Flutter framework to build mobile applications for iOS and Android.

Choose from the following:

·Building Layouts in Flutter
    How to build layouts using Flutter’s layout mechanism. Once you’ve learned basic principles, you’ll build the layout for a sample screenshot.
·Adding Interactivity to Your Flutter App
    You’ll extend the simple layout app created in 「Building Layouts in Flutter」 to make an icon tappable. Different ways of managing a widget’s state are also discussed.
·Animations in Flutter
    Explains the fundamental classes in the Flutter animation package (controllers, Animatable, curves, listeners, builders), as it guides you through a progression of tween animations using different aspects of the animation APIs.
·Internationalizing Flutter Apps
    Learn how to internationalize your Flutter application. A guide through the widgets and classes that enable apps to display their content using the user’s language and formatting conventions.
'''
        , softWrap: true,),);

    return new MaterialApp(
      title: 'Flutter Demo',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: new Scaffold(
        appBar: new AppBar(title: new Text('Flutter Approach 1'),),
        body: new ListView(children: <Widget>[
          new Image.asset(
            'images/android_1.jpg', width: 600.0,
            height: 240.0,
            fit: BoxFit.cover,),
          titleSection,
          buttonSection,
          textSection
        ],),),
    );
  }
}
複製代碼

因flutter的繪製特性,flutter是在本身的canvas上繪製界面。 Android開發者選項中-顯示佈局邊界功能對flutter繪製出的界面並沒什麼做用。佈局

此時能夠用debugPaintSizeEnabled,查看widget邊界flex

import 'package:flutter/rendering.dart';

void main() {
  debugPaintSizeEnabled = true; // 這個能夠看到UI的邊界
// runApp(new MyApp());
}
複製代碼

改變這個屬性時,可能須要從新編譯運行。ui

Flutter layout的要點

  • Widget是用來創建UI的類
  • Widget用於layout和UI元素
  • 將簡單的widget組合成複雜的widget Flutter layout核心機制是widget。幾乎全部的東西都是widget。

設計一個widget

要點:this

  • app自己也是一個widget。
  • 建立一個widget能簡單地添加到layout widget中。
  • 要在設備上展現一個widget,將其添加到app widget上。
  • Scaffold是很容易使用的,它來自Material組件庫;它提供了一個默認標題欄,背景顏色,擁有用於添加drawer、snack bar和bottom sheet的api。
  • 也能夠僅使用widget庫中的標準組件。

一個非material design的例子

非material design組件,沒有AppBar,沒有背景顏色,沒有標題。這些東西都要本身設置。

import 'package:flutter/material.dart';

void main() {
  runApp(new MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Container(
      decoration: new BoxDecoration(color: Colors.white70),
      child: new Center(
        child: new Text('my home page', textDirection: TextDirection.ltr,
          style: new TextStyle(fontSize: 40.0, color: Colors.black26),),
      ),
    );
  }

}
複製代碼

在手機上運行效果如圖

device-2018-06-25-110221.png

水平或豎直放置多個組件

豎直或水平放置組件是常見的佈局方式。能夠用Row widget來水平放置組件,或用Column widget垂直放置組件。

  • Row和Column是最經常使用的2中佈局方式
  • Row和Column均接受多個子widget
  • 子widget能夠是Row、Column或者其餘負責組件
  • 能夠指定子widget的對齊方式(垂直和水平方式都可)
  • 可延展或約束子widget
  • 能夠指定子widget使用父widget空餘空間的方式

Sizing widgets

若是要一個widget和它的同級widget同樣佔用自身寬度的兩倍區域。能夠把它放進Expanded widget裏面。認準Expanded。 Expanded widget有一個flex屬性,一個int值決定widget佔用的比例。默認是1。(有點就像LinearLayout裏面的weight)

下面是一個顯示2張圖片的例子

import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';

void main() {
  debugPaintSizeEnabled = true; // 這個能夠看到UI的邊界
  runApp(new MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: '隨便一個title',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: new MyHomePage(title: 'Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

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

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text(widget.title),
      ),
      body: new Center(
        child: new Row(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: [
            new Expanded(child: new Image.asset('images/p_box1.png')),
            new Expanded(
                flex: 2, child: new Image.asset('images/pic_kotlin_s.jpg')),
          ],
        ),
      ),
    );
  }
}
複製代碼

Sizing widgets效果圖

Packing widgets

默認狀況下,一行或一列會佔用盡量多的空間。但若是想把子widget緊密排列,須要設置mainAxisSizeMainAxisSize.min。 下面的例子是把幾個圖標緊湊排列。

Packing widgets效果圖

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text(widget.title),
      ),
      body: new Center(
        child: new Row(
          mainAxisSize: MainAxisSize.min,
          children: [
            new Icon(Icons.star, color: Colors.green,),
            new Icon(Icons.star, color: Colors.green[400],),
            new Icon(Icons.star, color: Colors.green[300],),
            new Icon(Icons.star, color: Colors.green[200],),
            new Icon(Icons.star, color: Colors.green[100],),
          ],
  // 無盡的括號......
}
複製代碼

Nesting rows and columns

能夠把Row和Column混起來用,組合到widget裏面。

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    var ratings = new Container(
      padding: EdgeInsets.all(20.0),
      child: new Row(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: <Widget>[
          new Row(mainAxisSize: MainAxisSize.min, children: <Widget>[
            new Icon(Icons.star, color: Colors.red,),
            new Icon(Icons.star, color: Colors.red[400],),
            new Icon(Icons.star, color: Colors.red[300],),
            new Icon(Icons.star, color: Colors.red[200],),
            new Icon(Icons.star, color: Colors.red[100],),
          ],),
          new Text('42 Read'),
        ],
      ),
    );

    return new Scaffold(
      appBar: new AppBar(
        title: new Text(widget.title),
      ),
      body: new Center(
          child: ratings
      ),
    );
  }
// ......
}
複製代碼

Row和Column混起來用
用變量 ratings來表示比較複雜的widget,能夠減緩一些縮進和括號問題。

橫屏的一個例子

橫屏的一個例子
使用了Card這個widget。

import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';

void main() {
// debugPaintSizeEnabled = true; // 這個能夠看到UI的邊界
  runApp(new MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: '隨便一個title',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: new MyHomePage(title: 'Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

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

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    var ratings = new Container(
      padding: EdgeInsets.all(20.0),
      child: new Row(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: <Widget>[
          new Row(mainAxisSize: MainAxisSize.min, children: <Widget>[
            new Icon(Icons.star, color: Colors.red,),
            new Icon(Icons.star, color: Colors.red[400],),
            new Icon(Icons.star, color: Colors.red[300],),
            new Icon(Icons.star, color: Colors.red[200],),
            new Icon(Icons.star, color: Colors.red[100],),
          ],),
          new Text('42 Read'),
        ],
      ),
    );

    var descTextStyle = new TextStyle(
      color: Colors.black,
      fontWeight: FontWeight.w800,
      fontFamily: 'Roboto',
      letterSpacing: 0.5,
      fontSize: 12.0,
      height: 2.0,
    );
    var iconList = DefaultTextStyle.merge(
      style: descTextStyle,
      child: new Container(
        padding: new EdgeInsets.all(2.0),
        child: new Row(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: [
            new Column(
              children: [
                new Icon(Icons.kitchen, color: Colors.red[500]),
                new Text('PREP:'),
                new Text('25 min'),
              ],
            ),
            new Column(
              children: [
                new Icon(Icons.timer, color: Colors.red[500]),
                new Text('COOK:'),
                new Text('1 hr'),
              ],
            ),
            new Column(
              children: [
                new Icon(Icons.restaurant, color: Colors.red[500]),
                new Text('FEEDS:'),
                new Text('4-6'),
              ],
            ),
          ],
        ),
      ),
    );

    var leftColumn = new Container(
      padding: new EdgeInsets.fromLTRB(20.0, 20.0, 20.0, 2.0),
      child: new Column(
        children: [
          ratings,
          iconList,
        ],
      ),
    );

    return new Scaffold(
      appBar: new AppBar(
        title: new Text(widget.title),
      ),
      body: new Center(
        child: new Container(
          margin: new EdgeInsets.fromLTRB(0.0, 40.0, 0.0, 30.0),
// height: 600.0,
          child: new Card(
            child: new Row(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
                new Container(
// width: 440.0,
                  child: leftColumn,
                ),
                new Expanded(
                    child: new Image.asset('images/android_1.jpg'))
              ],
            ),
          ),
        ),
      ),
    );
  }
}
複製代碼
相關文章
相關標籤/搜索