codelabs demo功能、官方步骤
1:模拟聊天界面
2:根据学习dart代码是的布局、事件绑定
3:构建组件
4: 简单的动画展示
5:根据ios、或android 显示界面
6:flutter 在android studio中调试
使用 Flutter 构建精美的界面 (flutter-io.cn)
debug其实类似Android 、java
函数上设置断点来练习使用调试程序,然后运行和调试应用。您可以检查堆栈框架以查看您的应用的函数调用历史记录。
demo截屏
flutter的界面布局-使用代码
原生android 默认使用xml方式进行布局
flutter使用代码组件进行布局,类似vue、微信小程序
main.dart -step03 在添加动画前
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
void main() {
runApp(new FriendlychatApp());
}
final ThemeData kIOSTheme = new ThemeData(//采用 iOS 颜色(浅灰色,强调色为橙色)
primarySwatch: Colors.orange,
primaryColor:Colors.grey[100],
primaryColorBrightness: Brightness.light,
);
final ThemeData kDefaultTheme = new ThemeData(//采用 Android 颜色(紫色,强调色为橙色)
primarySwatch: Colors.purple,
accentColor: Colors.orangeAccent[400],
);
class FriendlychatApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: "Friendlychat2",
theme: defaultTargetPlatform == TargetPlatform.iOS //根据iso平台、或android平台,使用不同的主题
? kIOSTheme:kDefaultTheme,
home: new ChatScreen(),
);
}
}
class ChatScreen extends StatefulWidget {
@override
State createState()=>new ChatScreenState();
}
class ChatScreenState extends State with TickerProviderStateMixin{//创建AnimationController对象后,您需要向其传递一个vsync参数。vsync可防止处于屏幕之外的动画消耗不必要的资源。要使用ChatScreenState作为vsync,请在ChatScreenState类定义中添加一个TickerProviderStateMixin mixin。
final List _messages = []; //用于存放消息list,发生消息是_handleSubmitted会将新消息添加进来
final TextEditingController _textController = new TextEditingController();//用它来读取输入字段的内容,并在发送文本消息后清除字段。
bool _isComposing = false; //是否有输入文字,决定是否启用send 按钮
@override
void dispose(){
for (ChatMessage message in _messages){
message.animationController.dispose(); //释放动画资源
super.dispose();
}
}
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("Friendlychat")
) ,
body:new Column(//可以占用多个子微件,包括滚动列表和输入字段的行。
children: [
new Flexible(//消息list的父容器,这将指示框架允许已接收的消息列表进行扩展以填充Column高度
child: new ListView.builder(
padding: new EdgeInsets.all(8.0),
reverse: true,//可使ListView从屏幕底部开始
itemBuilder: (_,int index)=>_messages[index],
itemCount: _messages.length,
)
),
new Divider(height: 1.0,) ,//分割线
new Container(//输入框+发送 Container可作为文本合成器的父微件,其可用于定义背景图片、内边距、外边距和其他常见的布局细节
decoration: new BoxDecoration(
color: Theme.of(context).cardColor
),
child: _buildTextComposer(),
),
],
),
//body: _buildTextComposer(),
);
}
Widget _buildTextComposer(){
return new IconTheme(//应用一个不同的主题背景。 图标的颜色、不透明度和大小
data: new IconThemeData(color: Theme.of(context).accentColor),//data属性指定当前主题背景的ThemeData对象
child: new Container(
margin: const EdgeInsets.symmetric(horizontal: 8.0),
child: new Row( //水平行方向创建子组件 Creates a horizontal array of children.
children: [
new Flexible(
child: new TextField(
controller: _textController, //构造函数提供一个 TextEditingController。此控制器还可用于清除字段或读取字段的值。
onChanged: (String text){
setState(() {
_isComposing = text.length>0;
});
},
onSubmitted: _handleSubmitted,
decoration: new InputDecoration.collapsed(hintText: "send a message"),
),
),
new Container(
margin: new EdgeInsets.symmetric(horizontal:4.0),
child: new IconButton(
icon: new Icon(Icons.send),
onPressed:_isComposing? ()=> _handleSubmitted(_textController.text):null //粗箭头函数声明 => expression 是 { return expression; } 的简写形式。
),
),
],
)
)
);
}
void _handleSubmitted(String value) {
_textController.clear();
setState(() {
_isComposing = false;
});
ChatMessage message = new ChatMessage(
text: value,
animationController:new AnimationController(//实例化一个AnimationController对象用于控制动画
duration: new Duration(milliseconds: 700),
vsync: this
),
);
setState(() { //并让框架了解此部分微件树已发生变化,且需要重新构建界面
_messages.insert(0, message);
});
message.animationController.forward();
}
}
const String _name = "牵手生活";
class ChatMessage extends StatelessWidget{
ChatMessage({required this.text,required this.animationController}); //???为何需要keyword
final String text;
final AnimationController animationController; //存储动画控制器,在 _handleSubmitted()函数初始化 All final variables must be initialized, but 'animationController' isn't. animationController由构造函数传入
@override
Widget build(BuildContext context) {
return new SizeTransition(//CurvedAnimation对象与SizeTransition类结合使用可生成一个缓出动画效果。缓出动画效果可使消息在动画开始时快速滑入,然后慢下来,直至停止
sizeFactor: new CurvedAnimation(
parent: animationController,
curve: Curves.easeOut
),
axisAlignment: 0.0,
child: new Container(
margin: const EdgeInsets.symmetric(vertical: 10.0),
child: new Row(
crossAxisAlignment: CrossAxisAlignment.start, //以确定头像和消息相对于其父微件的位置
children: [
new Container(
margin: const EdgeInsets.only(right: 16.0),
child: new CircleAvatar(child: new Text(_name[0]),), //头像部分:可使用用户的姓名首字母大写作为其标签
),
new Column(
crossAxisAlignment: CrossAxisAlignment.start,//消息,父微件是一个Column微件,其主轴是垂直的,因此CrossAxisAlignment.start将沿水平轴的最左侧位置对齐文本。
children: [
new Text(_name, style: Theme.of(context).textTheme.subtitle2), //主题 .subhead 风格已经没有了
new Container(
margin: const EdgeInsets.only(top:5.0),
child: new Text(text),
),
],
),
],
),
),
);
}
}