文章来自:http://blog.csdn.net/intbird
主要是两个使用方式:
1. RefreshIndicator 包裹 CustomScrollView ( appbar + pindHeader + sliverList)
2. NestedScrollView 包裹 AppBar + RefreshIndicator( ListView)
方便在没有服务器配合的情况下,单端完成数据调试
> brew update
> brew search nginx
> brew install nginx
> open /usr/local/Cellar/nginx/ // 查看nginx版本,比如后续的 1.17.6
> ln -s /usr/local/Cellar/nginx/1.17.6/docs /Users/intbird/configs/nginx/docs // 挂载新建的docs目录到指定目录下
> touch /Users/intbird/configs/nginx/docs/index.json // 创建一个默认的json文件,写点东西进去做测试
1 > open /usr/local/etc/nginx/
2 写入 nginx.conf 文件如图配置:
3 > sudo nginx // 首次启动nginx
4 如果已经启动则可刷新配置: sudo nginx -s reload ;
停止nginx: sudo nginx -s stop
5 访问nginx地址,配置完成:
附:除了本地插件,也可以在线json转dartbean: https://javiercbk.github.io/json_to_dart/
重点示意:
效果示意:
RefreshIndicator + SliverList 下拉刷新 | RefreshIndicator + SliverList 上拉 |
![]() |
![]() |
/// homepage.dart
void main() => runApp(new MaterialApp(
debugShowCheckedModeBanner: false,
theme:ThemeData(brightness: Brightness.light, primaryColor: Colors.blueGrey),
home: _scaffoldRefreshFromStatusBar()));
Scaffold _scaffoldRefreshFromStatusBar() {
// 下拉刷新完成通知列表数据刷新
SwipeValueNotifierData swipeValueNotifierData =
new SwipeValueNotifierData(new List());
return new Scaffold(
body: SwipeRefreshContainer(
// 下拉刷新完成存储最新数据
swipeValueNotifierData: swipeValueNotifierData,
swipeRefreshBody: SliverAppBarContainer1(
//使用最新数据
swipeValueNotifierData: swipeValueNotifierData,
)),
floatingActionButton: _floatingActionButton(),
);
}
///swiper-refresh-container.dart
import 'package:flutter/material.dart';
import 'api/HomePageApi.dart' as api;
import 'api/beans/list_beans_entity.dart';
class SwipeRefreshContainer extends StatefulWidget {
final Widget swipeRefreshBody;
final SwipeValueNotifierData swipeValueNotifierData;
SwipeRefreshContainer(
{Key key, this.swipeRefreshBody, this.swipeValueNotifierData})
: super(key: key);
@override
State createState() {
return _CreateState();
}
}
class _CreateState extends State {
final GlobalKey _refreshIndicatorKey =
new GlobalKey();
@override
void initState() {
super.initState();
WidgetsBinding.instance
.addPostFrameCallback((_) => _refreshIndicatorKey.currentState.show());
}
@override
Widget build(BuildContext context) {
return RefreshIndicator(
key: _refreshIndicatorKey,
onRefresh: _refresh,
child: widget.swipeRefreshBody ?? new Text("EMPTY"),
);
}
Future
///sliver-appbar-container-1.dart
import 'package:flutter/material.dart';
import 'package:intbird_lean_flutter_project/homepage/ListSliverWidget.dart';
import 'package:intbird_lean_flutter_project/homepage/SwipeRefreshContainer.dart';
class SliverAppBarContainer1 extends StatefulWidget {
final SwipeValueNotifierData swipeValueNotifierData;
SliverAppBarContainer1({Key key, this.swipeValueNotifierData})
: super(key: key);
@override
State createState() {
return _SliverAppBarBodyState();
}
}
class _SliverAppBarBodyState extends State {
List
//ListSliverWidget.dart
class ListSliverWidget {
final List listItems;
ListSliverWidget(this.listItems);
SliverChildBuilderDelegate createDelegate() {
return SliverChildBuilderDelegate((context, index) {
Object object = null != listItems ? listItems[index] : null;
if (object is ListBeans) {
return new ListBeanWidget(object);
}
return new Text("--no defined item--");
}, childCount: listItems?.length ?? 1);
}
}
重点示意: 因为头部多加了两个组件,所以刷新指示条位置较低
效果示意:
NestedScrollView + ( RefreshIndicator + listview) | 上推 |
![]() |
![]() |
/// homepage.dart
// scrollview内部进行下拉刷新
Scaffold _scaffoldRefreshFromAppBar() {
SwipeValueNotifierData swipeValueNotifierData =
new SwipeValueNotifierData(new List());
return new Scaffold(
body: SliverAppBarContainer2(
child: SwipeRefreshContainer(
// 下拉刷新赋值数据
swipeValueNotifierData: swipeValueNotifierData,
swipeRefreshBody: ListViewWidget(
// Listview监听数据刷新列表
swipeValueNotifierData: swipeValueNotifierData,
),
)),
floatingActionButton: _floatingActionButton(),
);
}
///swipe-refresh-container.dart
import 'package:flutter/material.dart';
import 'api/HomePageApi.dart' as api;
import 'api/beans/list_beans_entity.dart';
class SwipeRefreshContainer extends StatefulWidget {
final Widget swipeRefreshBody;
final SwipeValueNotifierData swipeValueNotifierData;
SwipeRefreshContainer(
{Key key, this.swipeRefreshBody, this.swipeValueNotifierData})
: super(key: key);
@override
State createState() {
return _CreateState();
}
}
class _CreateState extends State {
final GlobalKey _refreshIndicatorKey =
new GlobalKey();
@override
void initState() {
super.initState();
WidgetsBinding.instance
.addPostFrameCallback((_) => _refreshIndicatorKey.currentState.show());
}
@override
Widget build(BuildContext context) {
return RefreshIndicator(
key: _refreshIndicatorKey,
onRefresh: _refresh,
child: widget.swipeRefreshBody ?? new Text("EMPTY"),
);
}
Future _refresh() {
return api.getListBeans().then((_lists) {
widget.swipeValueNotifierData.value = _lists;
}).catchError((error) {
print(error);
});
}
}
class SwipeValueNotifierData extends ValueNotifier> {
SwipeValueNotifierData(List value) : super(value);
}
/// sliver-appbar-container-2.dart
import 'package:flutter/material.dart';
import 'package:intbird_lean_flutter_project/homepage/ListSliverWidget.dart';
import 'package:intbird_lean_flutter_project/homepage/SwipeRefreshContainer.dart';
class SliverAppBarContainer2 extends StatefulWidget {
final Widget child;
SliverAppBarContainer2({Key key, this.child}) : super(key: key);
@override
State createState() {
return _SliverAppBarBodyState();
}
}
class _SliverAppBarBodyState extends State {
@override
Widget build(BuildContext context) {
return _scaffoldRefreshFromAppBar();
}
/// 传统做法 NestedScrollView: body由外部传入,可以是一个list
Scaffold _scaffoldRefreshFromAppBar() {
return new Scaffold(
body: NestedScrollView(
headerSliverBuilder: (context, innerBoxIsScrolled) {
return [
sliverAppBar(context),
persistentHeader(),
];
},
body: widget.child,
));
}
SliverPersistentHeader persistentHeader() {
return SliverPersistentHeader(
delegate: _SliverHeaderDelegate(),
pinned: false,
);
}
Widget sliverAppBar(context) {
return SliverAppBar(
floating: false,
title: const Text("intbird title"),
expandedHeight: 130,
flexibleSpace: FlexibleSpaceBar(
title: new Text("intbird flexibleSpace"),
collapseMode: CollapseMode.pin,
),
);
}
Widget sliverAbsorber(context) {
return SliverOverlapAbsorber(
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
child: SliverSafeArea(
top: false,
sliver: SliverAppBar(
expandedHeight: 200,
pinned: true,
flexibleSpace: FlexibleSpaceBar(
title: Text('Title'),
background: Container(color: Colors.amber)),
),
));
}
}
class _SliverHeaderDelegate extends SliverPersistentHeaderDelegate {
@override
Widget build(
BuildContext context, double shrinkOffset, bool overlapsContent) {
return new Container(
color: Colors.red,
alignment: Alignment.center,
child: new Text("SliverPersistentHeader"));
}
@override
// TODO: implement maxExtent
double get maxExtent => 100;
@override
// TODO: implement minExtent
double get minExtent => 100;
@override
bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) {
return false;
}
}
/// list-view-widget.dart
class ListViewWidget extends StatefulWidget {
final SwipeValueNotifierData swipeValueNotifierData;
const ListViewWidget({Key key, this.swipeValueNotifierData})
: super(key: key);
@override
State createState() {
return new _ListViewState();
}
}
class _ListViewState extends State {
List listItems = new List();
_ListViewState({Key key, this.listItems});
@override
void initState() {
super.initState();
widget.swipeValueNotifierData.addListener(_swipeRefreshDataChanged);
}
_swipeRefreshDataChanged() {
setState(() {
listItems = widget.swipeValueNotifierData.value;
});
}
@override
Widget build(BuildContext context) {
return new ListView.builder(
padding: EdgeInsets.zero,
itemCount: listItems?.length ?? 1,
itemBuilder: (context, index) {
Object object = null != listItems ? listItems[index] : null;
print("ListList:$object");
if (object is ListBeans) {
return new ListBeanWidget(object);
}
return new Text("--no defined item--");
},
);
}
}
1. bean
// index.json
[
{
"title": "title",
"subTitle": "subTitle",
"imageUrl": "imageUrl",
"schemeUrl": "schemeUrl"
},
{
"title": "title",
"subTitle": "subTitle",
"imageUrl": "imageUrl",
"schemeUrl": "schemeUrl"
},
...
]
2,接口请求:
import 'dart:async';
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'beans/list_beans_entity.dart';
const HOST_URL = "http://192.168.3.156:8080";
const CONFIG_URL = "$HOST_URL/homepage-config";
Future> getListBeans() async {
final response = await http.get(CONFIG_URL);
final respJson = json.decode(new Utf8Decoder().convert(response.bodyBytes));
return ListBeans.fromJsonList(respJson);
}
文章来自:http://blog.csdn.net/intbird