一 根据codelab https://codelabs.flutter-io.cn/codelabs/first-flutter-app-pt1-cn/index.html#0 制作第一个flutter app
配置好环境后,运行IDE自动生成的flutter demo一直卡在 Running Gradle task 'assembleDebug’或报connect timeout错误,需要在android/build.gradle中修改repository地址。
buildscript 和 allprojects都需要改。
repositories {
//google()
//jcenter()
maven { url 'https://maven.aliyun.com/repository/google' }
maven { url 'https://maven.aliyun.com/repository/jcenter' }
maven { url 'https://maven.aliyun.com/repository/public' }
maven { url 'http://download.flutter.io'}
}
改完后发现并没有解决问题,这是因为flutter自带的gradle里仍然有地址需要修改
flutter\packages\flutter_tools\gradle\ 中
flutter.gradle
repositories {
//google()
//jcenter()
maven { url 'https://maven.aliyun.com/repository/google' }
maven { url 'https://maven.aliyun.com/repository/jcenter' }
maven { url 'https://maven.aliyun.com/repository/public' }
}
------------------------------------------
private static final String MAVEN_REPO 改为 "download.flutter.io"
resolve_dependencies.gradle
repositories {
maven {
url "http://download.flutter.io"
}
}
再次运行,成功~(还是不行的话也可能是网络不好,可以换流量试试)
codelab的教程还是非常详细的,照着做基本没有什么问题。
成果图
做完后想自己添加一些新功能,比如在喜欢列表的页面里点击项目可以把该项目取消喜欢。
_navigateToSaved() {
Navigator.of(context)
.push(new MaterialPageRoute(builder: (BuildContext context) {
final Iterable<ListTile> tiles = _saved.map(
(WordPair pair) {
return new ListTile(
title: new Text(
pair.asPascalCase,
style: _fontSize,
),
trailing: new Icon(
// 新增代码开始 ...
Icons.favorite,
color: Colors.red,
),
);
},
);
_divided = ListTile.divideTiles(context: context, tiles: tiles).toList();
return savedList(
saved: _saved,
divided: _divided,
);
// new Scaffold(
// // 新增 6 行代码开始 ...
// appBar: new AppBar(
// title: const Text('Saved Suggestions'),
// ),
//// body: new ListView(children: divided,)
// body: ListView.builder(
// itemCount: divided.length,
// itemBuilder: (context, index) {
// if (index < divided.length) {
// final item = divided[index];
// return GestureDetector(
// onTap: () {
// divided.removeAt(index);
// setState(() {});
// },
// child: item,
// );
// }
// }),
// );
}));
}
一开始想直接在 MaterialPageRoute 的builder里直接返回onTap逻辑,但这样点击后列表中确实删除了,但setState并没有生效,没有重新渲染页面。
后来觉得应该直接再写一个widget,单独控制state
class savedList extends StatefulWidget {
final saved;
final divided;
savedList({this.saved, this.divided});
@override
State<StatefulWidget> createState() => _savedListState(saved, divided);
}
class _savedListState extends State<savedList> {
var saved;
var divided;
_savedListState(this.saved, this.divided);
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar:
new AppBar(title: const Text('Saved Suggestions'),
),
// body: new ListView(children: divided,)
body: ListView.builder(
itemCount: divided.length,
itemBuilder: (context, index) {
if (index < divided.length) {
final item = divided[index];
return GestureDetector(
onTap: () {
_divided.removeAt(index);
_saved.removeAt(index);
setState(() {});
},
child: item,
);
}
}),
);
}
}
这样喜欢列表的页面可以刷新了,但返回后的列表仍然没有刷新,这时需要重写返回按钮
new AppBar(title: const Text('Saved Suggestions'),
leading:
new IconButton(
icon: const Icon(Icons.arrow_back),
//pop时随便带个参数
onPressed: () => {Navigator.of(context).pop("aaa")},
)
),
_navigateToSaved方法中,push后加上.then(value)=>{setState(){});
这样就可以接到pop的参数,实现刷新。
完整代码
import 'package:flutter/material.dart';
import 'package:english_words/english_words.dart';
void main() => runApp(MyApp());
var _wordList = <WordPair>[];
var _saved = <WordPair>[];
var _fontSize = TextStyle(fontSize: 18.0);
var _divided = <Widget>[];
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(title: 'Welcome to Flutter', home: RandomWords());
}
}
class RandomWords extends StatefulWidget {
@override
_RandomWordsState createState() => _RandomWordsState();
}
class _RandomWordsState extends State<RandomWords> {
Widget _buildWordList() {
return ListView.builder(
padding: EdgeInsets.all(16),
itemBuilder: (context, i) {
if (i.isOdd) {
return Divider();
}
final index = i ~/ 2;
if (index >= _wordList.length) {
_wordList.addAll(generateWordPairs().take(10));
}
return _buildRow(_wordList[index]);
});
}
Widget _buildRow(WordPair pair) {
final bool alreadySaved = _saved.contains(pair);
return ListTile(
title: Text(
pair.asPascalCase,
style: _fontSize,
),
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);
}
});
},
);
}
_navigateToSaved() {
Navigator.of(context)
.push(new MaterialPageRoute(builder: (BuildContext context) {
final Iterable<ListTile> tiles = _saved.map(
(WordPair pair) {
return new ListTile(
title: new Text(
pair.asPascalCase,
style: _fontSize,
),
trailing: new Icon(
// 新增代码开始 ...
Icons.favorite,
color: Colors.red,
),
);
},
);
_divided = ListTile.divideTiles(context: context, tiles: tiles).toList();
return savedList(
saved: _saved,
divided: _divided,
);
})).then((value) => setState(() {}));
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Startup Name Generator'),
actions: <Widget>[
new IconButton(
icon: const Icon(Icons.list), onPressed: _navigateToSaved)
],
),
body: _buildWordList(),
);
}
}
class savedList extends StatefulWidget {
final saved;
final divided;
savedList({this.saved, this.divided});
@override
State<StatefulWidget> createState() => _savedListState(saved, divided);
}
class _savedListState extends State<savedList> {
var saved;
var divided;
_savedListState(this.saved, this.divided);
@override
Widget build(BuildContext context) {
return new Scaffold(
// 新增 6 行代码开始 ...
appBar:
new AppBar(title: const Text('Saved Suggestions'),
leading:
new IconButton(
icon: const Icon(Icons.arrow_back),
onPressed: () => {Navigator.of(context).pop("aaa")},
)
),
body: ListView.builder(
itemCount: divided.length,
itemBuilder: (context, index) {
if (index < divided.length) {
final item = divided[index];
return GestureDetector(
onTap: () {
_divided.removeAt(index);
_saved.removeAt(index);
setState(() {});
},
child: item,
);
}
}),
);
}
}