爲方便起見,文中有些地方會把widget
稱做組件
或部件
android
添加了一張圖片 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
要點:this
非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),),
),
);
}
}
複製代碼
在手機上運行效果如圖
豎直或水平放置組件是常見的佈局方式。能夠用Row widget來水平放置組件,或用Column widget垂直放置組件。
若是要一個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')),
],
),
),
);
}
}
複製代碼
默認狀況下,一行或一列會佔用盡量多的空間。但若是想把子widget緊密排列,須要設置mainAxisSize
爲 MainAxisSize.min
。 下面的例子是把幾個圖標緊湊排列。
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],),
],
// 無盡的括號......
}
複製代碼
能夠把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
),
);
}
// ......
}
複製代碼
用變量
ratings
來表示比較複雜的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'))
],
),
),
),
),
);
}
}
複製代碼