Flutter中有许多常用的控件,比如下面的:
Text:文本控件,相当于安卓TextView;
Row,Column:相当于安卓LinearLayout的两个方向;
Stack:与Positioned控件配合,放到top, right, bottom, or left;
Container:矩形控件,可与BoxDecoration配合来装饰 background, a border, or a shadow,可用margins, padding, and constraints来设置其尺寸。
当然还有很多其他的控件,后面用到的时候再一一介绍,这里大家先有个印象。
下面是一个常见页面的简单布局的完整代码:
import 'package:flutter/material.dart';
class MyAppBar extends StatelessWidget{
MyAppBar({this.title});
final Widget title;
@override
Widget build(BuildContext context) {
return new Container(//矩形控件
height: 50.0,//顶部导航栏的高度
padding: const EdgeInsets.symmetric(horizontal: 10.0),//顶部导航栏与两侧的距离,horizontal表示水平方向
decoration: new BoxDecoration(color: Colors.blue[500]),//顶部导航栏颜色
child: new Row(//Row相当于LinearLayout水平布局,包括菜单按钮,标题,搜索按钮
children: <Widget>[new IconButton(icon:new Icon( Icons.menu), onPressed: null),//左上角菜单按钮,系统提供了图片,无点击事件
new Expanded(child: title),//标题文本充满整行布局
new IconButton(icon: new Icon(Icons.search), onPressed: null),],//右上角搜索按钮,系统提供了图片,无点击事件
), );
}
}
class MyScalffold extends StatelessWidget{
@override
Widget build(BuildContext context) {
return new Material(
child: new Column(//Column相当于LinearLayout垂直布局,包括顶部标题栏和下面的内容
children: <Widget>[
new MyAppBar(title: new Text("我是标题",style: Theme.of(context).primaryTextTheme.title,),
),new Expanded(child: new Center(child: new Text('内容:Hello wrold'),),),
],
),
);
}
}
void main(){//主函数入口
runApp(new MaterialApp(title: 'My app',home: new MyScalffold(),));
}
运行结果
上面代码同样界面的MD(Material Design)风格
import 'package:flutter/material.dart';
void main(){
runApp(new MaterialApp(title: 'Flutter Tutorial',home: new TutorialHome(),));
}
class TutorialHome extends StatelessWidget{
@override
Widget build(BuildContext context) {
return new Scaffold(//替换上面代码中的MyScaffold
appBar: new AppBar(//替换上面代码中的MyAppBar
leading: new IconButton(
icon: new Icon(Icons.menu), tooltip: 'ddd', onPressed: null,),
title: new Text('MD风格'),
actions: <Widget>[new IconButton(icon: new Icon(Icons.search), onPressed: null)],
),
body: new Center(child: new Text('Hello World'),),
floatingActionButton: new FloatingActionButton(tooltip: '增加',child: new Icon(Icons.add), onPressed: null),
);
}
}
运行结果
我们将上个工程中自定义的MyAppBar和MyScaffold 切换为系统AppBar和 Scaffold,我们就使用了MD风格,比如说顶部导航栏有阴影效果等等,同时代码是不是简洁了许多?。值得注意的是,我们将AppBar控件作为参数,传递给另外一个控件Scaffold,将leading控件, actions 控件和title控件作为AppBar控件的参数 ,这一点贯穿整个框架。
–手势控制
点击Container控件,GestureDetector控件将调用onTap()方法,然后打印信息。GestureDetector支持的手势包括taps, drags和 scales,许多控件,比如 IconButton, RaisedButton和 FloatingActionButton控件被点击后会调用onPressed()方法。
import 'package:flutter/material.dart';
void main(){
runApp(new MaterialApp(title: '手势Demo',home: new MyButton(),));
}
class MyButton extends StatelessWidget{
@override
Widget build(BuildContext context) {
return new GestureDetector(
onTap: (){print('BUtton was tapped');},
child: new Container(//Container:矩形控件,可与BoxDecoration配合来装饰 background, a border, or a shadow,
// 可用margins, padding, and constraints来设置其尺寸。
height: 30.0,
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.symmetric(horizontal: 8.0),
decoration: new BoxDecoration(borderRadius: new BorderRadius.circular(5.0),//背景的圆角
color: Colors.lightGreen[500],),//背景色
child: new Center(child: new Text('Engage'),),//显示 "Engage"
),);}
}
运行结果
–为了响应输入而改变控件
前面我们都是用的无状态的控件,这些无状态的控件从它们的父控件接受参数。为了满足更复杂的场景,APP需要记住一些状态,即Flutter中的StateFullWidgets控件。它知道如何产生用来保持状态的State对象,
import 'package:flutter/material.dart';
void main() {
runApp(new Counter());
}
class Counter extends StatefulWidget{
@override
_CounterState createState() => new _CounterState();
}
class _CounterState extends State<Counter>{
int _counter=0;
void _increment(){
setState((){_counter++;});
}
@override
Widget build(BuildContext context) {
return new Row(children: <Widget>[new FloatingActionButton(onPressed: _increment,
//不使用FloatingActionButton,使用RaisedButton会报错
child: new Text('增加'),),
new Text('Count = $_counter')],);// $_counter表示获取_counter的值
}
}
运行结果
过程中遇到的错误
══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
The following assertion was thrown building MaterialButton(dirty; state:
_MaterialButtonState#767c2()):
No Material widget found.
MaterialButton widgets require a Material widget ancestor.
刚开始使用RaisedButton时报错了,我以为是因为使用了如下的运行方式,以为Counter()不是继承自MD风格的控件
runApp(new MaterialApp(title: ‘Flutter Tutorial’, home: new Counter(), ));
于是我将其修改为
runApp(new Counter());
问题依旧,怎么办,继续排查,值得怀疑的地方是最后面bulid方法里面返回的内容,
return new Row(children: [new RaisedButton(onPressed: _increment,
child: new Text(‘增加’),), new Text(‘Count = $_counter’)],);
不知道是不是这里问题,不管,先试试,返回最简单的 return new Center(child: new Text(‘Hello Flutter!’),运行正常。果然是这里,尝试用new Center替换new Row,FloatingActionButton替换RaisedButton,最终找到问题。
这篇文章主要介绍一些常见控件的用法等基础知识,代码写了注释,都是我个人的理解,可能有些地方表达不准确,理解不够深,这也正是我学习的目的意义。
由于工程大部分地方都相同,只有main.dart文件内容不同,只提供demo2和demo4的源码,也就是MD风格和最后的点击事件。其余的自己复制文章中的代码,然后替换掉main.dart里面的代码即可。
源码下载