Add:创建 flutter go web 版

This commit is contained in:
ryan
2019-08-14 23:15:38 +08:00
parent da67ccf5a8
commit 060db7f718
40 changed files with 4568 additions and 253 deletions

75
README copy.md Normal file
View File

@ -0,0 +1,75 @@
安装flutter_web构建工具
要安装webdev包为Flutter for web提供构建工具的 包,请运行以下命令:
$ flutter packages pub global activate webdev
确保$HOME/.pub-cache/bin目录 在您的路径中然后您可以webdev直接从终端使用该命令。
注意如果您在配置webdev直接运行时遇到问题请尝试
flutter packages pub global run webdev [command]。
运行hello_world示例
该示例存在于examples/hello_world存储库中。
$ cd examples / hello_world /
更新包。
$ flutter包升级
flutter_web 0.0.0 from path ../../flutter_web
flutter_web_ui 0.0.0 from path ../../flutter_web_ui
在hello_world中运行“flutter packages upgrade”... 5.0s
如果成功,你就可以运行了!
在本地构建并提供示例。
$ webdev serve
[INFO]生成构建脚本完成耗时331ms
...
[INFO]建立新资产图完成耗时1.4s
...
[INFO]运行构建完成耗时27.9s
...
[INFO] 28.1后成功s有618个输出3233个动作
在http// localhost8080上提供`web`
在Chrome中打开http// localhost8080您应该会Hello World在左上角看到红色文字。
获取(无状态)热重载 webdev
要webdev与热重载一起使用请在项目目录中运行以下命令
$ webdev serve --auto restart
您会注意到````的相似输出flutter packages pub run build_runner serve 但现在更改为您的应用程序代码应该导致在保存时快速刷新应用程序。
注意:该--hot-reload选项并不完美。如果发现意外行为则可能需要手动刷新页面。
注意:该--hot-reload选项目前是“无状态”。重新加载时应用程序状态将丢失。我们希望在网上提供“有状态”的热重载 - 我们正积极致力于此!
使用生产JavaScript编译器构建
上面介绍的工作流程可用于build_runner和webdev使用Dart Dev Compiler它专为快速增量编译和简单调试而设计。
如果您想评估生产性能,浏览器兼容性和代码大小,可以启用我们的发布编译器 dart2js。
要启用发布编译器,请传入--release标志或只是-r
$ webdev serve -r
注意:此配置中的构建可能会更慢。
如果您想生成输出到磁盘我们建议您使用webdev。
$ webdev build
这将创建一个build目录index.htmlmain.dart.js以及使用静态HTTP服务器运行应用程序所需的其余文件。
要优化输出JavaScript可以使用build.yaml项目根目录中的文件启用优化标志 ,其中包含以下内容:
请参阅https://github.com/dart-lang/build/tree/master/build_web_compilers#configuration
目标:
$ default
builders
build_web_compilers | entrypoint
generate_for
- web / **。dart
选项:
dart2js_args
- --no-source-maps
- -O4
注意:该-O4选项启用了许多高级优化这些优化可能会导致未经过全面测试的代码中的运行时错误。
uglifyjs project/ali-flutter-go/build/main.dart.js -o project/ali-flutter-go/build/main.dart.js

121
README.md
View File

@ -1,75 +1,80 @@
安装flutter_web构建工具
要安装webdev包为Flutter for web提供构建工具的 包,请运行以下命令:
### 欢迎来到 `Flutter GO for web` 的代码库。
##### 此代码库是配合 [Flutter-web](https://github.com/flutter/flutter_web) 官方预览版, 而对 `Flutter Go` 项目做的 `web` 版本的移植。
$ flutter packages pub global activate webdev
确保$HOME/.pub-cache/bin目录 在您的路径中然后您可以webdev直接从终端使用该命令。
#### `Flutter的Web`支持尚不稳定。我们将此版本指定为技术预览版; 对 `Flutter Go native` 版本移植还原度大概在 80%左右。旨在帮助 `Flutter` 开发人员,快速熟悉 `Flutter-web` 官方的实践。
注意如果您在配置webdev直接运行时遇到问题请尝试
flutter packages pub global run webdev [command]。
#### [在 `Flutter` 官方宣布Flutter暂时不会开发热更新Code push](https://github.com/flutter/flutter/issues/14330) 之后, `Flutter-web` 无疑是的动态更新代码最快捷的方式,虽然不是最佳方案,但是是最易用降级方案。
运行hello_world示例
该示例存在于examples/hello_world存储库中。
#### 通过 `Flutter-go-web` 版本的学习,可以快速,有效还原 `Flutter-go` native 版本。帮助开发者对快速版本H5化,做一个样例展示,提供 `Flutter-web` 的能力演示。
$ cd examples / hello_world /
更新包。
### 使用前准备
- [请了解 `Flutter-web` 官方说明](https://github.com/flutter/flutter_web/blob/master/README.md)
$ flutter包升级
flutter_web 0.0.0 from path ../../flutter_web
flutter_web_ui 0.0.0 from path ../../flutter_web_ui
在hello_world中运行“flutter packages upgrade”... 5.0s
如果成功,你就可以运行了!
### 如何使用
- git 拉取 `Flutter-go` 项目,并切换到 `web/flutter-go-web-0.0.1` 分支
```dart
$ git clone https://github.com/alibaba/flutter-go.git flutter-go
在本地构建并提供示例。
$ git checkout web/flutter-go-web-0.0.1
```
$ webdev serve
[INFO]生成构建脚本完成耗时331ms
...
[INFO]建立新资产图完成耗时1.4s
...
[INFO]运行构建完成耗时27.9s
...
[INFO] 28.1后成功s有618个输出3233个动作
在http// localhost8080上提供`web`
在Chrome中打开http// localhost8080您应该会Hello World在左上角看到红色文字。
- 安装flutter_web构建工具
```dart
$ flutter pub global activate webdev
```
获取(无状态)热重载 webdev
要webdev与热重载一起使用请在项目目录中运行以下命令
- 更新pub包
```dart
$ pub get
$ webdev serve --auto restart
您会注意到````的相似输出flutter packages pub run build_runner serve 但现在更改为您的应用程序代码应该导致在保存时快速刷新应用程序。
//...
Resolving dependencies...
Warning: You are using these overridden dependencies:
! flutter_web 0.0.0 from git https://github.com/flutter/flutter_web at 6cabfc in packages/flutter_web
! flutter_web_test 0.0.0 from git https://github.com/flutter/flutter_web at 6cabfc in packages/flutter_web_test
! flutter_web_ui 0.0.0 from git https://github.com/flutter/flutter_web at 6cabfc in packages/flutter_web_ui
Got dependencies!
Precompiling executables... (12.0s)
```
注意:该--hot-reload选项并不完美。如果发现意外行为则可能需要手动刷新页面。
- 开发模式,获取(无状态)热重载 webdev
```dart
$ webdev serve --auto restart
注意:该--hot-reload选项目前是“无状态”。重新加载时应用程序状态将丢失。我们希望在网上提供“有状态”的热重载 - 我们正积极致力于此!
[INFO] Building new asset graph completed, took 2.0s
[INFO] Checking for unexpected pre-existing outputs. completed, took 1ms
[INFO] Serving `web` on http://127.0.0.1:8080
[INFO] Running build completed, took 49.7s
[INFO] Caching finalized dependency graph completed, took 421ms
[INFO] Succeeded after 50.1s with 3309 outputs (9338 actions)
```
使用生产JavaScript编译器构建
上面介绍的工作流程可用于build_runner和webdev使用Dart Dev Compiler它专为快速增量编译和简单调试而设计。
- 发布模式,创建最终编译结果,这将创建一个build目录`index.html``main.dart.js`以及使用静态HTTP服务器运行应用程序所需的其余文件。
```dart
$ webdev build
```
如果您想评估生产性能,浏览器兼容性和代码大小,可以启用我们的发布编译器 dart2js。
pub global activate --source path /Users/ryan/work/ali/github/flutter-project/@ali-flutter-go/tools/
要启用发布编译器,请传入--release标志或只是-r
### 通过上面操作基本就能运行,`flutter-go-web` 的界面
$ webdev serve -r
注意:此配置中的构建可能会更慢
### 为了对已有 `native` 工程快速生成 `flutter-web` 版本,可以使用 `trans2fw` 工具
- 首先拷贝 native 版本下的lib 文件夹到当前目录, 并重命名如: lib-cp。
如果您想生成输出到磁盘我们建议您使用webdev。
- 安装 `trans2fw` 工具, 并注册程序
```dart
$ pub global activate trans2fw
$ pub global run trans2fw
```
$ webdev build
这将创建一个build目录index.htmlmain.dart.js以及使用静态HTTP服务器运行应用程序所需的其余文件。
要优化输出JavaScript可以使用build.yaml项目目录中的文件启用优化标志 ,其中包含以下内容:
请参阅https://github.com/dart-lang/build/tree/master/build_web_compilers#configuration
目标:
$ default
builders
build_web_compilers | entrypoint
generate_for
- web / **。dart
选项:
dart2js_args
- --no-source-maps
- -O4
注意:该-O4选项启用了许多高级优化这些优化可能会导致未经过全面测试的代码中的运行时错误。
uglifyjs project/ali-flutter-go/build/main.dart.js -o project/ali-flutter-go/build/main.dart.js
- 运行 `trans2fw` 工具,根据提示输入
```dart
$ trans2fw
[] 请输入需要转换的文件目录(相对于项目目录): lib-cp
[] 是否覆盖原有文件 ? (y/N) y
{path: lib-cp, cover: true}
使用输入文件目录:lib-cp
被转换的文件::lib-cp/Pagination.dart::32
被转换的文件::lib-cp/homeBanner-copy-copy.dart::32
...
```

View File

@ -0,0 +1,100 @@
import 'package:flutter_web/material.dart';
import 'package:flutter_rookie_book/views/Detail.dart';
class CompList extends StatefulWidget {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return new ListState();
}
}
class ListState extends State<CompList> {
@override
Widget build(BuildContext context) {
/// getData() ; this is test;
return new ListView.builder(
//itemCount: data == null ? 0 : data.length,
itemCount: 100,
itemBuilder: (BuildContext context, int index) {
return new Card(
/////child: new Container(
/////padding: new EdgeInsets.all(10.0),
child: new ListTile(
subtitle: new Container(
child: new Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
new Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
new Expanded(
child: new Text("Title",
///data[index]["title"],
style: new TextStyle(
fontWeight: FontWeight.bold, fontSize: 16.0)),
)
],
),
new Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
new Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
new Text("time:"),
new Text("2018-05-06")
],
),
],
),
new Row(
children: <Widget>[
new Container(
padding:
const EdgeInsets.fromLTRB(0.0, 8.0, 0.0, 2.0),
child: new Text("content"),
///child: new Text("id:"+data[index]["id"].toString()),
),
],
),
],
),
),
trailing: new Icon(
Icons.keyboard_arrow_right,
color: Colors.grey,
),
///onTap: () => _onTap(data[index]["id"].toString()),
onTap: () => _onTap('1'),
),
/////),
);
},
);
}
void _onTap(String id){
Navigator.of(context).push(new PageRouteBuilder(
opaque: false,
pageBuilder: (BuildContext context, _,__){
return new Detail(id);
},
transitionsBuilder: (_,Animation<double> animation,__,Widget child){
return new FadeTransition(
opacity: animation,
child: new SlideTransition(position: new Tween<Offset>(
begin: const Offset(0.0, 1.0),
end: Offset.zero,
).animate(animation),child: child,
),
) ;
}
));
}
}

View File

@ -0,0 +1,100 @@
import 'package:flutter_web/material.dart';
import 'package:flutter_rookie_book/views/Detail.dart';
class CompList extends StatefulWidget {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return new ListState();
}
}
class ListState extends State<CompList> {
@override
Widget build(BuildContext context) {
/// getData() ; this is test;
return new ListView.builder(
//itemCount: data == null ? 0 : data.length,
itemCount: 100,
itemBuilder: (BuildContext context, int index) {
return new Card(
/////child: new Container(
/////padding: new EdgeInsets.all(10.0),
child: new ListTile(
subtitle: new Container(
child: new Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
new Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
new Expanded(
child: new Text("Title",
///data[index]["title"],
style: new TextStyle(
fontWeight: FontWeight.bold, fontSize: 16.0)),
)
],
),
new Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
new Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
new Text("time:"),
new Text("2018-05-06")
],
),
],
),
new Row(
children: <Widget>[
new Container(
padding:
const EdgeInsets.fromLTRB(0.0, 8.0, 0.0, 2.0),
child: new Text("content"),
///child: new Text("id:"+data[index]["id"].toString()),
),
],
),
],
),
),
trailing: new Icon(
Icons.keyboard_arrow_right,
color: Colors.grey,
),
///onTap: () => _onTap(data[index]["id"].toString()),
onTap: () => _onTap('1'),
),
/////),
);
},
);
}
void _onTap(String id){
Navigator.of(context).push(new PageRouteBuilder(
opaque: false,
pageBuilder: (BuildContext context, _,__){
return new Detail(id);
},
transitionsBuilder: (_,Animation<double> animation,__,Widget child){
return new FadeTransition(
opacity: animation,
child: new SlideTransition(position: new Tween<Offset>(
begin: const Offset(0.0, 1.0),
end: Offset.zero,
).animate(animation),child: child,
),
) ;
}
));
}
}

100
lib-cp/CompList-copy.dart Normal file
View File

@ -0,0 +1,100 @@
import 'package:flutter_web/material.dart';
import 'package:flutter_rookie_book/views/Detail.dart';
class CompList extends StatefulWidget {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return new ListState();
}
}
class ListState extends State<CompList> {
@override
Widget build(BuildContext context) {
/// getData() ; this is test;
return new ListView.builder(
//itemCount: data == null ? 0 : data.length,
itemCount: 100,
itemBuilder: (BuildContext context, int index) {
return new Card(
/////child: new Container(
/////padding: new EdgeInsets.all(10.0),
child: new ListTile(
subtitle: new Container(
child: new Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
new Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
new Expanded(
child: new Text("Title",
///data[index]["title"],
style: new TextStyle(
fontWeight: FontWeight.bold, fontSize: 16.0)),
)
],
),
new Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
new Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
new Text("time:"),
new Text("2018-05-06")
],
),
],
),
new Row(
children: <Widget>[
new Container(
padding:
const EdgeInsets.fromLTRB(0.0, 8.0, 0.0, 2.0),
child: new Text("content"),
///child: new Text("id:"+data[index]["id"].toString()),
),
],
),
],
),
),
trailing: new Icon(
Icons.keyboard_arrow_right,
color: Colors.grey,
),
///onTap: () => _onTap(data[index]["id"].toString()),
onTap: () => _onTap('1'),
),
/////),
);
},
);
}
void _onTap(String id){
Navigator.of(context).push(new PageRouteBuilder(
opaque: false,
pageBuilder: (BuildContext context, _,__){
return new Detail(id);
},
transitionsBuilder: (_,Animation<double> animation,__,Widget child){
return new FadeTransition(
opacity: animation,
child: new SlideTransition(position: new Tween<Offset>(
begin: const Offset(0.0, 1.0),
end: Offset.zero,
).animate(animation),child: child,
),
) ;
}
));
}
}

100
lib-cp/CompList.dart Normal file
View File

@ -0,0 +1,100 @@
import 'package:flutter_web/material.dart';
import 'package:flutter_rookie_book/views/Detail.dart';
class CompList extends StatefulWidget {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return new ListState();
}
}
class ListState extends State<CompList> {
@override
Widget build(BuildContext context) {
/// getData() ; this is test;
return new ListView.builder(
//itemCount: data == null ? 0 : data.length,
itemCount: 100,
itemBuilder: (BuildContext context, int index) {
return new Card(
/////child: new Container(
/////padding: new EdgeInsets.all(10.0),
child: new ListTile(
subtitle: new Container(
child: new Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
new Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
new Expanded(
child: new Text("Title",
///data[index]["title"],
style: new TextStyle(
fontWeight: FontWeight.bold, fontSize: 16.0)),
)
],
),
new Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
new Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
new Text("time:"),
new Text("2018-05-06")
],
),
],
),
new Row(
children: <Widget>[
new Container(
padding:
const EdgeInsets.fromLTRB(0.0, 8.0, 0.0, 2.0),
child: new Text("content"),
///child: new Text("id:"+data[index]["id"].toString()),
),
],
),
],
),
),
trailing: new Icon(
Icons.keyboard_arrow_right,
color: Colors.grey,
),
///onTap: () => _onTap(data[index]["id"].toString()),
onTap: () => _onTap('1'),
),
/////),
);
},
);
}
void _onTap(String id){
Navigator.of(context).push(new PageRouteBuilder(
opaque: false,
pageBuilder: (BuildContext context, _,__){
return new Detail(id);
},
transitionsBuilder: (_,Animation<double> animation,__,Widget child){
return new FadeTransition(
opacity: animation,
child: new SlideTransition(position: new Tween<Offset>(
begin: const Offset(0.0, 1.0),
end: Offset.zero,
).animate(animation),child: child,
),
) ;
}
));
}
}

View File

@ -0,0 +1,178 @@
/**
* Created with Android Studio.
* User: 一晟
* Date: 2019/1/4
* Time: 上午1:16
* email: zhu.yan@alibaba-inc.com
* tartget: FlatButton 的示例
*/
import 'package:flutter_web/material.dart';
import 'dart:math';
class ListRefresh extends StatefulWidget {
final renderItem;
final requestApi;
const ListRefresh([this.requestApi,this.renderItem]) : super();
@override
State<StatefulWidget> createState() => listRefresh();
}
class listRefresh extends State<ListRefresh> {
bool isLoading = false; // 是否正在请求数据中
bool _hasMore = true; // 是否还有更多数据可加载
int _pageIndex = 0; // 页面的索引
int _pageTotal = 0; // 页面的索引
List items = new List();
ScrollController _scrollController = new ScrollController();
@override
void initState() {
super.initState();
_getMoreData();
_scrollController.addListener(() {
// 如果下拉的当前位置到scroll的最下面
if (_scrollController.position.pixels == _scrollController.position.maxScrollExtent) {
_getMoreData();
}
});
}
/*
* 回弹效果
* */
backElasticEffect(){
// double edge = 50.0;
// double offsetFromBottom = _scrollController.position.maxScrollExtent - _scrollController.position.pixels;
// if (offsetFromBottom < edge) { // 添加一个动画没有更多数据的时候 ListView 向下移动覆盖正在加载更多数据的标志
// _scrollController.animateTo(
// _scrollController.offset - (edge -offsetFromBottom),
// duration: new Duration(milliseconds: 1000),
// curve: Curves.easeOut);
// }
}
/*
* list探底执行的具体事件
* */
Future _getMoreData() async {
if (!isLoading && _hasMore) { // 如果上一次异步请求数据完成 同时有数据可以加载
setState(() => isLoading = true);
//if(_hasMore){ // 还有数据可以拉新
List newEntries = await mokeHttpRequest();
//if (newEntries.isEmpty) {
_hasMore = (_pageIndex <= _pageTotal);
setState(() {
items.addAll(newEntries);
isLoading = false;
});
backElasticEffect();
}else if (!isLoading && !_hasMore){ // 这样判断,减少以后的绘制
_pageIndex = 0;
backElasticEffect();
}
}
/*
* 伪装吐出新数据
* */
Future<List> mokeHttpRequest() async {
if(widget.requestApi is Function){
final listObj = await widget.requestApi({'pageIndex':_pageIndex});
_pageIndex = listObj['pageIndex'];
_pageTotal = listObj['total'];
return listObj['list'];
}else {
return Future.delayed(Duration(seconds: 2), () {
return [];
});
}
}
/*
* 下拉加载的事件清空之前list内容取前X个
* 其实就是列表重置
* */
Future<Null> _handleRefresh() async {
List newEntries = await mokeHttpRequest();
setState(() {
items.clear();
items.addAll(newEntries);
isLoading = false;
_hasMore = true;
return null;
});
}
/*
* 加载中的提示
* */
Widget _buildLoadText() {
return Container(child: Padding(
padding: const EdgeInsets.all(18.0),
child: Center(
child: Text("数据没有更多了!!!"),
),
));
}
/*
* 上提加载loading的widget,如果数据到达极限,显示没有更多
* */
Widget _buildProgressIndicator() {
if(_hasMore){
return new Padding(
padding: const EdgeInsets.all(8.0),
child: new Center(
child:Column(
children: <Widget>[
new Opacity(
opacity: isLoading ? 1.0 : 0.0,
child: new CircularProgressIndicator(valueColor: AlwaysStoppedAnimation(Colors.blue)),
),
SizedBox(height:20.0),
Text('稍等片刻更精彩...',style: TextStyle(fontSize: 14.0),)
],)
//child:
),
);
}else {
return _buildLoadText();
}
}
@override
void dispose() {
super.dispose();
_scrollController.dispose();
}
@override
Widget build(BuildContext context) {
return new RefreshIndicator(
child:ListView.builder(
itemCount: items.length + 1,
itemBuilder: (context, index) {
if(index == 0 && index != items.length){
return Container(height:0);
}
if (index == items.length) {
//return _buildLoadText();
return _buildProgressIndicator();
} else {
//print('itemsitemsitemsitems:${items[index].title}');
//return ListTile(title: Text("Index${index}:${items[index].title}"));
if (widget.renderItem is Function) {
return widget.renderItem(index,items[index]);
}
//return makeCard(index,items[index]);
}
},
controller: _scrollController,
),
onRefresh: _handleRefresh,
);
}
}

View File

@ -0,0 +1,178 @@
/**
* Created with Android Studio.
* User: 一晟
* Date: 2019/1/4
* Time: 上午1:16
* email: zhu.yan@alibaba-inc.com
* tartget: FlatButton 的示例
*/
import 'package:flutter_web/material.dart';
import 'dart:math';
class ListRefresh extends StatefulWidget {
final renderItem;
final requestApi;
const ListRefresh([this.requestApi,this.renderItem]) : super();
@override
State<StatefulWidget> createState() => listRefresh();
}
class listRefresh extends State<ListRefresh> {
bool isLoading = false; // 是否正在请求数据中
bool _hasMore = true; // 是否还有更多数据可加载
int _pageIndex = 0; // 页面的索引
int _pageTotal = 0; // 页面的索引
List items = new List();
ScrollController _scrollController = new ScrollController();
@override
void initState() {
super.initState();
_getMoreData();
_scrollController.addListener(() {
// 如果下拉的当前位置到scroll的最下面
if (_scrollController.position.pixels == _scrollController.position.maxScrollExtent) {
_getMoreData();
}
});
}
/*
* 回弹效果
* */
backElasticEffect(){
// double edge = 50.0;
// double offsetFromBottom = _scrollController.position.maxScrollExtent - _scrollController.position.pixels;
// if (offsetFromBottom < edge) { // 添加一个动画没有更多数据的时候 ListView 向下移动覆盖正在加载更多数据的标志
// _scrollController.animateTo(
// _scrollController.offset - (edge -offsetFromBottom),
// duration: new Duration(milliseconds: 1000),
// curve: Curves.easeOut);
// }
}
/*
* list探底执行的具体事件
* */
Future _getMoreData() async {
if (!isLoading && _hasMore) { // 如果上一次异步请求数据完成 同时有数据可以加载
setState(() => isLoading = true);
//if(_hasMore){ // 还有数据可以拉新
List newEntries = await mokeHttpRequest();
//if (newEntries.isEmpty) {
_hasMore = (_pageIndex <= _pageTotal);
setState(() {
items.addAll(newEntries);
isLoading = false;
});
backElasticEffect();
}else if (!isLoading && !_hasMore){ // 这样判断,减少以后的绘制
_pageIndex = 0;
backElasticEffect();
}
}
/*
* 伪装吐出新数据
* */
Future<List> mokeHttpRequest() async {
if(widget.requestApi is Function){
final listObj = await widget.requestApi({'pageIndex':_pageIndex});
_pageIndex = listObj['pageIndex'];
_pageTotal = listObj['total'];
return listObj['list'];
}else {
return Future.delayed(Duration(seconds: 2), () {
return [];
});
}
}
/*
* 下拉加载的事件清空之前list内容取前X个
* 其实就是列表重置
* */
Future<Null> _handleRefresh() async {
List newEntries = await mokeHttpRequest();
setState(() {
items.clear();
items.addAll(newEntries);
isLoading = false;
_hasMore = true;
return null;
});
}
/*
* 加载中的提示
* */
Widget _buildLoadText() {
return Container(child: Padding(
padding: const EdgeInsets.all(18.0),
child: Center(
child: Text("数据没有更多了!!!"),
),
));
}
/*
* 上提加载loading的widget,如果数据到达极限,显示没有更多
* */
Widget _buildProgressIndicator() {
if(_hasMore){
return new Padding(
padding: const EdgeInsets.all(8.0),
child: new Center(
child:Column(
children: <Widget>[
new Opacity(
opacity: isLoading ? 1.0 : 0.0,
child: new CircularProgressIndicator(valueColor: AlwaysStoppedAnimation(Colors.blue)),
),
SizedBox(height:20.0),
Text('稍等片刻更精彩...',style: TextStyle(fontSize: 14.0),)
],)
//child:
),
);
}else {
return _buildLoadText();
}
}
@override
void dispose() {
super.dispose();
_scrollController.dispose();
}
@override
Widget build(BuildContext context) {
return new RefreshIndicator(
child:ListView.builder(
itemCount: items.length + 1,
itemBuilder: (context, index) {
if(index == 0 && index != items.length){
return Container(height:0);
}
if (index == items.length) {
//return _buildLoadText();
return _buildProgressIndicator();
} else {
//print('itemsitemsitemsitems:${items[index].title}');
//return ListTile(title: Text("Index${index}:${items[index].title}"));
if (widget.renderItem is Function) {
return widget.renderItem(index,items[index]);
}
//return makeCard(index,items[index]);
}
},
controller: _scrollController,
),
onRefresh: _handleRefresh,
);
}
}

View File

@ -0,0 +1,178 @@
/**
* Created with Android Studio.
* User: 一晟
* Date: 2019/1/4
* Time: 上午1:16
* email: zhu.yan@alibaba-inc.com
* tartget: FlatButton 的示例
*/
import 'package:flutter_web/material.dart';
import 'dart:math';
class ListRefresh extends StatefulWidget {
final renderItem;
final requestApi;
const ListRefresh([this.requestApi,this.renderItem]) : super();
@override
State<StatefulWidget> createState() => listRefresh();
}
class listRefresh extends State<ListRefresh> {
bool isLoading = false; // 是否正在请求数据中
bool _hasMore = true; // 是否还有更多数据可加载
int _pageIndex = 0; // 页面的索引
int _pageTotal = 0; // 页面的索引
List items = new List();
ScrollController _scrollController = new ScrollController();
@override
void initState() {
super.initState();
_getMoreData();
_scrollController.addListener(() {
// 如果下拉的当前位置到scroll的最下面
if (_scrollController.position.pixels == _scrollController.position.maxScrollExtent) {
_getMoreData();
}
});
}
/*
* 回弹效果
* */
backElasticEffect(){
// double edge = 50.0;
// double offsetFromBottom = _scrollController.position.maxScrollExtent - _scrollController.position.pixels;
// if (offsetFromBottom < edge) { // 添加一个动画没有更多数据的时候 ListView 向下移动覆盖正在加载更多数据的标志
// _scrollController.animateTo(
// _scrollController.offset - (edge -offsetFromBottom),
// duration: new Duration(milliseconds: 1000),
// curve: Curves.easeOut);
// }
}
/*
* list探底执行的具体事件
* */
Future _getMoreData() async {
if (!isLoading && _hasMore) { // 如果上一次异步请求数据完成 同时有数据可以加载
setState(() => isLoading = true);
//if(_hasMore){ // 还有数据可以拉新
List newEntries = await mokeHttpRequest();
//if (newEntries.isEmpty) {
_hasMore = (_pageIndex <= _pageTotal);
setState(() {
items.addAll(newEntries);
isLoading = false;
});
backElasticEffect();
}else if (!isLoading && !_hasMore){ // 这样判断,减少以后的绘制
_pageIndex = 0;
backElasticEffect();
}
}
/*
* 伪装吐出新数据
* */
Future<List> mokeHttpRequest() async {
if(widget.requestApi is Function){
final listObj = await widget.requestApi({'pageIndex':_pageIndex});
_pageIndex = listObj['pageIndex'];
_pageTotal = listObj['total'];
return listObj['list'];
}else {
return Future.delayed(Duration(seconds: 2), () {
return [];
});
}
}
/*
* 下拉加载的事件清空之前list内容取前X个
* 其实就是列表重置
* */
Future<Null> _handleRefresh() async {
List newEntries = await mokeHttpRequest();
setState(() {
items.clear();
items.addAll(newEntries);
isLoading = false;
_hasMore = true;
return null;
});
}
/*
* 加载中的提示
* */
Widget _buildLoadText() {
return Container(child: Padding(
padding: const EdgeInsets.all(18.0),
child: Center(
child: Text("数据没有更多了!!!"),
),
));
}
/*
* 上提加载loading的widget,如果数据到达极限,显示没有更多
* */
Widget _buildProgressIndicator() {
if(_hasMore){
return new Padding(
padding: const EdgeInsets.all(8.0),
child: new Center(
child:Column(
children: <Widget>[
new Opacity(
opacity: isLoading ? 1.0 : 0.0,
child: new CircularProgressIndicator(valueColor: AlwaysStoppedAnimation(Colors.blue)),
),
SizedBox(height:20.0),
Text('稍等片刻更精彩...',style: TextStyle(fontSize: 14.0),)
],)
//child:
),
);
}else {
return _buildLoadText();
}
}
@override
void dispose() {
super.dispose();
_scrollController.dispose();
}
@override
Widget build(BuildContext context) {
return new RefreshIndicator(
child:ListView.builder(
itemCount: items.length + 1,
itemBuilder: (context, index) {
if(index == 0 && index != items.length){
return Container(height:0);
}
if (index == items.length) {
//return _buildLoadText();
return _buildProgressIndicator();
} else {
//print('itemsitemsitemsitems:${items[index].title}');
//return ListTile(title: Text("Index${index}:${items[index].title}"));
if (widget.renderItem is Function) {
return widget.renderItem(index,items[index]);
}
//return makeCard(index,items[index]);
}
},
controller: _scrollController,
),
onRefresh: _handleRefresh,
);
}
}

178
lib-cp/ListRefresh.dart Normal file
View File

@ -0,0 +1,178 @@
/**
* Created with Android Studio.
* User: 一晟
* Date: 2019/1/4
* Time: 上午1:16
* email: zhu.yan@alibaba-inc.com
* tartget: FlatButton 的示例
*/
import 'package:flutter_web/material.dart';
import 'dart:math';
class ListRefresh extends StatefulWidget {
final renderItem;
final requestApi;
const ListRefresh([this.requestApi,this.renderItem]) : super();
@override
State<StatefulWidget> createState() => listRefresh();
}
class listRefresh extends State<ListRefresh> {
bool isLoading = false; // 是否正在请求数据中
bool _hasMore = true; // 是否还有更多数据可加载
int _pageIndex = 0; // 页面的索引
int _pageTotal = 0; // 页面的索引
List items = new List();
ScrollController _scrollController = new ScrollController();
@override
void initState() {
super.initState();
_getMoreData();
_scrollController.addListener(() {
// 如果下拉的当前位置到scroll的最下面
if (_scrollController.position.pixels == _scrollController.position.maxScrollExtent) {
_getMoreData();
}
});
}
/*
* 回弹效果
* */
backElasticEffect(){
// double edge = 50.0;
// double offsetFromBottom = _scrollController.position.maxScrollExtent - _scrollController.position.pixels;
// if (offsetFromBottom < edge) { // 添加一个动画没有更多数据的时候 ListView 向下移动覆盖正在加载更多数据的标志
// _scrollController.animateTo(
// _scrollController.offset - (edge -offsetFromBottom),
// duration: new Duration(milliseconds: 1000),
// curve: Curves.easeOut);
// }
}
/*
* list探底执行的具体事件
* */
Future _getMoreData() async {
if (!isLoading && _hasMore) { // 如果上一次异步请求数据完成 同时有数据可以加载
setState(() => isLoading = true);
//if(_hasMore){ // 还有数据可以拉新
List newEntries = await mokeHttpRequest();
//if (newEntries.isEmpty) {
_hasMore = (_pageIndex <= _pageTotal);
setState(() {
items.addAll(newEntries);
isLoading = false;
});
backElasticEffect();
}else if (!isLoading && !_hasMore){ // 这样判断,减少以后的绘制
_pageIndex = 0;
backElasticEffect();
}
}
/*
* 伪装吐出新数据
* */
Future<List> mokeHttpRequest() async {
if(widget.requestApi is Function){
final listObj = await widget.requestApi({'pageIndex':_pageIndex});
_pageIndex = listObj['pageIndex'];
_pageTotal = listObj['total'];
return listObj['list'];
}else {
return Future.delayed(Duration(seconds: 2), () {
return [];
});
}
}
/*
* 下拉加载的事件清空之前list内容取前X个
* 其实就是列表重置
* */
Future<Null> _handleRefresh() async {
List newEntries = await mokeHttpRequest();
setState(() {
items.clear();
items.addAll(newEntries);
isLoading = false;
_hasMore = true;
return null;
});
}
/*
* 加载中的提示
* */
Widget _buildLoadText() {
return Container(child: Padding(
padding: const EdgeInsets.all(18.0),
child: Center(
child: Text("数据没有更多了!!!"),
),
));
}
/*
* 上提加载loading的widget,如果数据到达极限,显示没有更多
* */
Widget _buildProgressIndicator() {
if(_hasMore){
return new Padding(
padding: const EdgeInsets.all(8.0),
child: new Center(
child:Column(
children: <Widget>[
new Opacity(
opacity: isLoading ? 1.0 : 0.0,
child: new CircularProgressIndicator(valueColor: AlwaysStoppedAnimation(Colors.blue)),
),
SizedBox(height:20.0),
Text('稍等片刻更精彩...',style: TextStyle(fontSize: 14.0),)
],)
//child:
),
);
}else {
return _buildLoadText();
}
}
@override
void dispose() {
super.dispose();
_scrollController.dispose();
}
@override
Widget build(BuildContext context) {
return new RefreshIndicator(
child:ListView.builder(
itemCount: items.length + 1,
itemBuilder: (context, index) {
if(index == 0 && index != items.length){
return Container(height:0);
}
if (index == items.length) {
//return _buildLoadText();
return _buildProgressIndicator();
} else {
//print('itemsitemsitemsitems:${items[index].title}');
//return ListTile(title: Text("Index${index}:${items[index].title}"));
if (widget.renderItem is Function) {
return widget.renderItem(index,items[index]);
}
//return makeCard(index,items[index]);
}
},
controller: _scrollController,
),
onRefresh: _handleRefresh,
);
}
}

View File

@ -0,0 +1,63 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter_web/material.dart';
import './homeBanner.dart';
import '../model/story.dart';
import 'package:url_launcher/url_launcher.dart';
class Pagination extends StatelessWidget {
static const String routeName = '/material/page-selector';
static final List<Icon> icons = <Icon>[
const Icon(Icons.event, semanticLabel: 'Event'),
const Icon(Icons.home, semanticLabel: 'Home'),
const Icon(Icons.android, semanticLabel: 'Android'),
const Icon(Icons.alarm, semanticLabel: 'Alarm'),
const Icon(Icons.face, semanticLabel: 'Face'),
const Icon(Icons.language, semanticLabel: 'Language'),
];
List<StoryModel> bannerStories = [];
List<dynamic> arr = [
{'image': 'https://img.alicdn.com/tfs/TB1W4hMAwHqK1RjSZJnXXbNLpXa-519-260.jpg', 'type': 0, 'id': 9695909, 'url': 'https://www.zhihu.com/question/294145797/answer/551162834', 'title': '为什么阿里巴巴、腾讯和 Google 之类的企业都在使用 Flutter 开发 App'},
{'image': 'https://img.alicdn.com/tfs/TB1XmFIApzqK1RjSZSgXXcpAVXa-720-338.jpg', 'type': 0, 'id': 9695859, 'url': 'https://zhuanlan.zhihu.com/p/51696594', 'title': 'Flutter 1.0 正式发布: Google 的便携 UI 工具包'},
{'image': 'https://img.alicdn.com/tfs/TB1mClCABLoK1RjSZFuXXXn0XXa-600-362.jpg', 'type': 0, 'id': 96956491409, 'url':'https://zhuanlan.zhihu.com/p/53497167','title': 'Flutter 示范应用现已开源 — 万物起源(The History of Everything)'},
{'image': 'https://img.alicdn.com/tfs/TB1fXxIAAvoK1RjSZFNXXcxMVXa-600-362.jpg', 'type': 0, 'id': 9695816, 'url': 'https://mp.weixin.qq.com/s?__biz=MzAwODY4OTk2Mg==&mid=2652048101&idx=1&sn=20296088e4bd8ca33c5c9991167d9f7d&chksm=808caaa0b7fb23b65c0e5806209f8d86da6732f3a00a70353f3606018339518b0a8656f14dc5&mpshare=1&scene=2&srcid=0106SZapVysZdIS6Oc5AhNH6&from=timeline&ascene=2&devicetype=android-27&version=27000038&nettype=WIFI&abtest_cookie=BQABAAgACgALABMAFAAFAJ2GHgAjlx4AV5keAJuZHgCcmR4AAAA%3D&lang=zh_CN&pass_ticket=4K1%2FUpsxP4suPj2iubR17wbAP7r9LW9iYrPAC2dppTqv7j7JO5FWMXtcKeBRxueV&wx_header=1', 'title': 'Flutter 与 Material Design 双剑合璧,助您构建精美应用'}
];
void _launchURL(String url) async {
if (await canLaunch(url)) {
await launch(url);
} else {
throw 'Could not launch $url';
}
}
List<Widget> _PageSelector(BuildContext context) {
List<Widget> list = [];
/// super.initState();
arr.forEach((item) {
bannerStories.add(StoryModel.fromJson(item));
});
if (arr.length > 0) {
list.add(HomeBanner(bannerStories, (story) {
_launchURL('${story.url}');
}));
}
return list;
}
@override
Widget build(BuildContext context) {
return
Column(
//physics: AlwaysScrollableScrollPhysics(),
//padding: EdgeInsets.only(),
children: _PageSelector(context)
);
}
}

View File

@ -0,0 +1,63 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter_web/material.dart';
import './homeBanner.dart';
import '../model/story.dart';
import 'package:url_launcher/url_launcher.dart';
class Pagination extends StatelessWidget {
static const String routeName = '/material/page-selector';
static final List<Icon> icons = <Icon>[
const Icon(Icons.event, semanticLabel: 'Event'),
const Icon(Icons.home, semanticLabel: 'Home'),
const Icon(Icons.android, semanticLabel: 'Android'),
const Icon(Icons.alarm, semanticLabel: 'Alarm'),
const Icon(Icons.face, semanticLabel: 'Face'),
const Icon(Icons.language, semanticLabel: 'Language'),
];
List<StoryModel> bannerStories = [];
List<dynamic> arr = [
{'image': 'https://img.alicdn.com/tfs/TB1W4hMAwHqK1RjSZJnXXbNLpXa-519-260.jpg', 'type': 0, 'id': 9695909, 'url': 'https://www.zhihu.com/question/294145797/answer/551162834', 'title': '为什么阿里巴巴、腾讯和 Google 之类的企业都在使用 Flutter 开发 App'},
{'image': 'https://img.alicdn.com/tfs/TB1XmFIApzqK1RjSZSgXXcpAVXa-720-338.jpg', 'type': 0, 'id': 9695859, 'url': 'https://zhuanlan.zhihu.com/p/51696594', 'title': 'Flutter 1.0 正式发布: Google 的便携 UI 工具包'},
{'image': 'https://img.alicdn.com/tfs/TB1mClCABLoK1RjSZFuXXXn0XXa-600-362.jpg', 'type': 0, 'id': 96956491409, 'url':'https://zhuanlan.zhihu.com/p/53497167','title': 'Flutter 示范应用现已开源 — 万物起源(The History of Everything)'},
{'image': 'https://img.alicdn.com/tfs/TB1fXxIAAvoK1RjSZFNXXcxMVXa-600-362.jpg', 'type': 0, 'id': 9695816, 'url': 'https://mp.weixin.qq.com/s?__biz=MzAwODY4OTk2Mg==&mid=2652048101&idx=1&sn=20296088e4bd8ca33c5c9991167d9f7d&chksm=808caaa0b7fb23b65c0e5806209f8d86da6732f3a00a70353f3606018339518b0a8656f14dc5&mpshare=1&scene=2&srcid=0106SZapVysZdIS6Oc5AhNH6&from=timeline&ascene=2&devicetype=android-27&version=27000038&nettype=WIFI&abtest_cookie=BQABAAgACgALABMAFAAFAJ2GHgAjlx4AV5keAJuZHgCcmR4AAAA%3D&lang=zh_CN&pass_ticket=4K1%2FUpsxP4suPj2iubR17wbAP7r9LW9iYrPAC2dppTqv7j7JO5FWMXtcKeBRxueV&wx_header=1', 'title': 'Flutter 与 Material Design 双剑合璧,助您构建精美应用'}
];
void _launchURL(String url) async {
if (await canLaunch(url)) {
await launch(url);
} else {
throw 'Could not launch $url';
}
}
List<Widget> _PageSelector(BuildContext context) {
List<Widget> list = [];
/// super.initState();
arr.forEach((item) {
bannerStories.add(StoryModel.fromJson(item));
});
if (arr.length > 0) {
list.add(HomeBanner(bannerStories, (story) {
_launchURL('${story.url}');
}));
}
return list;
}
@override
Widget build(BuildContext context) {
return
Column(
//physics: AlwaysScrollableScrollPhysics(),
//padding: EdgeInsets.only(),
children: _PageSelector(context)
);
}
}

View File

@ -0,0 +1,63 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter_web/material.dart';
import './homeBanner.dart';
import '../model/story.dart';
import 'package:url_launcher/url_launcher.dart';
class Pagination extends StatelessWidget {
static const String routeName = '/material/page-selector';
static final List<Icon> icons = <Icon>[
const Icon(Icons.event, semanticLabel: 'Event'),
const Icon(Icons.home, semanticLabel: 'Home'),
const Icon(Icons.android, semanticLabel: 'Android'),
const Icon(Icons.alarm, semanticLabel: 'Alarm'),
const Icon(Icons.face, semanticLabel: 'Face'),
const Icon(Icons.language, semanticLabel: 'Language'),
];
List<StoryModel> bannerStories = [];
List<dynamic> arr = [
{'image': 'https://img.alicdn.com/tfs/TB1W4hMAwHqK1RjSZJnXXbNLpXa-519-260.jpg', 'type': 0, 'id': 9695909, 'url': 'https://www.zhihu.com/question/294145797/answer/551162834', 'title': '为什么阿里巴巴、腾讯和 Google 之类的企业都在使用 Flutter 开发 App'},
{'image': 'https://img.alicdn.com/tfs/TB1XmFIApzqK1RjSZSgXXcpAVXa-720-338.jpg', 'type': 0, 'id': 9695859, 'url': 'https://zhuanlan.zhihu.com/p/51696594', 'title': 'Flutter 1.0 正式发布: Google 的便携 UI 工具包'},
{'image': 'https://img.alicdn.com/tfs/TB1mClCABLoK1RjSZFuXXXn0XXa-600-362.jpg', 'type': 0, 'id': 96956491409, 'url':'https://zhuanlan.zhihu.com/p/53497167','title': 'Flutter 示范应用现已开源 — 万物起源(The History of Everything)'},
{'image': 'https://img.alicdn.com/tfs/TB1fXxIAAvoK1RjSZFNXXcxMVXa-600-362.jpg', 'type': 0, 'id': 9695816, 'url': 'https://mp.weixin.qq.com/s?__biz=MzAwODY4OTk2Mg==&mid=2652048101&idx=1&sn=20296088e4bd8ca33c5c9991167d9f7d&chksm=808caaa0b7fb23b65c0e5806209f8d86da6732f3a00a70353f3606018339518b0a8656f14dc5&mpshare=1&scene=2&srcid=0106SZapVysZdIS6Oc5AhNH6&from=timeline&ascene=2&devicetype=android-27&version=27000038&nettype=WIFI&abtest_cookie=BQABAAgACgALABMAFAAFAJ2GHgAjlx4AV5keAJuZHgCcmR4AAAA%3D&lang=zh_CN&pass_ticket=4K1%2FUpsxP4suPj2iubR17wbAP7r9LW9iYrPAC2dppTqv7j7JO5FWMXtcKeBRxueV&wx_header=1', 'title': 'Flutter 与 Material Design 双剑合璧,助您构建精美应用'}
];
void _launchURL(String url) async {
if (await canLaunch(url)) {
await launch(url);
} else {
throw 'Could not launch $url';
}
}
List<Widget> _PageSelector(BuildContext context) {
List<Widget> list = [];
/// super.initState();
arr.forEach((item) {
bannerStories.add(StoryModel.fromJson(item));
});
if (arr.length > 0) {
list.add(HomeBanner(bannerStories, (story) {
_launchURL('${story.url}');
}));
}
return list;
}
@override
Widget build(BuildContext context) {
return
Column(
//physics: AlwaysScrollableScrollPhysics(),
//padding: EdgeInsets.only(),
children: _PageSelector(context)
);
}
}

63
lib-cp/Pagination.dart Normal file
View File

@ -0,0 +1,63 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter_web/material.dart';
import './homeBanner.dart';
import '../model/story.dart';
import 'package:url_launcher/url_launcher.dart';
class Pagination extends StatelessWidget {
static const String routeName = '/material/page-selector';
static final List<Icon> icons = <Icon>[
const Icon(Icons.event, semanticLabel: 'Event'),
const Icon(Icons.home, semanticLabel: 'Home'),
const Icon(Icons.android, semanticLabel: 'Android'),
const Icon(Icons.alarm, semanticLabel: 'Alarm'),
const Icon(Icons.face, semanticLabel: 'Face'),
const Icon(Icons.language, semanticLabel: 'Language'),
];
List<StoryModel> bannerStories = [];
List<dynamic> arr = [
{'image': 'https://img.alicdn.com/tfs/TB1W4hMAwHqK1RjSZJnXXbNLpXa-519-260.jpg', 'type': 0, 'id': 9695909, 'url': 'https://www.zhihu.com/question/294145797/answer/551162834', 'title': '为什么阿里巴巴、腾讯和 Google 之类的企业都在使用 Flutter 开发 App'},
{'image': 'https://img.alicdn.com/tfs/TB1XmFIApzqK1RjSZSgXXcpAVXa-720-338.jpg', 'type': 0, 'id': 9695859, 'url': 'https://zhuanlan.zhihu.com/p/51696594', 'title': 'Flutter 1.0 正式发布: Google 的便携 UI 工具包'},
{'image': 'https://img.alicdn.com/tfs/TB1mClCABLoK1RjSZFuXXXn0XXa-600-362.jpg', 'type': 0, 'id': 96956491409, 'url':'https://zhuanlan.zhihu.com/p/53497167','title': 'Flutter 示范应用现已开源 — 万物起源(The History of Everything)'},
{'image': 'https://img.alicdn.com/tfs/TB1fXxIAAvoK1RjSZFNXXcxMVXa-600-362.jpg', 'type': 0, 'id': 9695816, 'url': 'https://mp.weixin.qq.com/s?__biz=MzAwODY4OTk2Mg==&mid=2652048101&idx=1&sn=20296088e4bd8ca33c5c9991167d9f7d&chksm=808caaa0b7fb23b65c0e5806209f8d86da6732f3a00a70353f3606018339518b0a8656f14dc5&mpshare=1&scene=2&srcid=0106SZapVysZdIS6Oc5AhNH6&from=timeline&ascene=2&devicetype=android-27&version=27000038&nettype=WIFI&abtest_cookie=BQABAAgACgALABMAFAAFAJ2GHgAjlx4AV5keAJuZHgCcmR4AAAA%3D&lang=zh_CN&pass_ticket=4K1%2FUpsxP4suPj2iubR17wbAP7r9LW9iYrPAC2dppTqv7j7JO5FWMXtcKeBRxueV&wx_header=1', 'title': 'Flutter 与 Material Design 双剑合璧,助您构建精美应用'}
];
void _launchURL(String url) async {
if (await canLaunch(url)) {
await launch(url);
} else {
throw 'Could not launch $url';
}
}
List<Widget> _PageSelector(BuildContext context) {
List<Widget> list = [];
/// super.initState();
arr.forEach((item) {
bannerStories.add(StoryModel.fromJson(item));
});
if (arr.length > 0) {
list.add(HomeBanner(bannerStories, (story) {
_launchURL('${story.url}');
}));
}
return list;
}
@override
Widget build(BuildContext context) {
return
Column(
//physics: AlwaysScrollableScrollPhysics(),
//padding: EdgeInsets.only(),
children: _PageSelector(context)
);
}
}

View File

@ -0,0 +1,399 @@
import 'dart:async';
import 'package:flutter_web/material.dart';
import 'package:meta/meta.dart';
typedef String FormFieldFormatter<T>(T v);
typedef bool MaterialSearchFilter<T>(T v, String c);
typedef int MaterialSearchSort<T>(T a, T b, String c);
typedef Future<List<MaterialSearchResult>> MaterialResultsFinder(String c);
typedef void OnSubmit(String value);
///搜索结果内容显示面板
class MaterialSearchResult<T> extends StatelessWidget {
const MaterialSearchResult({
Key key,
this.value,
this.text,
this.icon,
this.onTap
}) : super(key: key);
final T value;
final VoidCallback onTap;
final String text;
final IconData icon;
@override
Widget build(BuildContext context) {
return new InkWell(
onTap: this.onTap,
child: new Container(
height: 64.0,
padding: EdgeInsets.fromLTRB(20.0, 0.0, 20.0, 10.0),
child: new Row(
children: <Widget>[
new Container(width: 30.0, child: new Icon(icon)) ?? null,
new Expanded(child: new Text(text, style: Theme.of(context).textTheme.subhead)),
new Text(text, style: Theme.of(context).textTheme.subhead)
],
),
),
);
}
}
class MaterialSearch<T> extends StatefulWidget {
MaterialSearch({
Key key,
this.placeholder,
this.results,
this.getResults,
this.filter,
this.sort,
this.limit: 10,
this.onSelect,
this.onSubmit,
this.barBackgroundColor = Colors.white,
this.iconColor = Colors.black,
this.leading,
}) : assert(() {
if (results == null && getResults == null ||
results != null && getResults != null) {
throw new AssertionError(
'Either provide a function to get the results, or the results.');
}
return true;
}()),
super(key: key);
final String placeholder;
final List<MaterialSearchResult<T>> results;
final MaterialResultsFinder getResults;
final MaterialSearchFilter<T> filter;
final MaterialSearchSort<T> sort;
final int limit;
final ValueChanged<T> onSelect;
final OnSubmit onSubmit;
final Color barBackgroundColor;
final Color iconColor;
final Widget leading;
@override
_MaterialSearchState<T> createState() => new _MaterialSearchState<T>();
}
class _MaterialSearchState<T> extends State<MaterialSearch> {
bool _loading = false;
List<MaterialSearchResult<T>> _results = [];
String _criteria = '';
TextEditingController _controller = new TextEditingController();
_filter(dynamic v, String c) {
return v
.toString()
.toLowerCase()
.trim()
.contains(new RegExp(r'' + c.toLowerCase().trim() + ''));
}
@override
void initState() {
super.initState();
if (widget.getResults != null) {
_getResultsDebounced();
}
_controller.addListener(() {
setState(() {
_criteria = _controller.value.text;
if (widget.getResults != null) {
_getResultsDebounced();
}
});
});
}
Timer _resultsTimer;
Future _getResultsDebounced() async {
if (_results.length == 0) {
setState(() {
_loading = true;
});
}
if (_resultsTimer != null && _resultsTimer.isActive) {
_resultsTimer.cancel();
}
_resultsTimer = new Timer(new Duration(milliseconds: 400), () async {
if (!mounted) {
return;
}
setState(() {
_loading = true;
});
//TODO: debounce widget.results too
var results = await widget.getResults(_criteria);
if (!mounted) {
return;
}
if (results != null) {
setState(() {
_loading = false;
_results = results;
});
}
});
}
@override
void dispose() {
super.dispose();
_resultsTimer?.cancel();
}
Widget buildBody(List results) {
if (_loading) {
return new Center(
child: new Padding(
padding: const EdgeInsets.only(top: 50.0),
child: new CircularProgressIndicator()
)
);
}
if (results.isNotEmpty) {
var content = new SingleChildScrollView(
child: new Column(
children: results
)
);
return content;
}
return Center(child: Text("暂无数据"));
}
@override
Widget build(BuildContext context) {
var results =
(widget.results ?? _results).where((MaterialSearchResult result) {
if (widget.filter != null) {
return widget.filter(result.value, _criteria);
}
//only apply default filter if used the `results` option
//because getResults may already have applied some filter if `filter` option was omited.
else if (widget.results != null) {
return _filter(result.value, _criteria);
}
return true;
}).toList();
if (widget.sort != null) {
results.sort((a, b) => widget.sort(a.value, b.value, _criteria));
}
results = results.take(widget.limit).toList();
IconThemeData iconTheme =
Theme.of(context).iconTheme.copyWith(color: widget.iconColor);
return new Scaffold(
appBar: new AppBar(
leading: widget.leading,
backgroundColor: widget.barBackgroundColor,
iconTheme: iconTheme,
title: new TextField(
controller: _controller,
autofocus: true,
decoration:
new InputDecoration.collapsed(hintText: widget.placeholder),
style: Theme.of(context).textTheme.title,
onSubmitted: (String value) {
if (widget.onSubmit != null) {
widget.onSubmit(value);
}
},
),
actions: _criteria.length == 0
? []
: [
new IconButton(
icon: new Icon(Icons.clear),
onPressed: () {
setState(() {
_controller.text = _criteria = '';
});
}),
],
),
body: buildBody(results),
);
}
}
class _MaterialSearchPageRoute<T> extends MaterialPageRoute<T> {
_MaterialSearchPageRoute({
@required WidgetBuilder builder,
RouteSettings settings: const RouteSettings(),
maintainState: true,
bool fullscreenDialog: false,
}) : assert(builder != null),
super(
builder: builder,
settings: settings,
maintainState: maintainState,
fullscreenDialog: fullscreenDialog);
}
class MaterialSearchInput<T> extends StatefulWidget {
MaterialSearchInput({
Key key,
this.onSaved,
this.validator,
this.autovalidate,
this.placeholder,
this.formatter,
this.results,
this.getResults,
this.filter,
this.sort,
this.onSelect,
});
final FormFieldSetter<T> onSaved;
final FormFieldValidator<T> validator;
final bool autovalidate;
final String placeholder;
final FormFieldFormatter<T> formatter;
final List<MaterialSearchResult<T>> results;
final MaterialResultsFinder getResults;
final MaterialSearchFilter<T> filter;
final MaterialSearchSort<T> sort;
final ValueChanged<T> onSelect;
@override
_MaterialSearchInputState<T> createState() =>
new _MaterialSearchInputState<T>();
}
class _MaterialSearchInputState<T> extends State<MaterialSearchInput<T>> {
GlobalKey<FormFieldState<T>> _formFieldKey =
new GlobalKey<FormFieldState<T>>();
_buildMaterialSearchPage(BuildContext context) {
return new _MaterialSearchPageRoute<T>(
settings: new RouteSettings(
name: 'material_search',
isInitialRoute: false,
),
builder: (BuildContext context) {
return new Material(
child: new MaterialSearch<T>(
placeholder: widget.placeholder,
results: widget.results,
getResults: widget.getResults,
filter: widget.filter,
sort: widget.sort,
onSelect: (dynamic value) => Navigator.of(context).pop(value),
),
);
});
}
_showMaterialSearch(BuildContext context) {
Navigator.of(context)
.push(_buildMaterialSearchPage(context))
.then((dynamic value) {
if (value != null) {
_formFieldKey.currentState.didChange(value);
widget.onSelect(value);
}
});
}
bool get autovalidate {
return widget.autovalidate ??
Form.of(context)?.widget?.autovalidate ??
false;
}
bool _isEmpty(field) {
return field.value == null;
}
Widget build(BuildContext context) {
final TextStyle valueStyle = Theme.of(context).textTheme.subhead;
return new InkWell(
onTap: () => _showMaterialSearch(context),
child: new FormField<T>(
key: _formFieldKey,
validator: widget.validator,
onSaved: widget.onSaved,
autovalidate: autovalidate,
builder: (FormFieldState<T> field) {
return new InputDecorator(
isEmpty: _isEmpty(field),
decoration: new InputDecoration(
labelText: widget.placeholder,
border: InputBorder.none,
errorText: field.errorText,
),
child: _isEmpty(field)
? null
: new Text(
widget.formatter != null
? widget.formatter(field.value)
: field.value.toString(),
style: valueStyle),
);
},
),
);
}
}
///搜索框
class SearchInput extends StatelessWidget {
final getResults;
final ValueChanged<String> onSubmitted;
final VoidCallback onSubmitPressed;
SearchInput(this.getResults, this.onSubmitted, this.onSubmitPressed);
@override
Widget build(BuildContext context) {
return new Container(
height: 40.0,
decoration: BoxDecoration(
color: Theme.of(context).backgroundColor,
borderRadius: BorderRadius.circular(4.0)),
child: new Row(
children: <Widget>[
new Padding(
padding: new EdgeInsets.only(right: 10.0, top: 3.0, left: 10.0),
child: new Icon(Icons.search,
size: 24.0, color: Theme.of(context).accentColor),
),
new Expanded(
child: new MaterialSearchInput(
placeholder: '搜索 flutter 组件',
getResults: getResults,
),
),
],
),
);
}
}
// wigdet干掉.=> componets

View File

@ -0,0 +1,399 @@
import 'dart:async';
import 'package:flutter_web/material.dart';
import 'package:meta/meta.dart';
typedef String FormFieldFormatter<T>(T v);
typedef bool MaterialSearchFilter<T>(T v, String c);
typedef int MaterialSearchSort<T>(T a, T b, String c);
typedef Future<List<MaterialSearchResult>> MaterialResultsFinder(String c);
typedef void OnSubmit(String value);
///搜索结果内容显示面板
class MaterialSearchResult<T> extends StatelessWidget {
const MaterialSearchResult({
Key key,
this.value,
this.text,
this.icon,
this.onTap
}) : super(key: key);
final T value;
final VoidCallback onTap;
final String text;
final IconData icon;
@override
Widget build(BuildContext context) {
return new InkWell(
onTap: this.onTap,
child: new Container(
height: 64.0,
padding: EdgeInsets.fromLTRB(20.0, 0.0, 20.0, 10.0),
child: new Row(
children: <Widget>[
new Container(width: 30.0, child: new Icon(icon)) ?? null,
new Expanded(child: new Text(text, style: Theme.of(context).textTheme.subhead)),
new Text(text, style: Theme.of(context).textTheme.subhead)
],
),
),
);
}
}
class MaterialSearch<T> extends StatefulWidget {
MaterialSearch({
Key key,
this.placeholder,
this.results,
this.getResults,
this.filter,
this.sort,
this.limit: 10,
this.onSelect,
this.onSubmit,
this.barBackgroundColor = Colors.white,
this.iconColor = Colors.black,
this.leading,
}) : assert(() {
if (results == null && getResults == null ||
results != null && getResults != null) {
throw new AssertionError(
'Either provide a function to get the results, or the results.');
}
return true;
}()),
super(key: key);
final String placeholder;
final List<MaterialSearchResult<T>> results;
final MaterialResultsFinder getResults;
final MaterialSearchFilter<T> filter;
final MaterialSearchSort<T> sort;
final int limit;
final ValueChanged<T> onSelect;
final OnSubmit onSubmit;
final Color barBackgroundColor;
final Color iconColor;
final Widget leading;
@override
_MaterialSearchState<T> createState() => new _MaterialSearchState<T>();
}
class _MaterialSearchState<T> extends State<MaterialSearch> {
bool _loading = false;
List<MaterialSearchResult<T>> _results = [];
String _criteria = '';
TextEditingController _controller = new TextEditingController();
_filter(dynamic v, String c) {
return v
.toString()
.toLowerCase()
.trim()
.contains(new RegExp(r'' + c.toLowerCase().trim() + ''));
}
@override
void initState() {
super.initState();
if (widget.getResults != null) {
_getResultsDebounced();
}
_controller.addListener(() {
setState(() {
_criteria = _controller.value.text;
if (widget.getResults != null) {
_getResultsDebounced();
}
});
});
}
Timer _resultsTimer;
Future _getResultsDebounced() async {
if (_results.length == 0) {
setState(() {
_loading = true;
});
}
if (_resultsTimer != null && _resultsTimer.isActive) {
_resultsTimer.cancel();
}
_resultsTimer = new Timer(new Duration(milliseconds: 400), () async {
if (!mounted) {
return;
}
setState(() {
_loading = true;
});
//TODO: debounce widget.results too
var results = await widget.getResults(_criteria);
if (!mounted) {
return;
}
if (results != null) {
setState(() {
_loading = false;
_results = results;
});
}
});
}
@override
void dispose() {
super.dispose();
_resultsTimer?.cancel();
}
Widget buildBody(List results) {
if (_loading) {
return new Center(
child: new Padding(
padding: const EdgeInsets.only(top: 50.0),
child: new CircularProgressIndicator()
)
);
}
if (results.isNotEmpty) {
var content = new SingleChildScrollView(
child: new Column(
children: results
)
);
return content;
}
return Center(child: Text("暂无数据"));
}
@override
Widget build(BuildContext context) {
var results =
(widget.results ?? _results).where((MaterialSearchResult result) {
if (widget.filter != null) {
return widget.filter(result.value, _criteria);
}
//only apply default filter if used the `results` option
//because getResults may already have applied some filter if `filter` option was omited.
else if (widget.results != null) {
return _filter(result.value, _criteria);
}
return true;
}).toList();
if (widget.sort != null) {
results.sort((a, b) => widget.sort(a.value, b.value, _criteria));
}
results = results.take(widget.limit).toList();
IconThemeData iconTheme =
Theme.of(context).iconTheme.copyWith(color: widget.iconColor);
return new Scaffold(
appBar: new AppBar(
leading: widget.leading,
backgroundColor: widget.barBackgroundColor,
iconTheme: iconTheme,
title: new TextField(
controller: _controller,
autofocus: true,
decoration:
new InputDecoration.collapsed(hintText: widget.placeholder),
style: Theme.of(context).textTheme.title,
onSubmitted: (String value) {
if (widget.onSubmit != null) {
widget.onSubmit(value);
}
},
),
actions: _criteria.length == 0
? []
: [
new IconButton(
icon: new Icon(Icons.clear),
onPressed: () {
setState(() {
_controller.text = _criteria = '';
});
}),
],
),
body: buildBody(results),
);
}
}
class _MaterialSearchPageRoute<T> extends MaterialPageRoute<T> {
_MaterialSearchPageRoute({
@required WidgetBuilder builder,
RouteSettings settings: const RouteSettings(),
maintainState: true,
bool fullscreenDialog: false,
}) : assert(builder != null),
super(
builder: builder,
settings: settings,
maintainState: maintainState,
fullscreenDialog: fullscreenDialog);
}
class MaterialSearchInput<T> extends StatefulWidget {
MaterialSearchInput({
Key key,
this.onSaved,
this.validator,
this.autovalidate,
this.placeholder,
this.formatter,
this.results,
this.getResults,
this.filter,
this.sort,
this.onSelect,
});
final FormFieldSetter<T> onSaved;
final FormFieldValidator<T> validator;
final bool autovalidate;
final String placeholder;
final FormFieldFormatter<T> formatter;
final List<MaterialSearchResult<T>> results;
final MaterialResultsFinder getResults;
final MaterialSearchFilter<T> filter;
final MaterialSearchSort<T> sort;
final ValueChanged<T> onSelect;
@override
_MaterialSearchInputState<T> createState() =>
new _MaterialSearchInputState<T>();
}
class _MaterialSearchInputState<T> extends State<MaterialSearchInput<T>> {
GlobalKey<FormFieldState<T>> _formFieldKey =
new GlobalKey<FormFieldState<T>>();
_buildMaterialSearchPage(BuildContext context) {
return new _MaterialSearchPageRoute<T>(
settings: new RouteSettings(
name: 'material_search',
isInitialRoute: false,
),
builder: (BuildContext context) {
return new Material(
child: new MaterialSearch<T>(
placeholder: widget.placeholder,
results: widget.results,
getResults: widget.getResults,
filter: widget.filter,
sort: widget.sort,
onSelect: (dynamic value) => Navigator.of(context).pop(value),
),
);
});
}
_showMaterialSearch(BuildContext context) {
Navigator.of(context)
.push(_buildMaterialSearchPage(context))
.then((dynamic value) {
if (value != null) {
_formFieldKey.currentState.didChange(value);
widget.onSelect(value);
}
});
}
bool get autovalidate {
return widget.autovalidate ??
Form.of(context)?.widget?.autovalidate ??
false;
}
bool _isEmpty(field) {
return field.value == null;
}
Widget build(BuildContext context) {
final TextStyle valueStyle = Theme.of(context).textTheme.subhead;
return new InkWell(
onTap: () => _showMaterialSearch(context),
child: new FormField<T>(
key: _formFieldKey,
validator: widget.validator,
onSaved: widget.onSaved,
autovalidate: autovalidate,
builder: (FormFieldState<T> field) {
return new InputDecorator(
isEmpty: _isEmpty(field),
decoration: new InputDecoration(
labelText: widget.placeholder,
border: InputBorder.none,
errorText: field.errorText,
),
child: _isEmpty(field)
? null
: new Text(
widget.formatter != null
? widget.formatter(field.value)
: field.value.toString(),
style: valueStyle),
);
},
),
);
}
}
///搜索框
class SearchInput extends StatelessWidget {
final getResults;
final ValueChanged<String> onSubmitted;
final VoidCallback onSubmitPressed;
SearchInput(this.getResults, this.onSubmitted, this.onSubmitPressed);
@override
Widget build(BuildContext context) {
return new Container(
height: 40.0,
decoration: BoxDecoration(
color: Theme.of(context).backgroundColor,
borderRadius: BorderRadius.circular(4.0)),
child: new Row(
children: <Widget>[
new Padding(
padding: new EdgeInsets.only(right: 10.0, top: 3.0, left: 10.0),
child: new Icon(Icons.search,
size: 24.0, color: Theme.of(context).accentColor),
),
new Expanded(
child: new MaterialSearchInput(
placeholder: '搜索 flutter 组件',
getResults: getResults,
),
),
],
),
);
}
}
// wigdet干掉.=> componets

View File

@ -0,0 +1,399 @@
import 'dart:async';
import 'package:flutter_web/material.dart';
import 'package:meta/meta.dart';
typedef String FormFieldFormatter<T>(T v);
typedef bool MaterialSearchFilter<T>(T v, String c);
typedef int MaterialSearchSort<T>(T a, T b, String c);
typedef Future<List<MaterialSearchResult>> MaterialResultsFinder(String c);
typedef void OnSubmit(String value);
///搜索结果内容显示面板
class MaterialSearchResult<T> extends StatelessWidget {
const MaterialSearchResult({
Key key,
this.value,
this.text,
this.icon,
this.onTap
}) : super(key: key);
final T value;
final VoidCallback onTap;
final String text;
final IconData icon;
@override
Widget build(BuildContext context) {
return new InkWell(
onTap: this.onTap,
child: new Container(
height: 64.0,
padding: EdgeInsets.fromLTRB(20.0, 0.0, 20.0, 10.0),
child: new Row(
children: <Widget>[
new Container(width: 30.0, child: new Icon(icon)) ?? null,
new Expanded(child: new Text(text, style: Theme.of(context).textTheme.subhead)),
new Text(text, style: Theme.of(context).textTheme.subhead)
],
),
),
);
}
}
class MaterialSearch<T> extends StatefulWidget {
MaterialSearch({
Key key,
this.placeholder,
this.results,
this.getResults,
this.filter,
this.sort,
this.limit: 10,
this.onSelect,
this.onSubmit,
this.barBackgroundColor = Colors.white,
this.iconColor = Colors.black,
this.leading,
}) : assert(() {
if (results == null && getResults == null ||
results != null && getResults != null) {
throw new AssertionError(
'Either provide a function to get the results, or the results.');
}
return true;
}()),
super(key: key);
final String placeholder;
final List<MaterialSearchResult<T>> results;
final MaterialResultsFinder getResults;
final MaterialSearchFilter<T> filter;
final MaterialSearchSort<T> sort;
final int limit;
final ValueChanged<T> onSelect;
final OnSubmit onSubmit;
final Color barBackgroundColor;
final Color iconColor;
final Widget leading;
@override
_MaterialSearchState<T> createState() => new _MaterialSearchState<T>();
}
class _MaterialSearchState<T> extends State<MaterialSearch> {
bool _loading = false;
List<MaterialSearchResult<T>> _results = [];
String _criteria = '';
TextEditingController _controller = new TextEditingController();
_filter(dynamic v, String c) {
return v
.toString()
.toLowerCase()
.trim()
.contains(new RegExp(r'' + c.toLowerCase().trim() + ''));
}
@override
void initState() {
super.initState();
if (widget.getResults != null) {
_getResultsDebounced();
}
_controller.addListener(() {
setState(() {
_criteria = _controller.value.text;
if (widget.getResults != null) {
_getResultsDebounced();
}
});
});
}
Timer _resultsTimer;
Future _getResultsDebounced() async {
if (_results.length == 0) {
setState(() {
_loading = true;
});
}
if (_resultsTimer != null && _resultsTimer.isActive) {
_resultsTimer.cancel();
}
_resultsTimer = new Timer(new Duration(milliseconds: 400), () async {
if (!mounted) {
return;
}
setState(() {
_loading = true;
});
//TODO: debounce widget.results too
var results = await widget.getResults(_criteria);
if (!mounted) {
return;
}
if (results != null) {
setState(() {
_loading = false;
_results = results;
});
}
});
}
@override
void dispose() {
super.dispose();
_resultsTimer?.cancel();
}
Widget buildBody(List results) {
if (_loading) {
return new Center(
child: new Padding(
padding: const EdgeInsets.only(top: 50.0),
child: new CircularProgressIndicator()
)
);
}
if (results.isNotEmpty) {
var content = new SingleChildScrollView(
child: new Column(
children: results
)
);
return content;
}
return Center(child: Text("暂无数据"));
}
@override
Widget build(BuildContext context) {
var results =
(widget.results ?? _results).where((MaterialSearchResult result) {
if (widget.filter != null) {
return widget.filter(result.value, _criteria);
}
//only apply default filter if used the `results` option
//because getResults may already have applied some filter if `filter` option was omited.
else if (widget.results != null) {
return _filter(result.value, _criteria);
}
return true;
}).toList();
if (widget.sort != null) {
results.sort((a, b) => widget.sort(a.value, b.value, _criteria));
}
results = results.take(widget.limit).toList();
IconThemeData iconTheme =
Theme.of(context).iconTheme.copyWith(color: widget.iconColor);
return new Scaffold(
appBar: new AppBar(
leading: widget.leading,
backgroundColor: widget.barBackgroundColor,
iconTheme: iconTheme,
title: new TextField(
controller: _controller,
autofocus: true,
decoration:
new InputDecoration.collapsed(hintText: widget.placeholder),
style: Theme.of(context).textTheme.title,
onSubmitted: (String value) {
if (widget.onSubmit != null) {
widget.onSubmit(value);
}
},
),
actions: _criteria.length == 0
? []
: [
new IconButton(
icon: new Icon(Icons.clear),
onPressed: () {
setState(() {
_controller.text = _criteria = '';
});
}),
],
),
body: buildBody(results),
);
}
}
class _MaterialSearchPageRoute<T> extends MaterialPageRoute<T> {
_MaterialSearchPageRoute({
@required WidgetBuilder builder,
RouteSettings settings: const RouteSettings(),
maintainState: true,
bool fullscreenDialog: false,
}) : assert(builder != null),
super(
builder: builder,
settings: settings,
maintainState: maintainState,
fullscreenDialog: fullscreenDialog);
}
class MaterialSearchInput<T> extends StatefulWidget {
MaterialSearchInput({
Key key,
this.onSaved,
this.validator,
this.autovalidate,
this.placeholder,
this.formatter,
this.results,
this.getResults,
this.filter,
this.sort,
this.onSelect,
});
final FormFieldSetter<T> onSaved;
final FormFieldValidator<T> validator;
final bool autovalidate;
final String placeholder;
final FormFieldFormatter<T> formatter;
final List<MaterialSearchResult<T>> results;
final MaterialResultsFinder getResults;
final MaterialSearchFilter<T> filter;
final MaterialSearchSort<T> sort;
final ValueChanged<T> onSelect;
@override
_MaterialSearchInputState<T> createState() =>
new _MaterialSearchInputState<T>();
}
class _MaterialSearchInputState<T> extends State<MaterialSearchInput<T>> {
GlobalKey<FormFieldState<T>> _formFieldKey =
new GlobalKey<FormFieldState<T>>();
_buildMaterialSearchPage(BuildContext context) {
return new _MaterialSearchPageRoute<T>(
settings: new RouteSettings(
name: 'material_search',
isInitialRoute: false,
),
builder: (BuildContext context) {
return new Material(
child: new MaterialSearch<T>(
placeholder: widget.placeholder,
results: widget.results,
getResults: widget.getResults,
filter: widget.filter,
sort: widget.sort,
onSelect: (dynamic value) => Navigator.of(context).pop(value),
),
);
});
}
_showMaterialSearch(BuildContext context) {
Navigator.of(context)
.push(_buildMaterialSearchPage(context))
.then((dynamic value) {
if (value != null) {
_formFieldKey.currentState.didChange(value);
widget.onSelect(value);
}
});
}
bool get autovalidate {
return widget.autovalidate ??
Form.of(context)?.widget?.autovalidate ??
false;
}
bool _isEmpty(field) {
return field.value == null;
}
Widget build(BuildContext context) {
final TextStyle valueStyle = Theme.of(context).textTheme.subhead;
return new InkWell(
onTap: () => _showMaterialSearch(context),
child: new FormField<T>(
key: _formFieldKey,
validator: widget.validator,
onSaved: widget.onSaved,
autovalidate: autovalidate,
builder: (FormFieldState<T> field) {
return new InputDecorator(
isEmpty: _isEmpty(field),
decoration: new InputDecoration(
labelText: widget.placeholder,
border: InputBorder.none,
errorText: field.errorText,
),
child: _isEmpty(field)
? null
: new Text(
widget.formatter != null
? widget.formatter(field.value)
: field.value.toString(),
style: valueStyle),
);
},
),
);
}
}
///搜索框
class SearchInput extends StatelessWidget {
final getResults;
final ValueChanged<String> onSubmitted;
final VoidCallback onSubmitPressed;
SearchInput(this.getResults, this.onSubmitted, this.onSubmitPressed);
@override
Widget build(BuildContext context) {
return new Container(
height: 40.0,
decoration: BoxDecoration(
color: Theme.of(context).backgroundColor,
borderRadius: BorderRadius.circular(4.0)),
child: new Row(
children: <Widget>[
new Padding(
padding: new EdgeInsets.only(right: 10.0, top: 3.0, left: 10.0),
child: new Icon(Icons.search,
size: 24.0, color: Theme.of(context).accentColor),
),
new Expanded(
child: new MaterialSearchInput(
placeholder: '搜索 flutter 组件',
getResults: getResults,
),
),
],
),
);
}
}
// wigdet干掉.=> componets

399
lib-cp/SearchInput.dart Normal file
View File

@ -0,0 +1,399 @@
import 'dart:async';
import 'package:flutter_web/material.dart';
import 'package:meta/meta.dart';
typedef String FormFieldFormatter<T>(T v);
typedef bool MaterialSearchFilter<T>(T v, String c);
typedef int MaterialSearchSort<T>(T a, T b, String c);
typedef Future<List<MaterialSearchResult>> MaterialResultsFinder(String c);
typedef void OnSubmit(String value);
///搜索结果内容显示面板
class MaterialSearchResult<T> extends StatelessWidget {
const MaterialSearchResult({
Key key,
this.value,
this.text,
this.icon,
this.onTap
}) : super(key: key);
final T value;
final VoidCallback onTap;
final String text;
final IconData icon;
@override
Widget build(BuildContext context) {
return new InkWell(
onTap: this.onTap,
child: new Container(
height: 64.0,
padding: EdgeInsets.fromLTRB(20.0, 0.0, 20.0, 10.0),
child: new Row(
children: <Widget>[
new Container(width: 30.0, child: new Icon(icon)) ?? null,
new Expanded(child: new Text(text, style: Theme.of(context).textTheme.subhead)),
new Text(text, style: Theme.of(context).textTheme.subhead)
],
),
),
);
}
}
class MaterialSearch<T> extends StatefulWidget {
MaterialSearch({
Key key,
this.placeholder,
this.results,
this.getResults,
this.filter,
this.sort,
this.limit: 10,
this.onSelect,
this.onSubmit,
this.barBackgroundColor = Colors.white,
this.iconColor = Colors.black,
this.leading,
}) : assert(() {
if (results == null && getResults == null ||
results != null && getResults != null) {
throw new AssertionError(
'Either provide a function to get the results, or the results.');
}
return true;
}()),
super(key: key);
final String placeholder;
final List<MaterialSearchResult<T>> results;
final MaterialResultsFinder getResults;
final MaterialSearchFilter<T> filter;
final MaterialSearchSort<T> sort;
final int limit;
final ValueChanged<T> onSelect;
final OnSubmit onSubmit;
final Color barBackgroundColor;
final Color iconColor;
final Widget leading;
@override
_MaterialSearchState<T> createState() => new _MaterialSearchState<T>();
}
class _MaterialSearchState<T> extends State<MaterialSearch> {
bool _loading = false;
List<MaterialSearchResult<T>> _results = [];
String _criteria = '';
TextEditingController _controller = new TextEditingController();
_filter(dynamic v, String c) {
return v
.toString()
.toLowerCase()
.trim()
.contains(new RegExp(r'' + c.toLowerCase().trim() + ''));
}
@override
void initState() {
super.initState();
if (widget.getResults != null) {
_getResultsDebounced();
}
_controller.addListener(() {
setState(() {
_criteria = _controller.value.text;
if (widget.getResults != null) {
_getResultsDebounced();
}
});
});
}
Timer _resultsTimer;
Future _getResultsDebounced() async {
if (_results.length == 0) {
setState(() {
_loading = true;
});
}
if (_resultsTimer != null && _resultsTimer.isActive) {
_resultsTimer.cancel();
}
_resultsTimer = new Timer(new Duration(milliseconds: 400), () async {
if (!mounted) {
return;
}
setState(() {
_loading = true;
});
//TODO: debounce widget.results too
var results = await widget.getResults(_criteria);
if (!mounted) {
return;
}
if (results != null) {
setState(() {
_loading = false;
_results = results;
});
}
});
}
@override
void dispose() {
super.dispose();
_resultsTimer?.cancel();
}
Widget buildBody(List results) {
if (_loading) {
return new Center(
child: new Padding(
padding: const EdgeInsets.only(top: 50.0),
child: new CircularProgressIndicator()
)
);
}
if (results.isNotEmpty) {
var content = new SingleChildScrollView(
child: new Column(
children: results
)
);
return content;
}
return Center(child: Text("暂无数据"));
}
@override
Widget build(BuildContext context) {
var results =
(widget.results ?? _results).where((MaterialSearchResult result) {
if (widget.filter != null) {
return widget.filter(result.value, _criteria);
}
//only apply default filter if used the `results` option
//because getResults may already have applied some filter if `filter` option was omited.
else if (widget.results != null) {
return _filter(result.value, _criteria);
}
return true;
}).toList();
if (widget.sort != null) {
results.sort((a, b) => widget.sort(a.value, b.value, _criteria));
}
results = results.take(widget.limit).toList();
IconThemeData iconTheme =
Theme.of(context).iconTheme.copyWith(color: widget.iconColor);
return new Scaffold(
appBar: new AppBar(
leading: widget.leading,
backgroundColor: widget.barBackgroundColor,
iconTheme: iconTheme,
title: new TextField(
controller: _controller,
autofocus: true,
decoration:
new InputDecoration.collapsed(hintText: widget.placeholder),
style: Theme.of(context).textTheme.title,
onSubmitted: (String value) {
if (widget.onSubmit != null) {
widget.onSubmit(value);
}
},
),
actions: _criteria.length == 0
? []
: [
new IconButton(
icon: new Icon(Icons.clear),
onPressed: () {
setState(() {
_controller.text = _criteria = '';
});
}),
],
),
body: buildBody(results),
);
}
}
class _MaterialSearchPageRoute<T> extends MaterialPageRoute<T> {
_MaterialSearchPageRoute({
@required WidgetBuilder builder,
RouteSettings settings: const RouteSettings(),
maintainState: true,
bool fullscreenDialog: false,
}) : assert(builder != null),
super(
builder: builder,
settings: settings,
maintainState: maintainState,
fullscreenDialog: fullscreenDialog);
}
class MaterialSearchInput<T> extends StatefulWidget {
MaterialSearchInput({
Key key,
this.onSaved,
this.validator,
this.autovalidate,
this.placeholder,
this.formatter,
this.results,
this.getResults,
this.filter,
this.sort,
this.onSelect,
});
final FormFieldSetter<T> onSaved;
final FormFieldValidator<T> validator;
final bool autovalidate;
final String placeholder;
final FormFieldFormatter<T> formatter;
final List<MaterialSearchResult<T>> results;
final MaterialResultsFinder getResults;
final MaterialSearchFilter<T> filter;
final MaterialSearchSort<T> sort;
final ValueChanged<T> onSelect;
@override
_MaterialSearchInputState<T> createState() =>
new _MaterialSearchInputState<T>();
}
class _MaterialSearchInputState<T> extends State<MaterialSearchInput<T>> {
GlobalKey<FormFieldState<T>> _formFieldKey =
new GlobalKey<FormFieldState<T>>();
_buildMaterialSearchPage(BuildContext context) {
return new _MaterialSearchPageRoute<T>(
settings: new RouteSettings(
name: 'material_search',
isInitialRoute: false,
),
builder: (BuildContext context) {
return new Material(
child: new MaterialSearch<T>(
placeholder: widget.placeholder,
results: widget.results,
getResults: widget.getResults,
filter: widget.filter,
sort: widget.sort,
onSelect: (dynamic value) => Navigator.of(context).pop(value),
),
);
});
}
_showMaterialSearch(BuildContext context) {
Navigator.of(context)
.push(_buildMaterialSearchPage(context))
.then((dynamic value) {
if (value != null) {
_formFieldKey.currentState.didChange(value);
widget.onSelect(value);
}
});
}
bool get autovalidate {
return widget.autovalidate ??
Form.of(context)?.widget?.autovalidate ??
false;
}
bool _isEmpty(field) {
return field.value == null;
}
Widget build(BuildContext context) {
final TextStyle valueStyle = Theme.of(context).textTheme.subhead;
return new InkWell(
onTap: () => _showMaterialSearch(context),
child: new FormField<T>(
key: _formFieldKey,
validator: widget.validator,
onSaved: widget.onSaved,
autovalidate: autovalidate,
builder: (FormFieldState<T> field) {
return new InputDecorator(
isEmpty: _isEmpty(field),
decoration: new InputDecoration(
labelText: widget.placeholder,
border: InputBorder.none,
errorText: field.errorText,
),
child: _isEmpty(field)
? null
: new Text(
widget.formatter != null
? widget.formatter(field.value)
: field.value.toString(),
style: valueStyle),
);
},
),
);
}
}
///搜索框
class SearchInput extends StatelessWidget {
final getResults;
final ValueChanged<String> onSubmitted;
final VoidCallback onSubmitPressed;
SearchInput(this.getResults, this.onSubmitted, this.onSubmitPressed);
@override
Widget build(BuildContext context) {
return new Container(
height: 40.0,
decoration: BoxDecoration(
color: Theme.of(context).backgroundColor,
borderRadius: BorderRadius.circular(4.0)),
child: new Row(
children: <Widget>[
new Padding(
padding: new EdgeInsets.only(right: 10.0, top: 3.0, left: 10.0),
child: new Icon(Icons.search,
size: 24.0, color: Theme.of(context).accentColor),
),
new Expanded(
child: new MaterialSearchInput(
placeholder: '搜索 flutter 组件',
getResults: getResults,
),
),
],
),
);
}
}
// wigdet干掉.=> componets

View File

@ -0,0 +1,140 @@
import 'dart:async';
import 'package:flutter_web/material.dart';
import '../model/story.dart';
class HomeBanner extends StatefulWidget {
final List<StoryModel> bannerStories;
final OnTapBannerItem onTap;
HomeBanner(this.bannerStories, this.onTap, {Key key})
:super(key: key);
@override
State<StatefulWidget> createState() {
return _BannerState();
}
}
class _BannerState extends State<HomeBanner> {
int virtualIndex = 0;
int realIndex = 1;
PageController controller;
Timer timer;
@override
void initState() {
super.initState();
controller = PageController(initialPage: realIndex);
timer = Timer.periodic(Duration(seconds: 5), (timer) { // 自动滚动
/// print(realIndex);
controller.animateToPage(realIndex + 1,
duration: Duration(milliseconds: 300),
curve: Curves.linear);
});
}
@override
void dispose() {
super.dispose();
controller.dispose();
timer.cancel();
}
@override
Widget build(BuildContext context) {
return Container(
height: 226.0,
child: Stack(
alignment: Alignment.bottomCenter,
children: <Widget>[
PageView(
controller: controller,
onPageChanged: _onPageChanged,
children: _buildItems(),),
_buildIndicator(), // 下面的小点
]),
);
}
List<Widget> _buildItems() { // 排列轮播数组
List<Widget> items = [];
if (widget.bannerStories.length > 0) {
// 头部添加一个尾部Item模拟循环
items.add(
_buildItem(widget.bannerStories[widget.bannerStories.length - 1]));
// 正常添加Item
items.addAll(
widget.bannerStories.map((story) => _buildItem(story)).toList(
growable: false));
// 尾部
items.add(
_buildItem(widget.bannerStories[0]));
}
return items;
}
Widget _buildItem(StoryModel story) {
return GestureDetector(
onTap: () { // 按下
if (widget.onTap != null) {
widget.onTap(story);
}
},
child: Stack(
fit: StackFit.expand,
children: <Widget>[
Image.network(story.image, fit: BoxFit.cover),
_buildItemTitle(story.title), // 内容文字,大意
],),);
}
Widget _buildItemTitle(String title) {
return Container(
decoration: BoxDecoration( /// 背景的渐变色
gradient: LinearGradient(
begin: Alignment.bottomCenter,
end: const Alignment(0.0, -0.8),
colors: [const Color(0xa0000000), Colors.transparent],
),
),
alignment: Alignment.bottomCenter,
child: Container(
margin: EdgeInsets.symmetric(vertical: 22.0, horizontal: 16.0),
child: Text(
title, style: TextStyle(color: Colors.white, fontSize: 18.0),),),
);
}
Widget _buildIndicator() {
List<Widget> indicators = [];
for (int i = 0; i < widget.bannerStories.length; i++) {
indicators.add(Container(
width: 6.0,
height: 6.0,
margin: EdgeInsets.symmetric(horizontal: 1.5, vertical: 10.0),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: i == virtualIndex ? Colors.white : Colors.grey)));
}
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: indicators);
}
_onPageChanged(int index) {
realIndex = index;
int count = widget.bannerStories.length;
if (index == 0) {
virtualIndex = count - 1;
controller.jumpToPage(count);
} else if (index == count + 1) {
virtualIndex = 0;
controller.jumpToPage(1);
} else {
virtualIndex = index - 1;
}
setState(() {});
}
}
typedef void OnTapBannerItem(StoryModel story);

View File

@ -0,0 +1,140 @@
import 'dart:async';
import 'package:flutter_web/material.dart';
import '../model/story.dart';
class HomeBanner extends StatefulWidget {
final List<StoryModel> bannerStories;
final OnTapBannerItem onTap;
HomeBanner(this.bannerStories, this.onTap, {Key key})
:super(key: key);
@override
State<StatefulWidget> createState() {
return _BannerState();
}
}
class _BannerState extends State<HomeBanner> {
int virtualIndex = 0;
int realIndex = 1;
PageController controller;
Timer timer;
@override
void initState() {
super.initState();
controller = PageController(initialPage: realIndex);
timer = Timer.periodic(Duration(seconds: 5), (timer) { // 自动滚动
/// print(realIndex);
controller.animateToPage(realIndex + 1,
duration: Duration(milliseconds: 300),
curve: Curves.linear);
});
}
@override
void dispose() {
super.dispose();
controller.dispose();
timer.cancel();
}
@override
Widget build(BuildContext context) {
return Container(
height: 226.0,
child: Stack(
alignment: Alignment.bottomCenter,
children: <Widget>[
PageView(
controller: controller,
onPageChanged: _onPageChanged,
children: _buildItems(),),
_buildIndicator(), // 下面的小点
]),
);
}
List<Widget> _buildItems() { // 排列轮播数组
List<Widget> items = [];
if (widget.bannerStories.length > 0) {
// 头部添加一个尾部Item模拟循环
items.add(
_buildItem(widget.bannerStories[widget.bannerStories.length - 1]));
// 正常添加Item
items.addAll(
widget.bannerStories.map((story) => _buildItem(story)).toList(
growable: false));
// 尾部
items.add(
_buildItem(widget.bannerStories[0]));
}
return items;
}
Widget _buildItem(StoryModel story) {
return GestureDetector(
onTap: () { // 按下
if (widget.onTap != null) {
widget.onTap(story);
}
},
child: Stack(
fit: StackFit.expand,
children: <Widget>[
Image.network(story.image, fit: BoxFit.cover),
_buildItemTitle(story.title), // 内容文字,大意
],),);
}
Widget _buildItemTitle(String title) {
return Container(
decoration: BoxDecoration( /// 背景的渐变色
gradient: LinearGradient(
begin: Alignment.bottomCenter,
end: const Alignment(0.0, -0.8),
colors: [const Color(0xa0000000), Colors.transparent],
),
),
alignment: Alignment.bottomCenter,
child: Container(
margin: EdgeInsets.symmetric(vertical: 22.0, horizontal: 16.0),
child: Text(
title, style: TextStyle(color: Colors.white, fontSize: 18.0),),),
);
}
Widget _buildIndicator() {
List<Widget> indicators = [];
for (int i = 0; i < widget.bannerStories.length; i++) {
indicators.add(Container(
width: 6.0,
height: 6.0,
margin: EdgeInsets.symmetric(horizontal: 1.5, vertical: 10.0),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: i == virtualIndex ? Colors.white : Colors.grey)));
}
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: indicators);
}
_onPageChanged(int index) {
realIndex = index;
int count = widget.bannerStories.length;
if (index == 0) {
virtualIndex = count - 1;
controller.jumpToPage(count);
} else if (index == count + 1) {
virtualIndex = 0;
controller.jumpToPage(1);
} else {
virtualIndex = index - 1;
}
setState(() {});
}
}
typedef void OnTapBannerItem(StoryModel story);

140
lib-cp/homeBanner-copy.dart Normal file
View File

@ -0,0 +1,140 @@
import 'dart:async';
import 'package:flutter_web/material.dart';
import '../model/story.dart';
class HomeBanner extends StatefulWidget {
final List<StoryModel> bannerStories;
final OnTapBannerItem onTap;
HomeBanner(this.bannerStories, this.onTap, {Key key})
:super(key: key);
@override
State<StatefulWidget> createState() {
return _BannerState();
}
}
class _BannerState extends State<HomeBanner> {
int virtualIndex = 0;
int realIndex = 1;
PageController controller;
Timer timer;
@override
void initState() {
super.initState();
controller = PageController(initialPage: realIndex);
timer = Timer.periodic(Duration(seconds: 5), (timer) { // 自动滚动
/// print(realIndex);
controller.animateToPage(realIndex + 1,
duration: Duration(milliseconds: 300),
curve: Curves.linear);
});
}
@override
void dispose() {
super.dispose();
controller.dispose();
timer.cancel();
}
@override
Widget build(BuildContext context) {
return Container(
height: 226.0,
child: Stack(
alignment: Alignment.bottomCenter,
children: <Widget>[
PageView(
controller: controller,
onPageChanged: _onPageChanged,
children: _buildItems(),),
_buildIndicator(), // 下面的小点
]),
);
}
List<Widget> _buildItems() { // 排列轮播数组
List<Widget> items = [];
if (widget.bannerStories.length > 0) {
// 头部添加一个尾部Item模拟循环
items.add(
_buildItem(widget.bannerStories[widget.bannerStories.length - 1]));
// 正常添加Item
items.addAll(
widget.bannerStories.map((story) => _buildItem(story)).toList(
growable: false));
// 尾部
items.add(
_buildItem(widget.bannerStories[0]));
}
return items;
}
Widget _buildItem(StoryModel story) {
return GestureDetector(
onTap: () { // 按下
if (widget.onTap != null) {
widget.onTap(story);
}
},
child: Stack(
fit: StackFit.expand,
children: <Widget>[
Image.network(story.image, fit: BoxFit.cover),
_buildItemTitle(story.title), // 内容文字,大意
],),);
}
Widget _buildItemTitle(String title) {
return Container(
decoration: BoxDecoration( /// 背景的渐变色
gradient: LinearGradient(
begin: Alignment.bottomCenter,
end: const Alignment(0.0, -0.8),
colors: [const Color(0xa0000000), Colors.transparent],
),
),
alignment: Alignment.bottomCenter,
child: Container(
margin: EdgeInsets.symmetric(vertical: 22.0, horizontal: 16.0),
child: Text(
title, style: TextStyle(color: Colors.white, fontSize: 18.0),),),
);
}
Widget _buildIndicator() {
List<Widget> indicators = [];
for (int i = 0; i < widget.bannerStories.length; i++) {
indicators.add(Container(
width: 6.0,
height: 6.0,
margin: EdgeInsets.symmetric(horizontal: 1.5, vertical: 10.0),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: i == virtualIndex ? Colors.white : Colors.grey)));
}
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: indicators);
}
_onPageChanged(int index) {
realIndex = index;
int count = widget.bannerStories.length;
if (index == 0) {
virtualIndex = count - 1;
controller.jumpToPage(count);
} else if (index == count + 1) {
virtualIndex = 0;
controller.jumpToPage(1);
} else {
virtualIndex = index - 1;
}
setState(() {});
}
}
typedef void OnTapBannerItem(StoryModel story);

140
lib-cp/homeBanner.dart Normal file
View File

@ -0,0 +1,140 @@
import 'dart:async';
import 'package:flutter_web/material.dart';
import '../model/story.dart';
class HomeBanner extends StatefulWidget {
final List<StoryModel> bannerStories;
final OnTapBannerItem onTap;
HomeBanner(this.bannerStories, this.onTap, {Key key})
:super(key: key);
@override
State<StatefulWidget> createState() {
return _BannerState();
}
}
class _BannerState extends State<HomeBanner> {
int virtualIndex = 0;
int realIndex = 1;
PageController controller;
Timer timer;
@override
void initState() {
super.initState();
controller = PageController(initialPage: realIndex);
timer = Timer.periodic(Duration(seconds: 5), (timer) { // 自动滚动
/// print(realIndex);
controller.animateToPage(realIndex + 1,
duration: Duration(milliseconds: 300),
curve: Curves.linear);
});
}
@override
void dispose() {
super.dispose();
controller.dispose();
timer.cancel();
}
@override
Widget build(BuildContext context) {
return Container(
height: 226.0,
child: Stack(
alignment: Alignment.bottomCenter,
children: <Widget>[
PageView(
controller: controller,
onPageChanged: _onPageChanged,
children: _buildItems(),),
_buildIndicator(), // 下面的小点
]),
);
}
List<Widget> _buildItems() { // 排列轮播数组
List<Widget> items = [];
if (widget.bannerStories.length > 0) {
// 头部添加一个尾部Item模拟循环
items.add(
_buildItem(widget.bannerStories[widget.bannerStories.length - 1]));
// 正常添加Item
items.addAll(
widget.bannerStories.map((story) => _buildItem(story)).toList(
growable: false));
// 尾部
items.add(
_buildItem(widget.bannerStories[0]));
}
return items;
}
Widget _buildItem(StoryModel story) {
return GestureDetector(
onTap: () { // 按下
if (widget.onTap != null) {
widget.onTap(story);
}
},
child: Stack(
fit: StackFit.expand,
children: <Widget>[
Image.network(story.image, fit: BoxFit.cover),
_buildItemTitle(story.title), // 内容文字,大意
],),);
}
Widget _buildItemTitle(String title) {
return Container(
decoration: BoxDecoration( /// 背景的渐变色
gradient: LinearGradient(
begin: Alignment.bottomCenter,
end: const Alignment(0.0, -0.8),
colors: [const Color(0xa0000000), Colors.transparent],
),
),
alignment: Alignment.bottomCenter,
child: Container(
margin: EdgeInsets.symmetric(vertical: 22.0, horizontal: 16.0),
child: Text(
title, style: TextStyle(color: Colors.white, fontSize: 18.0),),),
);
}
Widget _buildIndicator() {
List<Widget> indicators = [];
for (int i = 0; i < widget.bannerStories.length; i++) {
indicators.add(Container(
width: 6.0,
height: 6.0,
margin: EdgeInsets.symmetric(horizontal: 1.5, vertical: 10.0),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: i == virtualIndex ? Colors.white : Colors.grey)));
}
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: indicators);
}
_onPageChanged(int index) {
realIndex = index;
int count = widget.bannerStories.length;
if (index == 0) {
virtualIndex = count - 1;
controller.jumpToPage(count);
} else if (index == count + 1) {
virtualIndex = 0;
controller.jumpToPage(1);
} else {
virtualIndex = index - 1;
}
setState(() {});
}
}
typedef void OnTapBannerItem(StoryModel story);

View File

@ -0,0 +1,32 @@
import 'package:flutter_markdown/flutter_markdown.dart' as md;
import '../common/high_light_code.dart';
import 'package:flutter_web/material.dart';
/// 使用方法
/// MarkdownBody(markdown)
final hightlighter = new HighLight();
class HighLight extends md.SyntaxHighlighter {
@override
TextSpan format(String source) {
// TODO: implement format
final SyntaxHighlighterStyle style = SyntaxHighlighterStyle.lightThemeStyle();
return TextSpan(
style: const TextStyle(fontSize: 10.0),
children: <TextSpan>[
DartSyntaxHighlighter(style).format(source)
]
);
}
}
class MarkdownBody extends StatelessWidget {
String data;
MarkdownBody(this.data);
@override
Widget build(BuildContext context) {
// TODO: implement build
return md.MarkdownBody(data: data, syntaxHighlighter: new HighLight());
}
}

View File

@ -0,0 +1,32 @@
import 'package:flutter_markdown/flutter_markdown.dart' as md;
import '../common/high_light_code.dart';
import 'package:flutter_web/material.dart';
/// 使用方法
/// MarkdownBody(markdown)
final hightlighter = new HighLight();
class HighLight extends md.SyntaxHighlighter {
@override
TextSpan format(String source) {
// TODO: implement format
final SyntaxHighlighterStyle style = SyntaxHighlighterStyle.lightThemeStyle();
return TextSpan(
style: const TextStyle(fontSize: 10.0),
children: <TextSpan>[
DartSyntaxHighlighter(style).format(source)
]
);
}
}
class MarkdownBody extends StatelessWidget {
String data;
MarkdownBody(this.data);
@override
Widget build(BuildContext context) {
// TODO: implement build
return md.MarkdownBody(data: data, syntaxHighlighter: new HighLight());
}
}

32
lib-cp/markdown-copy.dart Normal file
View File

@ -0,0 +1,32 @@
import 'package:flutter_markdown/flutter_markdown.dart' as md;
import '../common/high_light_code.dart';
import 'package:flutter_web/material.dart';
/// 使用方法
/// MarkdownBody(markdown)
final hightlighter = new HighLight();
class HighLight extends md.SyntaxHighlighter {
@override
TextSpan format(String source) {
// TODO: implement format
final SyntaxHighlighterStyle style = SyntaxHighlighterStyle.lightThemeStyle();
return TextSpan(
style: const TextStyle(fontSize: 10.0),
children: <TextSpan>[
DartSyntaxHighlighter(style).format(source)
]
);
}
}
class MarkdownBody extends StatelessWidget {
String data;
MarkdownBody(this.data);
@override
Widget build(BuildContext context) {
// TODO: implement build
return md.MarkdownBody(data: data, syntaxHighlighter: new HighLight());
}
}

32
lib-cp/markdown.dart Normal file
View File

@ -0,0 +1,32 @@
import 'package:flutter_markdown/flutter_markdown.dart' as md;
import '../common/high_light_code.dart';
import 'package:flutter_web/material.dart';
/// 使用方法
/// MarkdownBody(markdown)
final hightlighter = new HighLight();
class HighLight extends md.SyntaxHighlighter {
@override
TextSpan format(String source) {
// TODO: implement format
final SyntaxHighlighterStyle style = SyntaxHighlighterStyle.lightThemeStyle();
return TextSpan(
style: const TextStyle(fontSize: 10.0),
children: <TextSpan>[
DartSyntaxHighlighter(style).format(source)
]
);
}
}
class MarkdownBody extends StatelessWidget {
String data;
MarkdownBody(this.data);
@override
Widget build(BuildContext context) {
// TODO: implement build
return md.MarkdownBody(data: data, syntaxHighlighter: new HighLight());
}
}

View File

@ -0,0 +1,88 @@
/**
* @author 一凨
*/
import 'package:flutter_web/material.dart';
import '../common/Style.dart';
import '../common/widget_name_to_icon.dart';
class WidgetItem extends StatelessWidget {
final String title;
final VoidCallback onTap;
final int index; //用于计算border
final int totalCount;
final int rowLength;
String _widgetName;
WidgetItem(
{this.title, this.onTap, this.index, this.totalCount, this.rowLength});
Border _buildBorder(context) {
Border _border;
bool isRight = (index % rowLength) == (rowLength - 1); //是不是最右边的,决定是否有右侧边框
var currentRow = (index + 1) % rowLength > 0
? (index + 1) ~/ rowLength + 1
: (index + 1) ~/ rowLength;
int totalRow = totalCount % rowLength > 0
? totalCount ~/ rowLength + 1
: totalCount ~/ rowLength;
if (currentRow < totalRow && isRight) {
//不是最后一行,是最右边
_border = Border(
bottom: const BorderSide(
width: 1.0, color: Color(WidgetDemoColor.borderColor)),
);
}
if (currentRow < totalRow && !isRight) {
_border = Border(
right: const BorderSide(
width: 1.0, color: Color(WidgetDemoColor.borderColor)),
bottom: const BorderSide(
width: 1.0, color: Color(WidgetDemoColor.borderColor)),
);
}
if (currentRow == totalRow && !isRight) {
_border = Border(
right: const BorderSide(
width: 1.0, color: Color(WidgetDemoColor.borderColor)),
);
}
return _border;
}
@override
Widget build(BuildContext context) {
_widgetName = title.replaceFirst(
//首字母转为大写
title.substring(0, 1),
title.substring(0, 1).toUpperCase());
Icon widgetIcon;
if (WidgetName2Icon.icons[_widgetName] != null) {
widgetIcon = Icon(WidgetName2Icon.icons[_widgetName]);
} else {
widgetIcon = Icon(
Icons.crop,
);
}
return InkWell(
onTap: onTap,
child: Container(
decoration: new BoxDecoration(
border: _buildBorder(context),
),
padding: const EdgeInsets.symmetric(vertical: 30.0, horizontal: 10.0),
height: 150.0,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
widgetIcon,
SizedBox(
height: 8.0,
),
Text(_widgetName),
],
) ,
),
);
}
}

View File

@ -0,0 +1,88 @@
/**
* @author 一凨
*/
import 'package:flutter_web/material.dart';
import '../common/Style.dart';
import '../common/widget_name_to_icon.dart';
class WidgetItem extends StatelessWidget {
final String title;
final VoidCallback onTap;
final int index; //用于计算border
final int totalCount;
final int rowLength;
String _widgetName;
WidgetItem(
{this.title, this.onTap, this.index, this.totalCount, this.rowLength});
Border _buildBorder(context) {
Border _border;
bool isRight = (index % rowLength) == (rowLength - 1); //是不是最右边的,决定是否有右侧边框
var currentRow = (index + 1) % rowLength > 0
? (index + 1) ~/ rowLength + 1
: (index + 1) ~/ rowLength;
int totalRow = totalCount % rowLength > 0
? totalCount ~/ rowLength + 1
: totalCount ~/ rowLength;
if (currentRow < totalRow && isRight) {
//不是最后一行,是最右边
_border = Border(
bottom: const BorderSide(
width: 1.0, color: Color(WidgetDemoColor.borderColor)),
);
}
if (currentRow < totalRow && !isRight) {
_border = Border(
right: const BorderSide(
width: 1.0, color: Color(WidgetDemoColor.borderColor)),
bottom: const BorderSide(
width: 1.0, color: Color(WidgetDemoColor.borderColor)),
);
}
if (currentRow == totalRow && !isRight) {
_border = Border(
right: const BorderSide(
width: 1.0, color: Color(WidgetDemoColor.borderColor)),
);
}
return _border;
}
@override
Widget build(BuildContext context) {
_widgetName = title.replaceFirst(
//首字母转为大写
title.substring(0, 1),
title.substring(0, 1).toUpperCase());
Icon widgetIcon;
if (WidgetName2Icon.icons[_widgetName] != null) {
widgetIcon = Icon(WidgetName2Icon.icons[_widgetName]);
} else {
widgetIcon = Icon(
Icons.crop,
);
}
return InkWell(
onTap: onTap,
child: Container(
decoration: new BoxDecoration(
border: _buildBorder(context),
),
padding: const EdgeInsets.symmetric(vertical: 30.0, horizontal: 10.0),
height: 150.0,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
widgetIcon,
SizedBox(
height: 8.0,
),
Text(_widgetName),
],
) ,
),
);
}
}

View File

@ -0,0 +1,88 @@
/**
* @author 一凨
*/
import 'package:flutter_web/material.dart';
import '../common/Style.dart';
import '../common/widget_name_to_icon.dart';
class WidgetItem extends StatelessWidget {
final String title;
final VoidCallback onTap;
final int index; //用于计算border
final int totalCount;
final int rowLength;
String _widgetName;
WidgetItem(
{this.title, this.onTap, this.index, this.totalCount, this.rowLength});
Border _buildBorder(context) {
Border _border;
bool isRight = (index % rowLength) == (rowLength - 1); //是不是最右边的,决定是否有右侧边框
var currentRow = (index + 1) % rowLength > 0
? (index + 1) ~/ rowLength + 1
: (index + 1) ~/ rowLength;
int totalRow = totalCount % rowLength > 0
? totalCount ~/ rowLength + 1
: totalCount ~/ rowLength;
if (currentRow < totalRow && isRight) {
//不是最后一行,是最右边
_border = Border(
bottom: const BorderSide(
width: 1.0, color: Color(WidgetDemoColor.borderColor)),
);
}
if (currentRow < totalRow && !isRight) {
_border = Border(
right: const BorderSide(
width: 1.0, color: Color(WidgetDemoColor.borderColor)),
bottom: const BorderSide(
width: 1.0, color: Color(WidgetDemoColor.borderColor)),
);
}
if (currentRow == totalRow && !isRight) {
_border = Border(
right: const BorderSide(
width: 1.0, color: Color(WidgetDemoColor.borderColor)),
);
}
return _border;
}
@override
Widget build(BuildContext context) {
_widgetName = title.replaceFirst(
//首字母转为大写
title.substring(0, 1),
title.substring(0, 1).toUpperCase());
Icon widgetIcon;
if (WidgetName2Icon.icons[_widgetName] != null) {
widgetIcon = Icon(WidgetName2Icon.icons[_widgetName]);
} else {
widgetIcon = Icon(
Icons.crop,
);
}
return InkWell(
onTap: onTap,
child: Container(
decoration: new BoxDecoration(
border: _buildBorder(context),
),
padding: const EdgeInsets.symmetric(vertical: 30.0, horizontal: 10.0),
height: 150.0,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
widgetIcon,
SizedBox(
height: 8.0,
),
Text(_widgetName),
],
) ,
),
);
}
}

88
lib-cp/widget_item.dart Normal file
View File

@ -0,0 +1,88 @@
/**
* @author 一凨
*/
import 'package:flutter_web/material.dart';
import '../common/Style.dart';
import '../common/widget_name_to_icon.dart';
class WidgetItem extends StatelessWidget {
final String title;
final VoidCallback onTap;
final int index; //用于计算border
final int totalCount;
final int rowLength;
String _widgetName;
WidgetItem(
{this.title, this.onTap, this.index, this.totalCount, this.rowLength});
Border _buildBorder(context) {
Border _border;
bool isRight = (index % rowLength) == (rowLength - 1); //是不是最右边的,决定是否有右侧边框
var currentRow = (index + 1) % rowLength > 0
? (index + 1) ~/ rowLength + 1
: (index + 1) ~/ rowLength;
int totalRow = totalCount % rowLength > 0
? totalCount ~/ rowLength + 1
: totalCount ~/ rowLength;
if (currentRow < totalRow && isRight) {
//不是最后一行,是最右边
_border = Border(
bottom: const BorderSide(
width: 1.0, color: Color(WidgetDemoColor.borderColor)),
);
}
if (currentRow < totalRow && !isRight) {
_border = Border(
right: const BorderSide(
width: 1.0, color: Color(WidgetDemoColor.borderColor)),
bottom: const BorderSide(
width: 1.0, color: Color(WidgetDemoColor.borderColor)),
);
}
if (currentRow == totalRow && !isRight) {
_border = Border(
right: const BorderSide(
width: 1.0, color: Color(WidgetDemoColor.borderColor)),
);
}
return _border;
}
@override
Widget build(BuildContext context) {
_widgetName = title.replaceFirst(
//首字母转为大写
title.substring(0, 1),
title.substring(0, 1).toUpperCase());
Icon widgetIcon;
if (WidgetName2Icon.icons[_widgetName] != null) {
widgetIcon = Icon(WidgetName2Icon.icons[_widgetName]);
} else {
widgetIcon = Icon(
Icons.crop,
);
}
return InkWell(
onTap: onTap,
child: Container(
decoration: new BoxDecoration(
border: _buildBorder(context),
),
padding: const EdgeInsets.symmetric(vertical: 30.0, horizontal: 10.0),
height: 150.0,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
widgetIcon,
SizedBox(
height: 8.0,
),
Text(_widgetName),
],
) ,
),
);
}
}

View File

@ -0,0 +1,80 @@
import 'package:flutter_web/material.dart';
import './widget_item.dart';
import '../routers/application.dart';
import '../widgets/index.dart';
class WidgetItemContainer extends StatelessWidget {
final int columnCount; //一行几个
final List<dynamic> categories;
final bool isWidgetPoint;
// 所有的可用demos;
List widgetDemosList = new WidgetDemoList().getDemos();
WidgetItemContainer(
{Key key,
@required this.categories,
@required this.columnCount,
@required this.isWidgetPoint})
: super(key: key);
List<Widget> _buildColumns(context) {
List<Widget> _listWidget = [];
List<Widget> _listRows = [];
int addI;
for (int i = 0, length = categories.length; i < length; i += columnCount) {
_listRows = [];
for (int innerI = 0; innerI < columnCount; innerI++) {
addI = innerI + i;
if (addI < length) {
dynamic item = categories[addI];
_listRows.add(
Expanded(
flex: 1,
child: WidgetItem(
title: item.name,
onTap: () {
if (isWidgetPoint) {
String targetName = item.name;
String targetRouter = '/category/error/404';
widgetDemosList.forEach((item) {
if (item.name == targetName) {
targetRouter = item.routerName;
}
});
Application.router.navigateTo(context, "${targetRouter}");
} else {
Application.router
.navigateTo(context, "/category/${item.name}");
}
},
index: addI,
totalCount: length,
rowLength: columnCount,
),
),
);
} else {
_listRows.add(
Expanded(
flex: 1,
child: Container(),
),
);
}
}
_listWidget.add(
Row(
children: _listRows,
),
);
}
return _listWidget;
}
@override
Widget build(BuildContext context) {
return Column(
children: _buildColumns(context),
);
}
}

View File

@ -0,0 +1,80 @@
import 'package:flutter_web/material.dart';
import './widget_item.dart';
import '../routers/application.dart';
import '../widgets/index.dart';
class WidgetItemContainer extends StatelessWidget {
final int columnCount; //一行几个
final List<dynamic> categories;
final bool isWidgetPoint;
// 所有的可用demos;
List widgetDemosList = new WidgetDemoList().getDemos();
WidgetItemContainer(
{Key key,
@required this.categories,
@required this.columnCount,
@required this.isWidgetPoint})
: super(key: key);
List<Widget> _buildColumns(context) {
List<Widget> _listWidget = [];
List<Widget> _listRows = [];
int addI;
for (int i = 0, length = categories.length; i < length; i += columnCount) {
_listRows = [];
for (int innerI = 0; innerI < columnCount; innerI++) {
addI = innerI + i;
if (addI < length) {
dynamic item = categories[addI];
_listRows.add(
Expanded(
flex: 1,
child: WidgetItem(
title: item.name,
onTap: () {
if (isWidgetPoint) {
String targetName = item.name;
String targetRouter = '/category/error/404';
widgetDemosList.forEach((item) {
if (item.name == targetName) {
targetRouter = item.routerName;
}
});
Application.router.navigateTo(context, "${targetRouter}");
} else {
Application.router
.navigateTo(context, "/category/${item.name}");
}
},
index: addI,
totalCount: length,
rowLength: columnCount,
),
),
);
} else {
_listRows.add(
Expanded(
flex: 1,
child: Container(),
),
);
}
}
_listWidget.add(
Row(
children: _listRows,
),
);
}
return _listWidget;
}
@override
Widget build(BuildContext context) {
return Column(
children: _buildColumns(context),
);
}
}

View File

@ -0,0 +1,80 @@
import 'package:flutter_web/material.dart';
import './widget_item.dart';
import '../routers/application.dart';
import '../widgets/index.dart';
class WidgetItemContainer extends StatelessWidget {
final int columnCount; //一行几个
final List<dynamic> categories;
final bool isWidgetPoint;
// 所有的可用demos;
List widgetDemosList = new WidgetDemoList().getDemos();
WidgetItemContainer(
{Key key,
@required this.categories,
@required this.columnCount,
@required this.isWidgetPoint})
: super(key: key);
List<Widget> _buildColumns(context) {
List<Widget> _listWidget = [];
List<Widget> _listRows = [];
int addI;
for (int i = 0, length = categories.length; i < length; i += columnCount) {
_listRows = [];
for (int innerI = 0; innerI < columnCount; innerI++) {
addI = innerI + i;
if (addI < length) {
dynamic item = categories[addI];
_listRows.add(
Expanded(
flex: 1,
child: WidgetItem(
title: item.name,
onTap: () {
if (isWidgetPoint) {
String targetName = item.name;
String targetRouter = '/category/error/404';
widgetDemosList.forEach((item) {
if (item.name == targetName) {
targetRouter = item.routerName;
}
});
Application.router.navigateTo(context, "${targetRouter}");
} else {
Application.router
.navigateTo(context, "/category/${item.name}");
}
},
index: addI,
totalCount: length,
rowLength: columnCount,
),
),
);
} else {
_listRows.add(
Expanded(
flex: 1,
child: Container(),
),
);
}
}
_listWidget.add(
Row(
children: _listRows,
),
);
}
return _listWidget;
}
@override
Widget build(BuildContext context) {
return Column(
children: _buildColumns(context),
);
}
}

View File

@ -0,0 +1,80 @@
import 'package:flutter_web/material.dart';
import './widget_item.dart';
import '../routers/application.dart';
import '../widgets/index.dart';
class WidgetItemContainer extends StatelessWidget {
final int columnCount; //一行几个
final List<dynamic> categories;
final bool isWidgetPoint;
// 所有的可用demos;
List widgetDemosList = new WidgetDemoList().getDemos();
WidgetItemContainer(
{Key key,
@required this.categories,
@required this.columnCount,
@required this.isWidgetPoint})
: super(key: key);
List<Widget> _buildColumns(context) {
List<Widget> _listWidget = [];
List<Widget> _listRows = [];
int addI;
for (int i = 0, length = categories.length; i < length; i += columnCount) {
_listRows = [];
for (int innerI = 0; innerI < columnCount; innerI++) {
addI = innerI + i;
if (addI < length) {
dynamic item = categories[addI];
_listRows.add(
Expanded(
flex: 1,
child: WidgetItem(
title: item.name,
onTap: () {
if (isWidgetPoint) {
String targetName = item.name;
String targetRouter = '/category/error/404';
widgetDemosList.forEach((item) {
if (item.name == targetName) {
targetRouter = item.routerName;
}
});
Application.router.navigateTo(context, "${targetRouter}");
} else {
Application.router
.navigateTo(context, "/category/${item.name}");
}
},
index: addI,
totalCount: length,
rowLength: columnCount,
),
),
);
} else {
_listRows.add(
Expanded(
flex: 1,
child: Container(),
),
);
}
}
_listWidget.add(
Row(
children: _listRows,
),
);
}
return _listWidget;
}
@override
Widget build(BuildContext context) {
return Column(
children: _buildColumns(context),
);
}
}

View File

@ -1,51 +0,0 @@
/**
* Created with Android Studio.
* User: 一晟
* Date: 2019/6/9
* Time: 9:01 AM
* email: zhu.yan@alibaba-inc.com
* tartget:
*/
import 'dart:io'; // io作为dart标准库用来操作文件不需要在pubspec.yaml中声明依赖
import 'package:args/args.dart';
ArgResults argResults;
void main(List<String> arguments) {
final ArgParser argParser = new ArgParser()
..addOption('title', abbr: 't',
help: "The title will be inserted into the <title> tag.")
..addOption('filename', abbr: 'f', defaultsTo: 'index.html',
help: "Optional. Output file name. (Default: index.html)");
argResults = argParser.parse(arguments);
final String title = argResults['title'];
if (title == null) {
handleError("Missing required argument: title");
}
else {
final String filename = argResults['filename'];
final String output = """<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>$title</title>
</head>
<body>
</body>
</html>
""";
new File(filename).writeAsStringSync(output);// 为了简单实用了同步版本
stdout.writeln("File saved: $filename");
}
}
// 异步输出错误信息到标准错误流
void handleError(String msg) {
stderr.writeln(msg);
exitCode = 2; //当程序退出虚拟机检查exitCode0 表示Success1 表示Warnings,2 表示Errors
}

View File

@ -1,98 +0,0 @@
/**
* Created with Android Studio.
* User: 一晟
* Date: 2019/6/9
* Time: 10:15 AM
* email: zhu.yan@alibaba-inc.com
* tartget:
*/
import 'dart:async';
import 'dart:io';
import 'dart:convert';
import 'package:dart_inquirer/dart_inquirer.dart';
import 'package:console/console.dart';
//const defaultPath = "/Users/ryan/work/ali/github/flutter-study/flutter_web/examples/@ali-flutter-go/lib/widgets/elements";
const defaultPath = "/Users/ryan/work/ali/github/flutter-project/flutter-go-web/examples/@ali-flutter-go/lib/widgets/themes";
void main() async{
qus_ans();
}
void qus_ans() async{
List<Question> questions = [
ConfirmQuestion('confirm', '使用输入的文件目录 ?',preferN: false),
InputQuestion('path', '输入文件目录:', skipIf: (Map ctx) => ctx["confirm"] == false),
ConfirmQuestion('default', '使用默认文件目录 ?', skipIf: (Map ctx) => ctx["confirm"] == true)
];
Prompt prompt = Prompt(questions);
Map answers = await prompt.execute();
String filePath = answers["path"];
print(Seperator('='));
/// print(answers);
if (answers["path"] is String && (answers["path"] as String).isNotEmpty){
print("使用输入文件目录:${filePath}");
printFilesAync(filePath);
}else if(!answers["confirm"] && answers["default"]){
print("使用默认文件目录:${defaultPath}");
printFilesAync(defaultPath);
}else{
print(format("{@red}放弃转换!{@normal}"));
}
}
void printFilesAync(String path) async{
try{
var directory = new Directory(path);
List<FileSystemEntity> files = directory.listSync();
if(files.length == 0) {
print(format("{@yellow}目录为空!{@normal}"));
return;
}
//print('2::${files}');
for(var f in files){
var bool = FileSystemEntity.isFileSync(f.path);
if(!bool){
//print('1::${bool}::${f.path}::${files.length}');
await printFilesAync(f.path);
}else if(f.path.indexOf('.dart')!=-1){
print('2::${bool}::${f.path}::${files.length}');
var newPath = (f.path).replaceAll(new RegExp(r'.dart'), '-copy.dart');
File newfile = new File(newPath);
File oldfile = new File(f.path);
List<String> lines = oldfile.readAsLinesSync();
var result = '';
lines.forEach((l)=>{
if(l.trim().indexOf('package:flutter/material.dart') >=0){
result += "import 'package:flutter_web/material.dart';\n"
}else if(l.trim().indexOf('package:flutter/widgets.dart') >=0){
result += "import 'package:flutter_web/widgets.dart';\n"
}else if(l.trim().indexOf('package:flutter/cupertino.dart') >=0){
result += "import 'package:flutter_web/cupertino.dart';\n"
}else if(l.trim().indexOf('package:flutter/services.dart') >=0){
result += "import 'package:flutter_web/services.dart';\n"
}else if(l.trim().indexOf('package:flutter/rendering.dart') >=0){
result += "import 'package:flutter_web/rendering.dart';\n"
}else if(l.trim().indexOf('dart:ui') >=0){
result += "import 'package:flutter_web_ui/ui.dart';\n"
}else {
result += '${l}\n'
}
}
);
oldfile.writeAsStringSync(result);
//newfile.writeAsStringSync(result);
///await newfile.create();
//await newfile.create();
///file.createSync();
///await oldfile.delete();
}
}
}catch(e){
print(format("{@red}目录不存在!{@normal}"));
}
}

View File

@ -1,31 +0,0 @@
/**
* Created with Android Studio.
* User: 一晟
* Date: 2019/6/9
* Time: 8:16 AM
* email: zhu.yan@alibaba-inc.com
* tartget:
*/
import 'package:args/args.dart'; // 使用其中两个类ArgParser和ArgResults
ArgResults argResults; // 声明ArgResults类型的全局变量保存解析的参数结果
// 同时argResults也是ArgResults的实例
void main(List<String> arguments) {
// 创建ArgParser的实例同时指定需要输入的参数
final ArgParser argParser = new ArgParser()
/// “help”参数通过addFlag()定义flag 是一个特殊的命令行参数它是一个Boolean值而不是String。如果flag在命令行中出现它的值是true。
..addOption('name', abbr: 'n', defaultsTo: 'World', help: "Who would you like to greet?") // abbr表示缩写或别名defaultsTo表示默认值
..addFlag('help', abbr: 'h', negatable: false, help: "Displays this help information.");
argResults = argParser.parse(arguments);
if (argResults['help']) {
print("""** HELP **${argParser.usage}""");
}
// usage显示所有help内容
final String name = argResults['name'];
print("Hello, $name!");
}

105
tools/bin/trans2fw.dart Normal file
View File

@ -0,0 +1,105 @@
/**
* Created with Android Studio.
* User: 一晟
* Date: 2019/6/9
* Time: 10:15 AM
* email: zhu.yan@alibaba-inc.com
* tartget:
*/
import 'dart:async';
import 'dart:io';
import 'dart:convert';
import 'package:dart_inquirer/dart_inquirer.dart';
import 'package:console/console.dart';
import 'package:path/path.dart' as path;
const defaultPath = "";
var projectPath = (Directory.current.uri).toString();
void main() async {
qus_ans();
}
void qus_ans() async {
List<Question> questions = [
// ListQuestion('select', format("{@green}从上面的选项中选择你的路径类型{@normal}"),
// ['项目目录', '系统根目录']),
InputQuestion('path', '请输入需要转换的文件目录(相对于项目目录):',
skipIf: (Map ctx) => ctx["confirm"] == true),
ConfirmQuestion('cover', '是否覆盖原有文件 ?', preferN: true),
];
Prompt prompt = Prompt(questions);
Map answers = await prompt.execute();
String filePath = answers["path"];
String select = answers['select'];
bool cover = answers['cover'];
///print(Seperator('='));
print(answers);
// if (select == '项目目录') {
// filePath = projectPath + filePath;
// }
if (answers["path"] is String && (answers["path"] as String).isNotEmpty) {
print("使用输入文件目录:${filePath}");
printFilesAync(filePath, cover);
} else if (!answers["confirm"] && answers["default"]) {
print("使用默认文件目录:${defaultPath}");
printFilesAync(defaultPath, cover);
} else {
print(format("{@red}放弃转换!{@normal}"));
}
}
void printFilesAync(String path, bool cover) async {
try {
var directory = new Directory(path);
List<FileSystemEntity> files = directory.listSync();
if (files.length == 0) {
print(format("{@yellow}目录为空!{@normal}"));
return;
}
for (var f in files) {
var bool = FileSystemEntity.isFileSync(f.path);
if (!bool) {
//print('1::${bool}::${f.path}::${files.length}');
await printFilesAync(f.path, cover);
} else if (f.path.indexOf('.dart') != -1) {
print('被转换的文件::${f.path}::${files.length}');
var newPath = (f.path).replaceAll(new RegExp('.dart'), '-copy.dart');
File newfile = new File(newPath);
File oldfile = new File(f.path);
File output = cover ? oldfile : newfile;
List<String> lines = oldfile.readAsLinesSync();
var result = '';
lines.forEach((l) => {
if (l.trim().indexOf('package:flutter/material.dart') >= 0)
{result += "import 'package:flutter_web/material.dart';\n"}
else if (l.trim().indexOf('package:flutter/widgets.dart') >= 0)
{result += "import 'package:flutter_web/widgets.dart';\n"}
else if (l.trim().indexOf('package:flutter/cupertino.dart') >= 0)
{result += "import 'package:flutter_web/cupertino.dart';\n"}
else if (l.trim().indexOf('package:flutter/services.dart') >= 0)
{result += "import 'package:flutter_web/services.dart';\n"}
else if (l.trim().indexOf('package:flutter/rendering.dart') >= 0)
{result += "import 'package:flutter_web/rendering.dart';\n"}
else if (l.trim().indexOf('dart:ui') >= 0)
{result += "import 'package:flutter_web_ui/ui.dart';\n"}
else
{result += '${l}\n'}
});
output.writeAsStringSync(result);
//newfile.writeAsStringSync(result);
///await newfile.create();
//await newfile.create();
///file.createSync();
///await oldfile.delete();
}
}
} catch (e) {
print(format("{@red}目录不存在!{@normal}") + ':${path}');
}
}

View File

@ -1,12 +1,13 @@
name: testCom
name: trans2fw
version: 0.0.1
description: 自动化 flutter native 项目转化成 flutter-web 项目
publish_to: none
dependencies:
args: any
dart_inquirer: any
console: any
path: any
executables:
main:
creatHtml:
handl:
build-fw:

View File

@ -1,11 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>testTile</title>
</head>
<body>
</body>
</html>