Skip to content

Commit c352af7

Browse files
committed
网络请求抽离到service层,首页增加下拉刷新功能,完成新增文章页面
1 parent c69df9b commit c352af7

File tree

9 files changed

+304
-76
lines changed

9 files changed

+304
-76
lines changed

lib/config.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
22

33
const appConfig = {'title': 'flutter个人博客模板'};
44

5-
const baseUrl = 'http://192.168.1.137:3001';
5+
const baseUrl = 'http://192.168.1.138:3001';
66

77
const primaryColor = const MaterialColor(
88
0xFF66BB6A,

lib/pages/add.dart

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
import 'package:blog_flutter/services/article_service.dart';
2+
import 'package:flutter/material.dart';
3+
4+
class AddWidget extends StatefulWidget {
5+
@override
6+
AddWidgetState createState() => new AddWidgetState();
7+
}
8+
9+
class AddWidgetState extends State<AddWidget> {
10+
String _title = '新增文章';
11+
GlobalKey _globalKey = new GlobalKey();
12+
TextEditingController _titleController = new TextEditingController();
13+
TextEditingController _contentController = new TextEditingController();
14+
TextEditingController _authorController = new TextEditingController();
15+
16+
void _handleSave(BuildContext context) {
17+
if (!(_globalKey.currentState as FormState).validate()) return;
18+
ArticleService.save(_titleController.text, _contentController.text,
19+
_authorController.text)
20+
.then((value) {
21+
Navigator.of(context).pop(value);
22+
});
23+
}
24+
25+
@override
26+
Widget build(BuildContext context) {
27+
return Scaffold(
28+
appBar: AppBar(
29+
title: Text(_title),
30+
),
31+
body: SingleChildScrollView(
32+
child: Padding(
33+
padding: const EdgeInsets.symmetric(vertical: 16.0, horizontal: 24.0),
34+
child: Form(
35+
key: _globalKey,
36+
autovalidateMode: AutovalidateMode.always,
37+
child: Column(
38+
children: [
39+
TextFormField(
40+
controller: _titleController,
41+
decoration: InputDecoration(
42+
labelText: '文章标题',
43+
icon: Icon(Icons.title),
44+
hintText: '请输入文章标题',
45+
),
46+
validator: (value) {
47+
if (value.trim().length == 0) return '请输入文章标题';
48+
return null;
49+
},
50+
),
51+
TextFormField(
52+
controller: _contentController,
53+
maxLines: null,
54+
decoration: InputDecoration(
55+
labelText: '文章内容',
56+
icon: Icon(Icons.border_color),
57+
hintText: '请输入文章内容',
58+
),
59+
validator: (value) {
60+
if (value.trim().length == 0) return '请输入文章内容';
61+
return null;
62+
},
63+
),
64+
TextFormField(
65+
controller: _authorController,
66+
decoration: InputDecoration(
67+
labelText: '文章作者',
68+
icon: Icon(Icons.person),
69+
hintText: '请输入文章作者',
70+
),
71+
validator: (value) {
72+
if (value.trim().length == 0) return '请输入文章作者';
73+
return null;
74+
},
75+
),
76+
Padding(
77+
padding: EdgeInsets.only(top: 16),
78+
child: Row(
79+
children: [
80+
Expanded(
81+
child: ElevatedButton(
82+
child: Text('保存'),
83+
onPressed: () => _handleSave(context)),
84+
)
85+
],
86+
),
87+
),
88+
Row(
89+
children: [
90+
Expanded(
91+
child: ElevatedButton(
92+
child: Text('重置'),
93+
style: ButtonStyle(
94+
backgroundColor: ElevatedBtnBgColor()),
95+
onPressed: () =>
96+
(_globalKey.currentState as FormState).reset()),
97+
)
98+
],
99+
)
100+
],
101+
)),
102+
),
103+
),
104+
);
105+
}
106+
}
107+
108+
class ElevatedBtnBgColor extends MaterialStateColor {
109+
static const int _defaultColor = 0xdddddddd;
110+
static const int _pressedColor = 0xcccccccc;
111+
112+
ElevatedBtnBgColor() : super(_defaultColor);
113+
114+
@override
115+
Color resolve(Set<MaterialState> states) {
116+
if (states.contains(MaterialState.pressed)) {
117+
return new Color(_pressedColor);
118+
}
119+
return new Color(_defaultColor);
120+
}
121+
}

lib/pages/article.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ class ArticleWidget extends StatelessWidget {
1313
return Scaffold(
1414
appBar: AppBar(title: Text(params['title'])),
1515
body: Container(
16+
width: MediaQuery.of(context).size.width,
1617
height: MediaQuery.of(context).size.height,
1718
padding: EdgeInsets.fromLTRB(15, 10, 10, 10),
1819
decoration: BoxDecoration(color: lightGreen),

lib/pages/form.dart

Lines changed: 0 additions & 21 deletions
This file was deleted.

lib/pages/home.dart

Lines changed: 69 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import 'package:blog_flutter/config.dart';
2-
import 'package:blog_flutter/http.dart';
2+
import 'package:blog_flutter/services/article_service.dart';
33
import 'package:flutter/material.dart';
44

55
class HomeWidget extends StatefulWidget {
@@ -8,8 +8,8 @@ class HomeWidget extends StatefulWidget {
88
}
99

1010
class HomeWidgetState extends State<HomeWidget> {
11-
var _articles = <dynamic>[];
12-
var _start = 0, _limit = 10, _total = 0;
11+
List _articles = <dynamic>[];
12+
int _start = 0, _limit = 10, _total = 0;
1313

1414
@override
1515
void initState() {
@@ -18,14 +18,29 @@ class HomeWidgetState extends State<HomeWidget> {
1818
}
1919

2020
void _getArticles() async {
21-
var response = await http
22-
.get('/articles', queryParameters: {'start': _start, 'limit': _limit});
21+
var response = await ArticleService.getArticles(_start, _limit);
22+
print(response);
2323
setState(() {
2424
_articles.addAll(response.data['data']);
2525
_total = response.data['total'];
2626
});
2727
}
2828

29+
void _handleAdd() async {
30+
await Navigator.of(context).pushNamed('/add');
31+
_handlePullDownRefresh();
32+
}
33+
34+
Future _handlePullDownRefresh() {
35+
return Future.delayed(Duration(microseconds: 500), () {
36+
setState(() {
37+
_start = 0;
38+
_articles = [];
39+
_getArticles();
40+
});
41+
});
42+
}
43+
2944
@override
3045
Widget build(BuildContext context) {
3146
return Scaffold(
@@ -36,62 +51,64 @@ class HomeWidgetState extends State<HomeWidget> {
3651
style: TextStyle(color: Colors.white),
3752
)),
3853
),
39-
body: ListView.separated(
40-
itemCount: _articles.length,
41-
itemBuilder: (context, index) {
42-
final backgroundColor = index % 2 == 0 ? lightGreen : lightGrey;
54+
body: RefreshIndicator(
55+
onRefresh: _handlePullDownRefresh,
56+
child: ListView.separated(
57+
itemCount: _articles.length,
58+
itemBuilder: (context, index) {
59+
final backgroundColor = index % 2 == 0 ? lightGreen : lightGrey;
4360

44-
if (_articles.length == 0 || index == _articles.length - 1) {
45-
if (_articles.length < _total - 1) {
46-
_start += _limit;
47-
_getArticles();
48-
return Container(
49-
padding: EdgeInsets.all(16),
50-
alignment: Alignment.center,
51-
decoration: BoxDecoration(color: backgroundColor),
52-
child: SizedBox(
53-
width: 24,
54-
height: 24,
55-
child: CircularProgressIndicator(
56-
strokeWidth: 2,
57-
)),
58-
);
59-
} else {
60-
return Container(
61-
padding: EdgeInsets.all(16),
62-
alignment: Alignment.center,
63-
decoration: BoxDecoration(color: backgroundColor),
64-
child: Text('没有更多了', style: TextStyle(color: Colors.black87)),
65-
);
61+
if (_articles.length == 0 || index == _articles.length - 1) {
62+
if (_articles.length < _total - 1) {
63+
_start += _limit;
64+
_getArticles();
65+
return Container(
66+
padding: EdgeInsets.all(16),
67+
alignment: Alignment.center,
68+
decoration: BoxDecoration(color: backgroundColor),
69+
child: SizedBox(
70+
width: 24,
71+
height: 24,
72+
child: CircularProgressIndicator(
73+
strokeWidth: 2,
74+
)),
75+
);
76+
} else {
77+
return Container(
78+
padding: EdgeInsets.all(16),
79+
alignment: Alignment.center,
80+
decoration: BoxDecoration(color: backgroundColor),
81+
child: Text('没有更多了', style: TextStyle(color: Colors.black87)),
82+
);
83+
}
6684
}
67-
}
6885

69-
return Container(
70-
decoration: BoxDecoration(color: backgroundColor),
71-
child: ListTile(
72-
title: Text(_articles[index]['title'],
86+
return Container(
87+
decoration: BoxDecoration(color: backgroundColor),
88+
child: ListTile(
89+
title: Text(_articles[index]['title'],
90+
overflow: TextOverflow.ellipsis,
91+
style: TextStyle(
92+
fontSize: 22, height: 1.5, color: Colors.green)),
93+
subtitle: Text(
94+
_articles[index]['content'],
7395
overflow: TextOverflow.ellipsis,
74-
style: TextStyle(
75-
fontSize: 22, height: 1.5, color: Colors.green)),
76-
subtitle: Text(
77-
_articles[index]['content'],
78-
overflow: TextOverflow.ellipsis,
79-
maxLines: 2,
80-
style: TextStyle(fontSize: 16, height: 1.5),
96+
maxLines: 2,
97+
style: TextStyle(fontSize: 16, height: 1.5),
98+
),
99+
onTap: () => Navigator.of(context)
100+
.pushNamed('/article', arguments: _articles[index]),
81101
),
82-
onTap: () => Navigator.of(context)
83-
.pushNamed('/article', arguments: _articles[index]),
84-
),
85-
);
86-
},
87-
separatorBuilder: (context, index) => Divider(
88-
height: 0,
102+
);
103+
},
104+
separatorBuilder: (context, index) => Divider(
105+
height: 0,
106+
),
89107
),
90108
),
91109
floatingActionButton: FloatingActionButton(
92110
child: Icon(Icons.add),
93-
onPressed: () =>
94-
Navigator.of(context).pushNamed('/form', arguments: '新增文章'),
111+
onPressed: _handleAdd,
95112
),
96113
);
97114
}

0 commit comments

Comments
 (0)