// 对齐 child:Text( '很是喜欢前端,而且愿意为此奋斗一辈子。我但愿能够出1000集免费教程。', textAlign:TextAlign.left, ) /** textAlign:TextAlign.left * center: 文本以居中形式对齐,这个也算比较经常使用的了。 * left:左对齐,常用,让文本居左进行对齐,效果和start同样。 * right :右对齐,使用频率也不算高。 * start:以开始位置进行对齐,相似于左对齐。 * end: 觉得本结尾处进行对齐,不经常使用。有点相似右对齐 */
设置最多显示的行数,好比咱们如今只显示1行
child:Text( '很是喜欢前端,而且愿意为此奋斗一辈子。我但愿能够出1000集免费教程。', textAlign:TextAlign.left, maxLines: 1, )
overflow属性是用来设置文本溢出时,如何处理
child:Text( '很是喜欢前端,而且愿意为此奋斗一辈子。我但愿能够出1000集免费教程。', textAlign:TextAlign.left, overflow: clip, ) /* * clip:直接切断,剩下的文字就没有了 * ellipsis:在后边显示省略号,体验性较好 * fade: 溢出的部分会进行一个渐变消失的效果 * * */
style属性较多
child:Text( '很是喜欢前端,而且愿意为此奋斗一辈子。我但愿能够出1000集免费教程。', textAlign:TextAlign.left, overflow:TextOverflow.ellipsis, maxLines: 1, style: TextStyle( fontSize:25.0, color:Color.fromARGB(255, 255, 150, 150), decoration:TextDecoration.underline, decorationStyle:TextDecorationStyle.solid, ), ) /* inherit: true, // 为false的时候不显示 color: Color.fromARGB(255, 150, 150, 150), // 颜色 fontSize :22.0, // 字号 fontWeight: FontWeight.w700, // 字重,加粗也用这个字段 FontWeight.w700 fontStyle: FontStyle.italic , // FontStyle.normal FontStyle.italic斜体 letterSpacing: 10.0, // 字符间距 就是单个字母或者汉字之间的间隔,能够是负数 wordSpacing: 15.0, // 字间距 句字之间的间距 textBaseline: TextBaseline.alphabetic, // 基线,两个值,字面意思是一个用来排字母的,一人用来排表意字的(相似中文) textBaseline: TextBaseline.ideographic height: 1.0, // 当用来Text控件上时,行高(会乘以fontSize,因此不以设置过大) decoration: TextDecoration.overline, // 添加上划线 decoration: TextDecoration.lineThrough, // 添加删除线 decoration: TextDecoration.underline, // 添加下划线 decorationColor, // 划线的颜色 decorationStyle: TextDecorationStyle.dotted, // 这个style可能控制画实线,虚线,两条线,点, 波浪线等 debugLabel, background: //文本背景色 String fontFamily, // 字体 String package, */
Container(容器控件)在Flutter是常用的控件,它就至关于咱们HTML里的<div>标签
padding的属性就是一个内边距
child:Container( child:new Text('Container容器组件', style: TextStyle(fontSize: 40.0) ), alignment: Alignment.topLeft, width:500.0, height:400.0, color: Colors.lightBlue, padding:const EdgeInsets.all(10.0), )
padding:const EdgeInsets.all(10.0),
设置Container的内边距是10,左右上下所有为10
padding:const EdgeInsets.fromLTRB(10.0,30.0,0.0,0.0)
能够知足咱们分别设置上下左右,LTRB分别表明左、上、右、下
child:Container( child:new Text('Hello JSPang', style: TextStyle(fontSize: 40.0) ), alignment: Alignment.topLeft, width:500.0, height:400.0, color: Colors.lightBlue, padding:const EdgeInsets.fromLTRB(10.0,30.0,0.0,0.0), margin: const EdgeInsets.all(10.0), )
decoration是 container 的修饰器,主要的功能是设置背景和边框
好比你须要给背景加入一个渐变,和边框 这时候须要使用BoxDecoration这个类
须要注意的是若是你设置了decoration,就不要再设置color属性了,由于这样会冲突
child:Container( child:new Text('Hello JSPang',style: TextStyle(fontSize: 40.0),), alignment: Alignment.topLeft, width:500.0, height:400.0, padding:const EdgeInsets.fromLTRB(10.0,30.0,0.0,0.0), margin: const EdgeInsets.all(10.0), decoration:new BoxDecoration( gradient:const LinearGradient( colors:[Colors.lightBlue,Colors.greenAccent,Colors.purple] ), border:Border.all(width:2.0,color:Colors.red) ) )
1.Image.asset:加载资源图片,就是加载项目资源目录中的图片,加入图片后会增大打包的包体体积,用的是相对路径。
2.Image.network:网络资源图片,意思就是你须要加入一段http://xxxx.xxx的这样的网络路...。
3.Image.file:加载本地图片,就是加载本地文件中的图片,这个是一个绝对路径,跟包体无关。
4.Image.memory: 加载Uint8List资源图片前端
import 'package:flutter/material.dart'; void main () => runApp(MyApp()); class MyApp extends StatelessWidget{ @override Widget build(BuildContext context ){ return MaterialApp( title:'Text widget', home:Scaffold( body:Center( child:Container( child:new Image.network( 'http://jspang.com/static/myimg/blogtouxiang.jpg', scale:1.0, ), width:300.0, height:200.0, color: Colors.lightBlue, ), ), ), ); } }
fit属性能够控制图片的拉伸和挤压,这些都是根据图片的父级容器来的,咱们先来看看这些属性(建议此部分组好看视频理解)。vue
BoxFit.fill:全图显示,图片会被拉伸,并充满父容器。
BoxFit.contain:全图显示,显示原比例,可能会有空隙。
BoxFit.cover:显示可能拉伸,可能裁切,充满(图片要充满整个容器,还不变形)。
BoxFit.fitWidth:宽度充满(横向充满),显示可能拉伸,可能裁切。
BoxFit.fitHeight :高度充满(竖向充满),显示可能拉伸,可能裁切。
BoxFit.scaleDown:效果和contain差很少,可是此属性不容许显示超过源图片大小,可小不可大node
child:Container( child:new Image.network( 'http://img.nodebook.top/nodebooklogo.jpg', scale:1.0, fit: BoxFit.fill ), width:300.0, height:200.0, color: Colors.lightBlue, )
child:new Image.network( 'http://jspang.com/static/myimg/blogtouxiang.jpg', color: Colors.greenAccent, colorBlendMode: BlendMode.darken, )
color:是要混合的颜色,若是你只设置color是没有意义的
colorBlendMode:是混合模式,至关于咱们如何混合。
ImageRepeat.repeat : 横向和纵向都进行重复,直到铺满整个画布。web
ImageRepeat.repeatX: 横向重复,纵向不重复。typescript
ImageRepeat.repeatY:纵向重复,横向不重复数组
child:new Image.network( 'http://jspang.com/static/myimg/blogtouxiang.jpg', repeat: ImageRepeat.repeat, ),
import 'package:flutter/material.dart'; void main () => runApp(MyApp()); class MyApp extends StatelessWidget{ @override Widget build(BuildContext context){ return MaterialApp( title:'JSPang Flutter Demo', home:Scaffold( appBar:new AppBar( title:new Text('ListView Widget') ), body: new ListView( children:<Widget>[ new ListTile( leading:new Icon(Icons.access_time), title:new Text('access_time') ), new ListTile( leading:new Icon(Icons.account_balance), title:new Text('account_balance') ), ] ) ), ); } }
body: new ListView( children:<Widget>[ new ListTile( leading:new Icon(Icons.access_time), title:new Text('access_time') ), new ListTile( leading:new Icon(Icons.account_balance), title:new Text('account_balance') ), ] ), ---
body: new ListView( children:<Widget>[ new Image.network( 'http://jspang.com/static/upload/20181111/G-wj-ZQuocWlYOHM6MT2Hbh5.jpg' ), new Image.network( 'http://jspang.com/static/upload/20181109/1bHNoNGpZjyriCNcvqdKo3s6.jpg' ), new Image.network( 'http://jspang.com/static/myimg/typescript_banner.jpg' ), new Image.network( 'http://jspang.com/static/myimg/smile-vue.jpg' ) ] ),
其实仍是使用咱们的ListView组件,只是在ListView组件里加一个ScrollDirection属性。
import 'package:flutter/material.dart'; void main () => runApp(MyApp()); class MyApp extends StatelessWidget{ @override Widget build(BuildContext context ){ return MaterialApp( title:'Text widget', home:Scaffold( body:Center( child:Container( height:200.0, child:new ListView( scrollDirection: Axis.horizontal, children: <Widget>[ new Container( width:180.0, color: Colors.lightBlue, ), new Container( width:180.0, color: Colors.amber, ), new Container( width:180.0, color: Colors.deepOrange, ),new Container( width:180.0, color: Colors.deepPurpleAccent, ), ], ) ), ), ), ); } }
ListView组件的scrollDirection属性只有两个值,一个是横向滚动,一个是纵向滚动。默认的就是垂直滚动,因此若是是垂直滚动,咱们通常都不进行设置。网络
Axis.horizontal:横向滚动或者叫水平方向滚动。app
import 'package:flutter/material.dart'; void main () => runApp(MyApp()); class MyApp extends StatelessWidget{ @override Widget build(BuildContext context ){ return MaterialApp( title:'ListView widget', home:Scaffold( body:Center( child:Container( height:200.0, child:MyList() // => 组件化 ), ), ), ); } } // MyList class MyList extends StatelessWidget{ @override Widget build(BuildContext context){ return ListView( scrollDirection: Axis.horizontal, children: <Widget>[ new Container( width:180.0, color: Colors.lightBlue, ), new Container( width:180.0, color: Colors.amber, ), new Container( width:180.0, color: Colors.deepOrange, ),new Container( width:180.0, color: Colors.deepPurpleAccent, ), ], ); } }
List类型的使用
List是Dart的集合类型之一,其实你能够把它简单理解为数组(反正我是这么认为的) , 它的声明有几种方式:less
var myList = List(): 非固定长度的声明。
var myList = List(2): 固定长度的声明。
var myList= List<String>():固定类型的声明方式。
var myList = [1,2,3]: 对List直接赋值。jsp
void main () => runApp(MyApp( items: new List<String>.generate(1000, (i)=> "Item $i") ));
generate方法传递两个参数,第一个参数是生成的个数,第二个是方法
import 'package:flutter/material.dart'; void main () => runApp(MyApp( items: new List<String>.generate(1000, (i)=> "Item $i") )); class MyApp extends StatelessWidget{ final List<String> items; MyApp({Key key, @required this.items}):super(key:key); @override Widget build(BuildContext context ){ return MaterialApp( title:'ListView widget', home:Scaffold( body:new ListView.builder( itemCount:items.length, itemBuilder:(context,index){ return new ListTile( title:new Text('${items[index]}'), ); } ) ), ); } }
import 'package:flutter/material.dart'; void main () => runApp(MyApp()); class MyApp extends StatelessWidget{ @override Widget build(BuildContext context ){ return MaterialApp( title:'ListView widget', home:Scaffold( body:GridView.count( padding:const EdgeInsets.all(20.0), crossAxisSpacing: 10.0, crossAxisCount: 3, children: <Widget>[ const Text('I am Jspang'), const Text('I love Web'), const Text('jspang.com'), const Text('我喜欢玩游戏'), const Text('我喜欢看书'), const Text('我喜欢吃火锅') ], ) ), ); } }
padding:表示内边距,这个小伙伴们应该很熟悉。
crossAxisSpacing:网格间的空当,至关于每一个网格之间的间距。
import 'package:flutter/material.dart'; void main () => runApp(MyApp()); class MyApp extends StatelessWidget{ @override Widget build(BuildContext context ){ return MaterialApp( title:'ListView widget', home:Scaffold( body:GridView( gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 3, mainAxisSpacing: 2.0, crossAxisSpacing: 2.0, childAspectRatio: 0.7 ), children: <Widget>[ new Image.network('http://img5.mtime.cn/mt/2018/10/22/104316.77318635_180X260X4.jpg',fit: BoxFit.cover), new Image.network('http://img5.mtime.cn/mt/2018/10/10/112514.30587089_180X260X4.jpg',fit: BoxFit.cover), new Image.network('http://img5.mtime.cn/mt/2018/11/13/093605.61422332_180X260X4.jpg',fit: BoxFit.cover), new Image.network('http://img5.mtime.cn/mt/2018/11/07/092515.55805319_180X260X4.jpg',fit: BoxFit.cover), new Image.network('http://img5.mtime.cn/mt/2018/11/21/090246.16772408_135X190X4.jpg',fit: BoxFit.cover), new Image.network('http://img5.mtime.cn/mt/2018/11/17/162028.94879602_135X190X4.jpg',fit: BoxFit.cover), new Image.network('http://img5.mtime.cn/mt/2018/11/19/165350.52237320_135X190X4.jpg',fit: BoxFit.cover), new Image.network('http://img5.mtime.cn/mt/2018/11/16/115256.24365160_180X260X4.jpg',fit: BoxFit.cover), new Image.network('http://img5.mtime.cn/mt/2018/11/20/141608.71613590_135X190X4.jpg',fit: BoxFit.cover), ], ) ), ); } }
childAspectRatio:宽高比,这个值的意思是宽是高的多少倍,若是宽是高的2倍,那咱们就写2.0,若是高是宽的2倍,咱们就写0.5
Flutter中的row控件就是水平控件,它可让Row里边的子元素进行水平排列
Row控件能够分为灵活排列和非灵活排列两种
从字面上就能够理解到,不灵活就是根据Row子元素的大小,进行布局。若是子元素不足,它会留有空隙,若是子元素超出,它会警告。
import 'package:flutter/material.dart'; void main () => runApp(MyApp()); class MyApp extends StatelessWidget{ @override Widget build(BuildContext context ){ return MaterialApp( title:'ListView widget', home:Scaffold( appBar:new AppBar( title:new Text('水平方向布局'), ), body:new Row( children: <Widget>[ new RaisedButton( onPressed: (){ }, color:Colors.redAccent, child:new Text('红色按钮') ), new RaisedButton( onPressed: (){ }, color:Colors.orangeAccent, child: new Text('黄色按钮'), ), new RaisedButton( onPressed: (){ }, color:Colors.pinkAccent, child:new Text('粉色按钮') ) ], ) ), ); } }
这时候你会发现的页面已经有了三个按钮,但这三个按钮并无充满一行,而是出现了空隙。这就是不灵活横向排列形成的。它根据子元素的大小来进行排列。若是咱们想实现充满一行的效果,就要使用灵活水平布局了
在按钮的外边加入Expanded就能够了
import 'package:flutter/material.dart'; void main () => runApp(MyApp()); class MyApp extends StatelessWidget{ @override Widget build(BuildContext context ){ return MaterialApp( title:'ListView widget', home:Scaffold( appBar:new AppBar( title:new Text('水平方向布局'), ), body:new Row( children: <Widget>[ Expanded(child:new RaisedButton( onPressed: (){ }, color:Colors.redAccent, child:new Text('红色按钮') )), Expanded(child:new RaisedButton( onPressed: (){ }, color:Colors.orangeAccent, child: new Text('黄色按钮'), ) ), Expanded(child:new RaisedButton( onPressed: (){ }, color:Colors.pinkAccent, child:new Text('粉色按钮') ) ) ], ) ), ); } }
中间的按钮大,而两边的按钮保持真实大小
import 'package:flutter/material.dart'; void main () => runApp(MyApp()); class MyApp extends StatelessWidget{ @override Widget build(BuildContext context ){ return MaterialApp( title:'ListView widget', home:Scaffold( appBar:new AppBar( title:new Text('水平方向布局'), ), body:new Row( children: <Widget>[ new RaisedButton( onPressed: (){ }, color:Colors.redAccent, child:new Text('红色按钮') ), Expanded(child:new RaisedButton( onPressed: (){ }, color:Colors.orangeAccent, child: new Text('黄色按钮'), ) ), new RaisedButton( onPressed: (){ }, color:Colors.pinkAccent, child:new Text('粉色按钮') ) ], ) ), ); } }
import 'package:flutter/material.dart'; void main () => runApp(MyApp()); class MyApp extends StatelessWidget{ @override Widget build(BuildContext context ){ return MaterialApp( title:'ListView widget', home:Scaffold( appBar:new AppBar( title:new Text('垂直方向布局'), ), body:Column( children: <Widget>[ Text('I am JSPang'), Text('my website is jspang.com'), Text('I love coding') ], crossAxisAlignment: CrossAxisAlignment.start ) ), ); } }
CrossAxisAlignment.star:居左对齐。
CrossAxisAlignment.end:居右对齐。
mainAxisAlignment 主轴的对齐方式
main轴:若是你用column组件,那垂直就是主轴,若是你用Row组件,那水平就是主轴。
cross轴:cross轴咱们称为幅轴,是和主轴垂直的方向。好比Row组件,那垂直就是幅轴,Column组件的幅轴就是水平方向的
mainAxisAlignment: MainAxisAlignment.center
让文字相对于水平方向居中,咱们如何处理?其实只要加入Center组件就能够轻松解决
import 'package:flutter/material.dart'; void main () => runApp(MyApp()); class MyApp extends StatelessWidget{ @override Widget build(BuildContext context ){ return MaterialApp( title:'ListView widget', home:Scaffold( appBar:new AppBar( title:new Text('垂直方向布局'), ), body:Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Center(child:Text('I am JSPang')), Center(child:Text('my website is jspang.com')), Center(child:Text('I love coding')) ], ) ), ); } }
在学习水平布局的时候咱们对Expanded有了深入的理解,它就是灵活布局。好比咱们想让中间区域变大,而头部区域和底部根据文字所占空间进行显示
body:Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Center(child:Text('I am JSPang')), Expanded(child:Center(child:Text('my website is jspang.com'))), Center(child:Text('I love coding')) ], )
alignment属性是控制层叠的位置的,建议在两个内容进行层叠时使用。它有两个值X轴距离和Y轴距离,值是从0到1的,都是从上层容器的左上角开始算起的
CircleAvatar这个常常用来做头像的,组件里边有个radius的值能够设置图片的弧度
new CircleAvatar( backgroundImage: new NetworkImage('http://jspang.com/static//myimg/blogtouxiang.jpg'), radius: 100.0, )
import 'package:flutter/material.dart'; void main () => runApp(MyApp()); class MyApp extends StatelessWidget{ @override Widget build(BuildContext context ){ var stack = new Stack( alignment: const FractionalOffset(0, 0.1), children: <Widget>[ new CircleAvatar( backgroundImage: new NetworkImage('http://jspang.com/static//myimg/blogtouxiang.jpg'), radius: 100.0, ), new Container( decoration: new BoxDecoration( color: Colors.lightBlue, ), padding: EdgeInsets.all(5.0), child: new Text('JSPang 技术胖'), ) ], ); return MaterialApp( title:'ListView widget', home:Scaffold( appBar:new AppBar( title:new Text('垂直方向布局'), ), body:Center(child:stack), ), ); } }
若是是超过两个组件的层叠该如何进行定位那?这就是咱们加今天要学的主角Positioned组件了。这个组件也叫作层叠定位组件
Positioned组件的属性
bottom: 距离层叠组件下边的距离
left:距离层叠组件左边的距离
top:距离层叠组件上边的距离
right:距离层叠组件右边的距离
width: 层叠定位组件的宽度
height: 层叠定位组件的高度
import 'package:flutter/material.dart'; void main () => runApp(MyApp()); class MyApp extends StatelessWidget{ @override Widget build(BuildContext context ){ var stack = new Stack( children: <Widget>[ new CircleAvatar( backgroundImage: new NetworkImage('http://jspang.com/static//myimg/blogtouxiang.jpg'), radius: 100.0, ), new Positioned( top:10.0, left:10.0, child: new Text('JSPang.com'), ), new Positioned( bottom:10.0, right:10.0, child: new Text('技术胖'), ) ], ); return MaterialApp( title:'ListView widget', home:Scaffold( appBar:new AppBar( title:new Text('层叠布局'), ), body:Center(child:stack), ), ); } }
Flutter还有一种比较比较酷炫的布局方式:卡片式布局。这种布局相似ViewList,可是列表会以物理卡片的形态进行展现
import 'package:flutter/material.dart'; void main () => runApp(MyApp()); class MyApp extends StatelessWidget{ @override Widget build(BuildContext context ){ var card = new Card( child: Column( children: <Widget>[ ListTile( title:new Text('吉林省吉林市昌邑区',style: TextStyle(fontWeight: FontWeight.w500),), subtitle: new Text('技术胖:1513938888'), leading: new Icon(Icons.account_box,color: Colors.lightBlue,), ), new Divider(), ListTile( title:new Text('北京市海淀区中国科技大学',style: TextStyle(fontWeight: FontWeight.w500),), subtitle: new Text('胜宏宇:1513938888'), leading: new Icon(Icons.account_box,color: Colors.lightBlue,), ), new Divider(), ListTile( title:new Text('河南省濮阳市百姓办公楼',style: TextStyle(fontWeight: FontWeight.w500),), subtitle: new Text('JSPang:1513938888'), leading: new Icon(Icons.account_box,color: Colors.lightBlue,), ), new Divider(), ], ), ); return MaterialApp( title:'ListView widget', home:Scaffold( appBar:new AppBar( title:new Text('卡片布局'), ), body:Center(child:card), ), ); } }
它有两个最基本的属性:
child:能够放入容器,图标,文字。让你构建多彩的按钮。 onPressed:点击事件的相应,通常会调用Navigator组件
咱们在做页面导航时,大量的使用了RaisedButton组件,这个组件的使用在实际工做中用的也比较多
1.Navigator.push:是跳转到下一个页面,它要接受两个参数一个是上下文context,另外一个是要跳转
2.Navigator.pop:是返回到上一个页面,使用时传递一个context(上下文)参数,使用时要注意的是,你必须是有上级页面的,也就是说上级页面使用了Navigator.push。
import 'package:flutter/material.dart'; void main(){ runApp(MaterialApp( title:'导航演示1', home:new MyApp() )); } class MyApp extends StatelessWidget{ @override Widget build(BuildContext context){ return new Scaffold( appBar: AppBar(title:Text('导航页面')), body:Center( child:RaisedButton( child:Text('查看商品详情页面'), onPressed: (){ Navigator.push(context,new MaterialPageRoute( builder:(context) =>new SecondScreen()) ); }, ) ) ); } } class SecondScreen extends StatelessWidget{ @override Widget build(BuildContext context){ return Scaffold( appBar:AppBar(title:Text('技术胖商品详情页')), body:Center( child:RaisedButton( child:Text('返回'), onPressed: (){ Navigator.pop(context); }, )) ); } }
# Center组件
import 'package:flutter/material.dart';
void main(){
runApp(new Center( //Center组件 child: Text( "文本内容", textDirection: TextDirection.ltr ) ))
}
# 自定义组件
StatelessWidget //无状态组件
StatefulWidget //有状态组件
class MyApp extends StatelessWidget{
@override Widget build(BuildContext context) { return Center( //Center组件 child: Text( "文本内容", textDirection: TextDirection.ltr, style: TextStyle( fontSize: 40.0, color: Color.fromRGBO(255,0,0,0.5) ) ) ) }
}
# MaterialApp 和 Scaffold > MaterialApp是一个方便的Widget,它封装了应用程序实现 Material Desigin 所须要的一些Widget 通常做为顶层Widget组件 ### 经常使用属性 home(主页) title(标题) color(颜色) theme(主题) routes(路由) ### Scaffold组件 > Scaffold 是 Material Desigin 布局结构的基本实现 ### Scaffold组件属性 appBar 显示在界面顶部的一个 appBar body 当前界面所显示的主要 内饰 Widget drawer 抽屉菜单控件
import 'package:flutter/material.dart';
void main(){
runApp(MaterialApp(
title:'导航演示1', home:new MyApp(), theme:ThemeData( primarySwatch: Colors.yellow )
));
}
class MyApp extends StatelessWidget{
@override
Widget build(BuildContext context){
return new Scaffold( appBar: AppBar(title:Text('导航页面')), body:Center( child:RaisedButton( child:Text('查看商品详情页面'), onPressed: (){ Navigator.push(context,new MaterialPageRoute( builder:(context) =>new SecondScreen()) ); }, ) ) );
}
}
class SecondScreen extends StatelessWidget{
@override
Widget build(BuildContext context){
return Scaffold( appBar:AppBar(title:Text('技术胖商品详情页')), body:Center( child:RaisedButton( child:Text('返回'), onPressed: (){ Navigator.pop(context); }, )) );
}}