Android开发 学习Flutter 入门
一、前言
最近项目准备用Flutter混合开发,写写学习的笔记吧,学习Flutter首先需要了解Dart语言,(当然安全上网推荐一个Chrome插件(SetupVpn)),了解Dart相关语法之后,可以到Flutter中文网学习Flutter啦。
二、Flutter 环境搭建
Flutter中文网有详细的教程,我在Mac和Windows上都已经成功安装。
-
Flutter SDK 获取
去flutter官网下载其最新可用的安装包,转到下载页 。下载后将其解压,当前目录将为环境变量需要配置的。
mac 环境变量设置:
alias br="flutter packages pub run build_runner build" # br 快捷键
alias rmlock="rm -rf /Users/ningzhen942/app/flutter/bin/chche/lockfile" #删除lockfile 快捷键
export PATH=/Users/ningzhen942/app/flutter/bin:$PATH
export PUB_HOSTED_URL=https://pub.flutter-io.cn
export FLUTTER_STORAGE_BASE_URL=https://storage.flutter-io.cn
-
配置好环境变量 运行flutter --version 查看版本
-
运行 flutter doctor 查看环境状态
三、Flutter 工程目录结构
四、Flutter Widget 与Android 控件联想
五、Demo(ListView)
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:vscodeflutter/home.dart';
import 'package:vscodeflutter/muti_phote_page.dart';
import 'package:vscodeflutter/phote_view_page.dart';
import 'package:vscodeflutter/widght/gradient_text.dart';
import 'package:cached_network_image/cached_network_image.dart';
void main() {
runApp(new MyApp(
items: new List.generate(1000, (i) {
if (i % 8 == 0) {
return new HeadingItem("Heading I am No.$i");
} else if (i % 8 == 1) {
return new ImageItem(
"https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=2572170802,3058063046&fm=26&gp=0.jpg",
"Message body $i");
} else if (i % 8 == 2) {
List urls = new List.generate(8, (i) {
return "https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=3806557979,3233516071&fm=27&gp=0.jpg";
});
return new ListImageItem(urls, "多图片浏览");
} else {
return new MessageItem("Sender $i", "Message body $i");
}
}),
));
}
class MyApp extends StatelessWidget {
final List items;
MyApp({Key key, @required this.items}) : super(key: key);
@override
Widget build(BuildContext context) {
final title = 'Flutter List';
return new MaterialApp(
title: title,
home: new Scaffold(
appBar: new AppBar(
title: new Text(title),
backgroundColor: Colors.green,
),
body: new ListView.builder(
// Let the ListView know how many items it needs to build
itemCount: items.length,
// Provide a builder function. This is where the magic happens! We'll
// convert each item into a Widget based on the type of item it is.
itemBuilder: (context, index) {
final item = items[index];
if (item is HeadingItem) {
return getTitleItem(item, context);
} else if (item is MessageItem) {
return new ListTile(
title: new Text(item.sender),
subtitle: new Text(item.body),
);
} else if (item is ImageItem) {
return getImageItem(item, context);
} else if (item is ListImageItem) {
return new Container(
height: 220,
width: double.infinity,
padding: EdgeInsets.fromLTRB(10, 10, 0, 10),
child: ListView.builder(
itemBuilder: (context, index) {
return getListItem(context, item, index);
},
itemCount: item.urls.length,
scrollDirection: Axis.horizontal,
));
}
},
),
),
);
}
ListTile getTitleItem(HeadingItem item, BuildContext context) {
return new ListTile(
title: new GestureDetector(
child: new GradientText(
item.heading,
textAlign: TextAlign.left,
gradient: LinearGradient(colors: [Colors.redAccent, Colors.green]),
style: TextStyle(
fontSize: 30.0,
),
),
onTap: () {
Navigator.push(
context,
new MaterialPageRoute(builder: (context) => new HomePage()),
);
},
));
}
Widget getImageItem(ImageItem item, BuildContext context) {
return new Container(
height: 100,
margin: EdgeInsets.only(left: 10),
child: Stack(
children: [
new GestureDetector(
/*child: ClipRRect(
borderRadius: BorderRadius.circular(10),
child: new CachedNetworkImage(
imageUrl: item.url,
height: 100,
),
),*/
child: new ClipOval(
child: new CachedNetworkImage(
imageUrl: item.url,
height: 100,
),
),
onTap: () {
Navigator.push(
context,
new MaterialPageRoute(
builder: (context) => new PhoteViewPage(item.url)));
},
),
],
),
);
}
Container getListItem(BuildContext context, ListImageItem item, int index) {
return new Container(
width: 220,
height: 220,
padding: new EdgeInsets.only(right: 10),
child: GestureDetector(
onTap: () {
Navigator.push(
context,
new MaterialPageRoute(
builder: (context) => new MutiPhotePage(item.urls, index)));
},
child: ClipRRect(
borderRadius: BorderRadius.circular(6),
child: new CachedNetworkImage(
imageUrl: item.urls[index],
fit: BoxFit.cover,
placeholder: (context, url) => new CircularProgressIndicator(),
errorWidget: (context, url, error) => new Icon(Icons.error),
),
),
));
}
}
// The base class for the different types of items the List can contain
abstract class ListItem {}
// A ListItem that contains data to display a heading
class HeadingItem implements ListItem {
final String heading;
HeadingItem(this.heading);
}
// A ListItem that contains data to display a message
class MessageItem implements ListItem {
final String sender;
final String body;
MessageItem(this.sender, this.body);
}
// A ListItem that contains data to display a message
class ImageItem implements ListItem {
final String url;
final String title;
ImageItem(this.url, this.title);
}
// A ListItem that contains data to display a message
class ListImageItem implements ListItem {
final List urls;
final String title;
ListImageItem(this.urls, this.title);
}
六、Demo直接贴代码(图片浏览放大)
-
首先在pubspec.yaml引用phote_view 和网络图片加载库
#https://github.com/renefloor/flutter_cached_network_image
cached_network_image: ^0.7.0
#https://github.com/renancaraujo/photo_view
photo_view: ^0.2.2
import 'package:flutter/material.dart';
import 'package:photo_view/photo_view.dart';
import 'package:cached_network_image/cached_network_image.dart';
// ignore: must_be_immutable
class PhoteViewPage extends StatefulWidget {
String url;
PhoteViewPage(this.url);
@override
PhoteViewPageState createState() => new PhoteViewPageState(this.url);
}
class PhoteViewPageState extends State {
String url;
PhoteViewPageState(this.url);
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('图片浏览'),
backgroundColor: Colors.green,
),
body: new Container(
color: Colors.white,
child: PhotoView(imageProvider: new CachedNetworkImageProvider(url),
backgroundDecoration: new BoxDecoration(color: Colors.white),
),
),
);
}
@override
void initState() {
super.initState();
}
@override
void dispose() {
super.dispose();
}
@override
void didUpdateWidget(PhoteViewPage oldWidget) {
super.didUpdateWidget(oldWidget);
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
}
}
七、多图片浏览
使用TabbarView 与PhoteView 实现多图片的浏览
import 'package:flutter/material.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:photo_view/photo_view.dart';
class MutiPhotePage extends StatefulWidget {
List urls;
int postion;
MutiPhotePage(this.urls, this.postion);
@override
MutiPhotePageState createState() => new MutiPhotePageState(urls, postion);
}
class MutiPhotePageState extends State with SingleTickerProviderStateMixin{
List urls;
int postion;
TabController tabController;
MutiPhotePageState(this.urls, this.postion);
List getTabView() {
return urls.map((url) {
return new Container(
child: PhotoView(
imageProvider: new CachedNetworkImageProvider(url),
backgroundDecoration: new BoxDecoration(color: Colors.white),
),
);
}).toList(growable: true);
}
@override
void initState() {
super.initState();
this.tabController =
new TabController(length: urls.length, initialIndex: postion,vsync: this);
}
@override
void dispose() {
super.dispose();
}
@override
void didUpdateWidget(MutiPhotePage oldWidget) {
super.didUpdateWidget(oldWidget);
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
}
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("查看多张图片"),
backgroundColor: Colors.green,
),
body: new Container(
child: new TabBarView(
children: getTabView(),
controller: tabController,
),
),
);
}
}