注意 国内访问flutter可能会受限制,可下载国内镜像
PUB_HOSTED_URL https://pub.flutter-io.cn
FLUTTER_STORAGE_BASE_URLhttps://storage.flutter-io.cn
安装
1、电脑配置JDK(下载jdk,配置jdk )
2、下载安装Android studio
3、下载配置flutter sdk(flutter -v检验是否配置成功)
4、配置flutter国内镜像
5、输入flutter doctor 命令检测环境是否配置成功
(如果出现“!",命令行输入 flutter doctor --android-licenses)
6、Android studio 安装flutter 插件(config->Plugins->flutter)
7、创建项目(第一次创建时间非常长,可能有十几分钟)
报错(下载失败)——点击File->Sync Project With Gradle Files 重新下载Gradle。
准备Android 手机 ;手机、电脑开启调试模式;数据线吧手机电脑相连;手机对应的sdk版本必须安装()
虚拟机调试(模拟器和自带,自带的模拟器较慢安装较麻烦,推荐第三方模拟器)
1、安装flutter插件、flutter widget snippets插件
2、vscode连不上模拟器的解决方案 :
cd到模拟器D:xxxxx\bin目录下 运行 nox_adb.exe connect 127.0.01:62001
3、运行flutter项目;r键:点击后热加载,也算是重新加载
p键:显示网格,可以较好的掌握布局情况,
o键:切换Android 和ios的预览模式
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-D5q8zPH0-1640866944947)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20211016195511058.png)]
build运行项目生成的编译目录,libflutter相关代码,自己放置资源(自己编写的代码),pubspec.yaml项目配置文件(配置项目名称,项目依赖等,一般存放第三方库的依赖)
每个flutter项目里面的lib目录里面都有一个main.dart,这个文件就是flutter的入口文件。
main方法是dart的入口方法,runApp方法 是flutter提供的入口方法,可以调用flutter提供的组件,myApp是自定义的一个组件,flutter所有的组件都是类。
void main() {
runApp(new Center(//实例化时new可以省略
child: new Text(
'你好Fluter',
textDirection: TextDirection.ltr,
)));
}
实现一些简单的输出
自定义组件(flutter自定义组件就是一个类,这个类需要继承StaelessWidget/StateWidget 抽象类)
StatelessWidget是无状态组件,状态不可变的widget
StatefulWidget是有状态组件,持有的状态可能在widget生命周期改变
//自定义组件
import 'package:flutter/material.dart';
void main() {
runApp(Myapp());
}
//自定义组件
class Myapp extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return Center(
//实例化时new可以省略
child: Text(
'你好Fluter 我是小栗子',
textDirection: TextDirection.ltr,
));
}
}
MaterialApp封装了应用程序实现Material Design 所需要的一些Widget,一般作为顶层widget使用,常用的属性:home(主页)title(标题)color(颜色) theme(主题) routes(路由)
Scaffold的几个属性:
appBar-显示在界面顶部的一个AppBar
body-当前页面所显示的主要内容Widget
drawer-抽屉菜单控制
import 'package:flutter/material.dart';
void main() {
runApp(Myapp());
}
//自定义组件
class Myapp extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Flutter'),
),
body: HomeContent(),
),
theme: ThemeData(primaryColor: Colors.pink),
);
}
}
class HomeContent extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return Center(
//实例化时new可以省略
child: Text(
'你好Fluter 我是小栗子',
textDirection: TextDirection.ltr,
style: TextStyle(
fontSize: 40.0, //和数字有关的都是double类型的。
color: Colors.pink, //或者 color:Colors.fromRGBO(224,233,214,0.5)
),
));
}
}
示例
Container容器组件,相当于view,div,可以设置颜色
import 'package:flutter/material.dart';
void main() {
runApp(Myapp());
}
//自定义组件
class Myapp extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Flutter'),
),
body: HomeContent(),
),
theme: ThemeData(primaryColor: Colors.purple.shade100));
}
}
class HomeContent extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return Center(
//实例化时new可以省略
child: Container(
//child子元素
child: Text(
'小栗子',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 18.0,
fontStyle: FontStyle.italic,
decoration: TextDecoration.lineThrough,
letterSpacing: 4.0, //字间距
), //设置字体属性
overflow: TextOverflow.ellipsis, //超出行的部分省略
maxLines: 1,
textScaleFactor: 2, //字体放大两倍
),
height: 300.0,
width: 300.0,
decoration: BoxDecoration(
//背景颜色
color: Colors.pink.shade50,
border: Border.all(
color: Colors.pink.shade100,
width: 2.0, //线的宽度
),
borderRadius: BorderRadius.all(
Radius.circular(15.0),
),
),
// padding: EdgeInsets.all(50), //四个边距一样
//padding: EdgeInsets.fromLTRB(10, 20, 30, 30)),
//transform: Matrix4.translationValues(1, 0, 0),
alignment: Alignment.bottomLeft, //改变元素的位置
) //元素倾斜旋转
);
}
}
image组件有很多构造函数,
Image.asset ,本地图片
Image.network 远程图片
class HomeContent extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return Center(
child: Container(
child: Image.network(
"",
alignment: Alignment.bottomLeft,
// fit: BoxFit.cover, //fit属性控制图片的拉伸和挤压
repeat: ImageRepeat.repeatX, //图片的平铺
),
width: 200,
height: 200,
decoration: BoxDecoration(color: Colors.yellow),
));
}
}
flutter实现圆角和圆形图片
用Container实现:
class HomeContent extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return Center(
child: Container(
width: 200,
height: 200,
decoration: BoxDecoration(
color: Colors.yellow,
// borderRadius: BorderRadius.all(
// Radius.circular(100),
// )
borderRadius: BorderRadius.circular(100),
image:DecorationImage(
image: NetworkImage(""),
fit: BoxFit.cover
)),
));
}
}
用ClipOval组件实现
class HomeContent extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return Center(
child: ClipOval(
child: Image.network("", height: 100, width: 100, fit: BoxFit.cover),
),
);
}
}
在根目录新建文件夹(images)-》新建文件夹(2.0x,3.0x)->打开pubspec.yaml声明以下添加的图片文件,配置对
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Jk1SFcvE-1640866944952)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20211017114049919.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V4oB5hfl-1640866944955)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20211017114308757.png)]
在代码中使用
class HomeContent extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return Center(child: Container(child: Image.asset("images/2.0x/2.jpg")));
}
}
列表参数:scrollDirection leix:Axis 说明:Axis.horizontal水平列表
padding ,resolve.children(列表元素)
ListView一般配合ListTilte使用,可以加图片和图标,形成图文列表
垂直列表
class HomeContent extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return ListView(
padding: EdgeInsets.all(10),
children: [
//返回Widget的数组
ListTile(
leading: Icon(
Icons.settings,
color: Colors.pink,
size: 30,
), //前面加图标
title: Text('hhhhh五哈'),
subtitle: Text('hhhhhhhhgffnfn hjyygfhhhhhhhhh'), //二级标题
trailing: Icon(Icons.ac_unit_rounded), //后面加图标
),
ListTile(
leading: Icon(
Icons.home,
color: Colors.pink,
), //加图标
title: Text('hhhhh五哈'),
subtitle: Text('hhhhhhhhgffnfn hjyygfhhhhhhhhh'), //二级标题
),
ListTile(
leading: Image.network(
"https://img.ivsky.com/img/tupian/t/201910/05/daoying.jpg",
height: 40,
width: 40,
), //加图片
title: Text('hhhhh五哈'),
subtitle: Text('hhhhhhhhgffnfn hjyygfhhhhhhhhh'), //二级标题
),
],
);
}
}
class HomeContent extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return ListView(
padding: EdgeInsets.all(10),
children: [
Image.network(
"https://img.ivsky.com/img/tupian/t/201910/05/daoying.jpg"),
Container(
child: Text('我是一个标题',
textAlign: TextAlign.center, style: TextStyle(fontSize: 20)),
height: 20,
),
Image.network(
"https://img.ivsky.com/img/tupian/t/201910/05/daoying.jpg"),
Image.network(
"https://img.ivsky.com/img/tupian/t/201910/05/daoying.jpg"),
Image.network(
"https://img.ivsky.com/img/tupian/t/201910/05/daoying.jpg"),
],
);
}
}
水平列表
class HomeContent extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return Container(
height: 180,
child: ListView(
scrollDirection: Axis.horizontal,
children: [
Container(
width: 180,
height: 180,
color: Colors.pink.shade50,
),
Container(
width: 180,
height: 180,
child: ListView(
children: [
Image.network(
"https://img.ivsky.com/img/tupian/t/201910/05/daoying.jpg"),
Text('图片'),
],
),
color: Colors.pink.shade100,
),
Container(
width: 180,
height: 180,
color: Colors.pink.shade400,
),
Container(
width: 180,
height: 180,
color: Colors.pink.shade200,
)
],
));
}
}
动态列表(循环)
class HomeContent extends StatelessWidget {
//自定义方法
List _getData() {
List list = [];
for (var i = 0; i < 10; i++) {
list.add(ListTile(
title: Text("$i个糖炒栗子"),
));
}
return list;
// return [
// ListTile(title: Text('我是一个列表')),
// ListTile(title: Text('我是一个列表')),
// ListTile(title: Text('我是一个列表')),
// ListTile(title: Text('我是一个列表')),
// ];
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return ListView(
children: this._getData(),
);
}
}
用list view.builder实现循环遍历
class HomeContent extends StatelessWidget {
List list = [];
HomeContent() {
for (var i = 0; i < 10; i++) {
this.list.add(ListTile(
title: Text("$i个糖炒栗子"),
));
}
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return ListView.builder(
itemCount: this.list.length, //长度
itemBuilder: (context, index) {
return this.list[index];
},
);
}
}
1.GridView.count实现网格布局
class HomeContent extends StatelessWidget {
List _getData() {
List list = [];
for (var i = 0; i < 20; i++) {
list.add(Container(
alignment: Alignment.center,
color: Colors.pink.shade50,
child: Text(
'xiaozili',
style: TextStyle(color: Colors.white, fontSize: 20),
),
));
}
return list;
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return GridView.count(//实现网格布局
crossAxisSpacing: 20.0, //水平之间的距离
mainAxisSpacing: 20.0, //垂直之间的距离
crossAxisCount: 3,
childAspectRatio: 0.7, //宽度和高度的比例
children: this._getData(),
padding: EdgeInsets.all(10),
//[
// Text('eeeee'),
// Text('eeeee'),
// Text('eeeee'),
// Text('eeeee'),
// Text('eeeee'),
// Text('eeeee'),
// ],
);
}
}
GridView.builder实现网格布局跟ListView.builder类似,配置间距参数,需要gridDelegate: SliverGridDelegateWithFixedCrossAxisCount()
padding组件:很多widget组件没有padding属性,可以使用padding组件来处理
水平布局组件Row:
return Row(
mainAxisAlignment: MainAxisAlignment.center, //主轴
crossAxisAlignment: CrossAxisAlignment.end, //次轴
children: [
IconCotainer(
Icons.search,
size: 40,
color: Colors.red,
),
IconCotainer(
Icons.home,
size: 40,
color: Colors.black,
),
IconCotainer(
Icons.settings,
size: 40,
color: Colors.pink,
)
],
);
垂直布局组件:Column
Expanded可以在Row和Column布局中使用
class HomeContent extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(flex: 1, child: Text('xxx')),
Expanded(flex: 2, child: Text('xxx')),
Expanded(flex: 1, child: Text('xxx')),
],
);
}
}
Stack组件属性:alignment children
class HomeContent extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: Stack(
//元素堆积重叠
alignment: Alignment.center, //让里面所有的元素居中
children: [
Container(
height: 400,
width: 300,
color: Colors.red,
),
Text('hello'),
],
),
);
}
}
class HomeContent extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: Stack(
//元素堆积重叠
alignment: Alignment(-1, 0), //调整元素在容器的任意位置
children: [
Container(
height: 400,
width: 300,
color: Colors.red,
),
Text('hello'),
],
),
);
}
}
Stack结合Align使用:
positioned:top ,right等
AspectRatio是调整子元素child的宽高比
Card卡片组件块,内容可由大多数类型的Widget构成,Card具有圆角和阴影。
class HomeContent extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
height: 200,
child: ListView(
children: [
Card(
margin: EdgeInsets.all(10),
child: Column(
children: [
ListTile(
title: Text(
'张三',
style: TextStyle(fontSize: 23),
),
subtitle: Text('高级工程师'),
),
ListTile(
title: Text(
"1234567890",
),
),
ListTile(
title: Text(
"xxxxxx",
),
),
],
),
)
],
));
}
}
ClipOver,
CircleAvatar专门处理头像的,
可以实现流布局,单行的wrap和row表现一致,wrap多行时,maxAxis上空间不足时,则向crossAxis上去扩展显示。
statefulwidget是状态组件,持有的状态可能在widget生命周期改变,想改变页面数据可能会用到statefulwidget
实现点击按钮,文本文字变化
import 'package:flutter/material.dart';
void main() {
runApp(Myapp());
}
class Myapp extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('小栗子'),
),
body: HomePage(),
));
}
}
//自定义有状态组件
class HomePage extends StatefulWidget {
HomePage({Key? key}) : super(key: key);
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State {
int countnum = 0;
@override
Widget build(BuildContext context) {
return Container(
child: Column(
children: [
SizedBox(height: 100),
Chip(label: Text("${this.countnum}")),
SizedBox(height: 10),
ElevatedButton(
child: Text('按钮'),
onPressed: () {
setState(() {
//只有有状态组件才有
this.countnum++;
});
},
)
],
),
);
}
}
BottomNavigationBar组件 是底部导航条,可以让我们定义底部Tab切换,bottomNavigationBar是SCaffold组件的参数。
属性:items 底部导航栏按钮集合类型为List
iconSize:icon
currentIndex:默认选中第几个,
onTap:选中变化回调函数,触发的方法
fixedColor:选中的颜色
type BottomNavigationBarType.fixed//底部可以有多个按钮
导航条,页面切换
import 'package:flutter/material.dart';
import 'tabs/home.dart';
import 'tabs/home2.dart';
//自定义有状态组件
class Tabs extends StatefulWidget {
Tabs({Key? key}) : super(key: key);
@override
_TabsState createState() => _TabsState();
}
class _TabsState extends State {
List _pageList = [
HomePage(),
Home2Page(),
];
int _curentindex = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('小栗子'),
),
body: Text(this._pageList[this._curentindex]),
bottomNavigationBar: BottomNavigationBar(
currentIndex: this._curentindex,
onTap: (int index) {
//底部菜单点击出发的方法
setState(() {
this._curentindex = index; //实现点击选中的功能
});
},
items: [
BottomNavigationBarItem(
icon: Image.network(""),
label: "首页",
),
BottomNavigationBarItem(
icon: Image.network(""),
label: "优惠券",
),
BottomNavigationBarItem(
icon: Image.network(""),
label: "用户管理",
),
BottomNavigationBarItem(
icon: Image.network(""),
label: "我的",
),
],
),
);
}
}
路由就是页面跳转,在Flutter中通过Navigator组件管理路由导航,提供了管理堆栈的方法,
Navigator.push和Navigator.pop
flutter有两种配置路由跳转的方式1.基本路由 2命名路由
首页跳转到搜索页面
1.需要在首页HomePage中引入SearchPage.dart,2.使用Navigator.pop方法
Navigator.of(context)//路由跳转
.push(MaterialPageRoute(builder: (context) => searchPage()));
2.floatingActionButton:浮动按钮
在MaterialApp配置路由,直接通过navigator跳转
普通路由跳转到根目录:pushAndRemoveUntil()
debugShowCheckedModeBanner:false; //去掉debug图标 在main.dart里面
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
void main(){
runApp(MyApp());
// runApp(new Center(//实例化组件
// child:new Text(//再dart里面,实例化类时new可以省略。
// '你好Flutter',
// textDirection: TextDirection.ltr,
// )
// ));
}
//自定义组件
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return HomeContent();
// return MaterialApp(
// home:Scaffold(
// appBar: AppBar(
// title: Text('flutter demo'),
// ),
// body: HomeContent(),
// )
// );
}
}
class HomeContent extends StatelessWidget{
@override
Widget build(BuildContext context) {
// TODO: implement build
return Center(//实例化组件
child:new Text(//再dart里面,实例化类时new可以省略。
'你好Flutter11',
style: TextStyle(
fontSize: 40.0,
color:Colors.yellow
),
textDirection: TextDirection.ltr,
)
);
}
}
// Copyright 2018 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:math';
import 'package:english_words/english_words.dart';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
//final wordPair=WordPair.random();
return MaterialApp(
title: 'Startup Name Generator',
theme:new ThemeData(
primaryColor: Colors.pink.shade200,
),
home: RandomWords(),
// appBar: AppBar(
// title: const Text('Welcome to Flutter'),
// ),
// // body: const Center(
// // child: Text('Hello World'),
// body:Center(
// //child:Text(wordPair.asPascalCase),
// child: RandomWords(),
// ),
);
}
}
class RandomWords extends StatefulWidget {
// const RandomWords({Key? key}) : super(key: key);
@override
_RandomWordsState createState() => _RandomWordsState();
}
class _RandomWordsState extends State {
final List _suggestions=[];
final Set _saved=new Set();//存储用户喜欢的单词对
//final _suggestions=[];//保存建议的单词对
final TextStyle _biggerFont=const TextStyle(fontSize:18.0);//增大字体大小
// ignore: non_constant_identifier_names
Widget_buildSuggestions(){
return ListView.builder(
padding: const EdgeInsets.all(16.0),
itemBuilder:(context,i){
if(i.isOdd) return const Divider();
final index=i~/2;
if(index>=_suggestions.length){
_suggestions.addAll(generateWordPairs().take(10));
}
return _buildRow(_suggestions[index]);
});
}
// ignore: camel_case_types
Widget _buildRow (WordPair pair){
final bool alreadySaved=_saved.contains(pair);//确保单词还没有被加入收藏夹
return ListTile(
title: Text(
pair.asPascalCase,
style: _biggerFont,
),
trailing: new Icon(
alreadySaved?Icons.favorite:Icons.favorite_border,
color: alreadySaved?Colors.red:null,
),
onTap: (){
setState(() {
if(alreadySaved){
_saved.remove(pair);
}else{
_saved.add(pair);
}
});
},
);
}
@override
Widget build(BuildContext context) {
// final wordPair=WordPair.random();
// return Text(wordPair.asPascalCase);
return Scaffold(
appBar: AppBar(
title:const Text('Startup Name Generator'),
actions:[
new IconButton(icon:const Icon(Icons.list),onPressed:_pushSaved),
],
),
body:Widget_buildSuggestions(),
);
//return Container();
}
void _pushSaved(){
Navigator.of(context).push(
new MaterialPageRoute(
builder:(BuildContext context){
final Iterable tiles=_saved.map(
(WordPair pair){
return new ListTile(
title:new Text(
pair.asPascalCase,
style: _biggerFont,
),
);
},
);
final List divided=ListTile.divideTiles(
context:context,
tiles:tiles,
).toList();
return new Scaffold(
appBar:new AppBar(
title:const Text('Saved Suggestions'),
),
body:new ListView(children:divided),
);
},
),
);
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BVv6UG1v-1640866944958)(D:\前端学习\Dart学习\flutt-app1.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fdmVedxX-1640866944960)(D:\前端学习\Dart学习\flutter-app2.png)]
Flutter container组件、Text组件