mirror of
https://github.com/alibaba/flutter-go.git
synced 2025-05-20 14:26:23 +08:00
add files
This commit is contained in:
10
.gitignore
vendored
Normal file
10
.gitignore
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
.idea/*
|
||||||
|
.DS_Store
|
||||||
|
.flutter-plugins
|
||||||
|
.packages
|
||||||
|
android/*
|
||||||
|
build/*
|
||||||
|
flutter_rookie_book.iml
|
||||||
|
flutter_rookie_book_android.iml
|
||||||
|
ios/*
|
||||||
|
pubspec.lock
|
160
README.md
Normal file
160
README.md
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
# flutter-common-widgets-app
|
||||||
|
|
||||||
|
### 使用背景
|
||||||
|
* 鉴于目前flutter官方庞大的小部件(widget)系统以及api文档,只有文字描述,而没有可视化实例。
|
||||||
|
* 我们开发这套app,可以系统的看到常用小部件(widget)的用法。
|
||||||
|
* 辅助初学者更快上手,flutter官方小部件(widget)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### 参考资料
|
||||||
|
|
||||||
|
* [flutter-widgets的官方库地址]( https://docs.flutter.kim/widgets/widgets-library.html )
|
||||||
|
* [flutter-widgets的官方目录集]( http://doc.flutter-dev.cn/widgets/ )
|
||||||
|
* [sqlitestudio 本地可视化工具] (https://sqlitestudio.pl/index.rvt)
|
||||||
|
|
||||||
|
### 分支命名及使用规范
|
||||||
|
|
||||||
|
* 分支命名规范
|
||||||
|
- 自己开发分支命名统一为 username ,如:yifeng
|
||||||
|
- 分支两条主线为 Master分支和develop分支
|
||||||
|
- Master作为发布分支,develop作为开发测试分支、自己开发分支从dev checkout出去,发布即 merge to master
|
||||||
|
|
||||||
|
* 分支合并规范
|
||||||
|
- 从最新的develop分支checkout出自己的开发分支
|
||||||
|
- 在自己开发开发分支开发完成后,先去develop分支pull最新代码,
|
||||||
|
- 将develop 分支最新代码 merge 到自己分支,确保无冲突
|
||||||
|
- 再切回develop分支merge自己开发分支代码,确保无冲突,且能正常运行
|
||||||
|
|
||||||
|
### commit 提交规范
|
||||||
|
* $git cz
|
||||||
|
|
||||||
|
* 用于说明 commit 的类别,只允许使用下面7个标识。
|
||||||
|
|
||||||
|
- feat:新功能(feature)
|
||||||
|
|
||||||
|
- fix:修补bug
|
||||||
|
|
||||||
|
- docs:文档(documentation)
|
||||||
|
|
||||||
|
- style: 格式(不影响代码运行的变动)
|
||||||
|
|
||||||
|
- refactor:重构(即不是新增功能,也不是修改bug的代码变动)
|
||||||
|
|
||||||
|
- test:增加测试
|
||||||
|
|
||||||
|
- chore:构建过程或辅助工具的变动
|
||||||
|
|
||||||
|
|
||||||
|
### 代码规范
|
||||||
|
* 文件命名规范
|
||||||
|
- 文件命名使用下划线命名法,如:hello_world
|
||||||
|
- 请使用英文进行命名,不允许使用拼音。命名要求具有可读性,尽量避免使用缩写与数字
|
||||||
|
- 未完待续
|
||||||
|
|
||||||
|
* 代码编码规范
|
||||||
|
- 文件编码统一使用 UTF-8 编码;
|
||||||
|
- 前端编码采用首字母小写驼峰法. Widget Class 必须采用首字母大写驼峰法.
|
||||||
|
|
||||||
|
### 文件目录结构(以LIb文件说明)
|
||||||
|
|
||||||
|
- lib
|
||||||
|
- main.dart 入口文件
|
||||||
|
- common 公共的method
|
||||||
|
- components widget
|
||||||
|
- generated
|
||||||
|
- model 存放模型, 不应该加入逻辑层
|
||||||
|
- router 路由
|
||||||
|
- views 展示界面
|
||||||
|
- widget (与components概念重合,废弃)
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
├── main.dart //入口文件
|
||||||
|
├── common 公共的method
|
||||||
|
│ ├── Style.dart
|
||||||
|
│ ├── eventBus.dart
|
||||||
|
│ ├── provider.dart
|
||||||
|
│ └── sql.dart
|
||||||
|
├── components //app展示框架用到的组件
|
||||||
|
│ ├── Input.dart
|
||||||
|
│ ├── List.dart
|
||||||
|
│ ├── Pagination.dart
|
||||||
|
│ ├── Pagination2.dart
|
||||||
|
│ ├── SearchInput.dart
|
||||||
|
│ └── homeBanner.dart
|
||||||
|
├── generated
|
||||||
|
│ └── i18n.dart
|
||||||
|
├── model //本地存放模型, 不应该加入逻辑层
|
||||||
|
│ ├── base.dart
|
||||||
|
│ ├── cat.dart
|
||||||
|
│ ├── story.dart
|
||||||
|
│ └── widget.dart
|
||||||
|
├── routers //路由
|
||||||
|
│ ├── application.dart
|
||||||
|
│ ├── router_handler.dart
|
||||||
|
│ └── routers.dart
|
||||||
|
├── views //app展示界面
|
||||||
|
│ ├── Detail.dart
|
||||||
|
│ ├── FirstPage.dart
|
||||||
|
│ ├── FourthPage.dart
|
||||||
|
│ ├── ThirdPage.dart
|
||||||
|
│ ├── category.dart
|
||||||
|
│ ├── demos
|
||||||
|
│ │ ├── home.dart
|
||||||
|
│ │ └── layout
|
||||||
|
│ │ ├── SamplePage.dart
|
||||||
|
│ │ └── layout_type.dart
|
||||||
|
│ └── widgetPage.dart
|
||||||
|
└── widgets
|
||||||
|
└── ... //下面详细说明
|
||||||
|
```
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
└── widgets // 对flutter所有元素和组件的分类
|
||||||
|
├── 404.dart
|
||||||
|
├── index.dart // widgets 的总入口文件
|
||||||
|
├── components // 组件的分类 (区别于上面的components)
|
||||||
|
│ └── index.dart
|
||||||
|
├── elements // 基础元素的分类
|
||||||
|
│ ├── index.dart // elements下的 elements 类型入口文件
|
||||||
|
│ ├── Form // elements下的 From 类型集合
|
||||||
|
│ │ ├── Button // button 元素,里面是 文件夹代表类名/index.dart
|
||||||
|
│ │ │ ├── FlatButton
|
||||||
|
│ │ │ │ └── index.dart
|
||||||
|
│ │ │ ├── RaisedButton
|
||||||
|
│ │ │ │ └── index.dart
|
||||||
|
│ │ │ └── index.dart
|
||||||
|
│ │ ├── CheckBox
|
||||||
|
│ │ ├── Input
|
||||||
|
│ │ ├── Radio
|
||||||
|
│ │ ├── Slider
|
||||||
|
│ │ ├── Switch
|
||||||
|
│ │ ├── Text
|
||||||
|
│ │ └── index.dart
|
||||||
|
│ ├── Frame // elements下的 Frame 类型集合
|
||||||
|
│ │ ├── Align
|
||||||
|
│ │ ├── Axis
|
||||||
|
│ │ ├── Box
|
||||||
|
│ │ ├── Expanded
|
||||||
|
│ │ ├── Layout
|
||||||
|
│ │ ├── Stack
|
||||||
|
│ │ ├── Table
|
||||||
|
│ │ └── spacing
|
||||||
|
│ └── Media // elements下的 Media 类型集合
|
||||||
|
│ ├── Canvas
|
||||||
|
│ ├── Icon
|
||||||
|
│ └── Image
|
||||||
|
└── themes
|
||||||
|
└── index.dart
|
||||||
|
```
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
widget 里的文件结构,用来存放封装的逻辑组件, 文件目录应为, 类比rax
|
||||||
|
- widget // widget 下详细元素或组件的目录结构
|
||||||
|
- hello-world // 例如
|
||||||
|
- mods // (可选, 子模块)
|
||||||
|
- mocks // (可选)
|
||||||
|
- utils // (可选, 存放暂时的私有method)
|
||||||
|
- schema
|
||||||
|
- index.dart
|
||||||
|
```
|
BIN
assets/app.db
Normal file
BIN
assets/app.db
Normal file
Binary file not shown.
BIN
docs/17_02_18__11_13_2018.jpg
Normal file
BIN
docs/17_02_18__11_13_2018.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 360 KiB |
BIN
docs/17_47_49__11_13_2018.jpg
Normal file
BIN
docs/17_47_49__11_13_2018.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 673 KiB |
BIN
docs/20_03_01__11_13_2018.jpg
Normal file
BIN
docs/20_03_01__11_13_2018.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 215 KiB |
BIN
docs/36B53C6F-98F1-452B-B45A-A93293CC6B3C.png
Normal file
BIN
docs/36B53C6F-98F1-452B-B45A-A93293CC6B3C.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 36 KiB |
23
lib/common/Style.dart
Normal file
23
lib/common/Style.dart
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
//颜色配置
|
||||||
|
class AppColor{
|
||||||
|
static const int white = 0xFFFFFFFF;
|
||||||
|
static const int mainTextColor = 0xFF121917;
|
||||||
|
static const int subTextColor = 0xff959595;
|
||||||
|
}
|
||||||
|
|
||||||
|
//文本设置
|
||||||
|
class AppText{
|
||||||
|
static const middleSize = 16.0;
|
||||||
|
|
||||||
|
static const middleText = TextStyle(
|
||||||
|
color: Color(AppColor.mainTextColor),
|
||||||
|
fontSize: middleSize,
|
||||||
|
);
|
||||||
|
|
||||||
|
static const middleSubText = TextStyle(
|
||||||
|
color: Color(AppColor.subTextColor),
|
||||||
|
fontSize: middleSize,
|
||||||
|
);
|
||||||
|
}
|
8
lib/common/eventBus.dart
Normal file
8
lib/common/eventBus.dart
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import 'package:event_bus/event_bus.dart';
|
||||||
|
|
||||||
|
EventBus eventBus = new EventBus();
|
||||||
|
|
||||||
|
class MyEvent {
|
||||||
|
String text;
|
||||||
|
MyEvent(this.text);
|
||||||
|
}
|
32
lib/common/provider.dart
Normal file
32
lib/common/provider.dart
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
import 'dart:io';
|
||||||
|
import 'dart:typed_data';
|
||||||
|
import 'package:path/path.dart';
|
||||||
|
import 'package:sqflite/sqflite.dart';
|
||||||
|
import 'package:flutter/services.dart' show rootBundle;
|
||||||
|
|
||||||
|
class Provider {
|
||||||
|
static Database db;
|
||||||
|
|
||||||
|
//初始化数据库
|
||||||
|
// isCreate 用永远 copy 一个新的数据库
|
||||||
|
Future init(bool isCreate) async {
|
||||||
|
String databasesPath = await getDatabasesPath();
|
||||||
|
String path = join(databasesPath,'flutter.db');
|
||||||
|
print("path ${path}");
|
||||||
|
|
||||||
|
if(db == null && isCreate){
|
||||||
|
ByteData data = await rootBundle.load(join("assets", "app.db"));
|
||||||
|
List<int> bytes = data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);
|
||||||
|
await new File(path).writeAsBytes(bytes);
|
||||||
|
|
||||||
|
db = await openDatabase(path,version: 2,onCreate : (Database db, int version) async{
|
||||||
|
print('db created version is $version');
|
||||||
|
},onOpen : (Database db) async{
|
||||||
|
print('new db opened');
|
||||||
|
});
|
||||||
|
}else{
|
||||||
|
print('Opening existing database');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
66
lib/common/sql.dart
Normal file
66
lib/common/sql.dart
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
import './provider.dart';
|
||||||
|
import 'dart:async';
|
||||||
|
import 'package:sqflite/sqflite.dart';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class BaseModel{
|
||||||
|
Database db;
|
||||||
|
final String table = '';
|
||||||
|
var query;
|
||||||
|
BaseModel(this.db){
|
||||||
|
query = db.query;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Sql extends BaseModel {
|
||||||
|
final String tableName;
|
||||||
|
|
||||||
|
Sql.setTable(String name)
|
||||||
|
: tableName = name,
|
||||||
|
super(Provider.db);
|
||||||
|
|
||||||
|
// sdf
|
||||||
|
Future<List> get() async{
|
||||||
|
return await this.query(tableName);
|
||||||
|
}
|
||||||
|
String getTableName () {
|
||||||
|
return tableName;
|
||||||
|
}
|
||||||
|
|
||||||
|
// condition: {}
|
||||||
|
Future<List> getByCondition({Map<dynamic, dynamic> conditions}) async {
|
||||||
|
if (conditions == null || conditions.isEmpty) {
|
||||||
|
return this.get();
|
||||||
|
}
|
||||||
|
String stringConditions = '';
|
||||||
|
|
||||||
|
int index = 0;
|
||||||
|
print("condition>>> $conditions");
|
||||||
|
conditions.forEach((key, value) {
|
||||||
|
if (value == null) {
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
print("$key value.runtimeType: ${value.runtimeType}");
|
||||||
|
if (value.runtimeType == String) {
|
||||||
|
stringConditions = '$stringConditions $key = "$value"';
|
||||||
|
}
|
||||||
|
if (value.runtimeType == int) {
|
||||||
|
stringConditions = '$stringConditions $key = $value';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index >= 0 && index < conditions.length -1) {
|
||||||
|
stringConditions = '$stringConditions and';
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
});
|
||||||
|
print("this is string condition for sql > $stringConditions");
|
||||||
|
|
||||||
|
return await this.query(tableName, where: stringConditions);
|
||||||
|
}
|
||||||
|
Future<Map<String, dynamic>> insert(Map<String, dynamic> json) async {
|
||||||
|
var id = await this.db.insert(tableName, json);
|
||||||
|
json['id'] = id;
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
}
|
26
lib/components/Input.dart
Normal file
26
lib/components/Input.dart
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class Input extends StatelessWidget {
|
||||||
|
Input({Key key, this.active}):super(key: key);
|
||||||
|
|
||||||
|
String active;
|
||||||
|
TextEditingController controller;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return new Column(
|
||||||
|
children: <Widget>[
|
||||||
|
new Container(
|
||||||
|
padding: new EdgeInsets.only(top:100.0),
|
||||||
|
child: new Text('这是一个组件')
|
||||||
|
),
|
||||||
|
new Container(
|
||||||
|
decoration: new BoxDecoration(border: new Border.all(width:1.0,color: Colors.blue)),
|
||||||
|
padding: new EdgeInsets.all(20.0),
|
||||||
|
child: new Text('来自输入框:'+active)
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
100
lib/components/List.dart
Normal file
100
lib/components/List.dart
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_rookie_book/views/Detail.dart';
|
||||||
|
|
||||||
|
class List extends StatefulWidget {
|
||||||
|
@override
|
||||||
|
State<StatefulWidget> createState() {
|
||||||
|
// TODO: implement createState
|
||||||
|
return new ListState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ListState extends State<List> {
|
||||||
|
@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,
|
||||||
|
),
|
||||||
|
) ;
|
||||||
|
}
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
68
lib/components/Pagination.dart
Normal file
68
lib/components/Pagination.dart
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
// 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/material.dart';
|
||||||
|
import './homeBanner.dart';
|
||||||
|
import '../model/story.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://pic2.zhimg.com/v2-6733af287e1220a041fc8dcef6be9dc9.jpg', 'type': 0, 'id': 9695909, 'ga_prefix': 091507, 'title': '从一个摄影师的角度,我来谈谈这一代 iPhone 是如何继续'},
|
||||||
|
{'image': 'https://pic1.zhimg.com/v2-c9a673ff89e5cc4c31ffcdf0c2d2f364.jpg', 'type': 0, 'id': 9695859, 'ga_prefix': 091517, 'title': '怪不得他能拿诺贝尔文学奖,一个月就能写出一部了不起的长篇小说'},
|
||||||
|
{'image': 'https://pic3.zhimg.com/v2-cf89ac60dbe59ab3ca908ff4bbf843e6.jpg', 'type': 0, 'id': 96956491409, 'title': '「死者被碎尸,警方排除他杀」,这并不荒唐'},
|
||||||
|
{'image': 'https://pic4.zhimg.com/v2-e21659cb7bc4ab43599772fa552e6e8b.jpg', 'type': 0, 'id': 9695816, 'ga_prefix': 091312, 'title': 'iPhone 5c、SE 接连失利之后,这次苹果还是「没长记性」'}
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
// @override
|
||||||
|
// void initState() { // 无状态widget 不会调用
|
||||||
|
// print('start');
|
||||||
|
// /// super.initState();
|
||||||
|
// arr.forEach((item) {
|
||||||
|
// bannerStories.add(StoryModel.fromJson(item));
|
||||||
|
// });
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
List<Widget> _PageSelector(BuildContext context) {
|
||||||
|
List<Widget> list = [];
|
||||||
|
print('start');
|
||||||
|
/// super.initState();
|
||||||
|
arr.forEach((item) {
|
||||||
|
bannerStories.add(StoryModel.fromJson(item));
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
if (icons.length > 0) {
|
||||||
|
list.add(HomeBanner(bannerStories, (story) {
|
||||||
|
/// _openStoryDetailPage(story);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return
|
||||||
|
Column(
|
||||||
|
//physics: AlwaysScrollableScrollPhysics(),
|
||||||
|
//padding: EdgeInsets.only(),
|
||||||
|
children: _PageSelector(context)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
112
lib/components/Pagination2.dart
Normal file
112
lib/components/Pagination2.dart
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
// 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/material.dart';
|
||||||
|
|
||||||
|
class _PageSelector extends StatelessWidget {
|
||||||
|
const _PageSelector({ this.icons });
|
||||||
|
|
||||||
|
final List<Icon> icons;
|
||||||
|
|
||||||
|
void _handleArrowButtonPress(BuildContext context, int delta) {
|
||||||
|
final TabController controller = DefaultTabController.of(context);
|
||||||
|
if (!controller.indexIsChanging)
|
||||||
|
controller.animateTo((controller.index + delta).clamp(0, icons.length - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final TabController controller = DefaultTabController.of(context);
|
||||||
|
final Color color = Theme.of(context).accentColor;
|
||||||
|
return new SafeArea(
|
||||||
|
top: false,
|
||||||
|
bottom: false,
|
||||||
|
child: new Column(
|
||||||
|
children: <Widget>[
|
||||||
|
new Expanded(
|
||||||
|
child: new IconTheme(
|
||||||
|
data: new IconThemeData(
|
||||||
|
size: 128.0,
|
||||||
|
color: color,
|
||||||
|
),
|
||||||
|
child: new TabBarView(
|
||||||
|
children: icons.map((Icon icon) {
|
||||||
|
return
|
||||||
|
new Align(
|
||||||
|
alignment: Alignment.topCenter,
|
||||||
|
child:new Container(
|
||||||
|
color: Colors.red,
|
||||||
|
width:300.0,
|
||||||
|
height:250.0,
|
||||||
|
padding: const EdgeInsets.all(12.0),
|
||||||
|
child: new Card(
|
||||||
|
color: Colors.yellow,
|
||||||
|
child: new Center(
|
||||||
|
child: icon,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}).toList()
|
||||||
|
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
new Container(
|
||||||
|
margin: const EdgeInsets.only(top: 16.0),
|
||||||
|
child: new Row(
|
||||||
|
children: <Widget>[
|
||||||
|
new IconButton(
|
||||||
|
icon: const Icon(Icons.chevron_left),
|
||||||
|
color: color,
|
||||||
|
onPressed: () { _handleArrowButtonPress(context, -1); },
|
||||||
|
tooltip: 'Page back'
|
||||||
|
),
|
||||||
|
new TabPageSelector(controller: controller),
|
||||||
|
new IconButton(
|
||||||
|
icon: const Icon(Icons.chevron_right),
|
||||||
|
color: color,
|
||||||
|
onPressed: () { _handleArrowButtonPress(context, 1); },
|
||||||
|
tooltip: 'Page forward'
|
||||||
|
)
|
||||||
|
],
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween
|
||||||
|
)
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Pagination2 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'),
|
||||||
|
];
|
||||||
|
|
||||||
|
// @override
|
||||||
|
// Widget build(BuildContext context) {
|
||||||
|
// return new Scaffold(
|
||||||
|
// appBar: new AppBar(title: const Text('Page selector')),
|
||||||
|
// body: new DefaultTabController(
|
||||||
|
// length: icons.length,
|
||||||
|
// child: new _PageSelector(icons: icons),
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return new DefaultTabController(
|
||||||
|
length: icons.length,
|
||||||
|
child: new _PageSelector(icons: icons),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
372
lib/components/SearchInput.dart
Normal file
372
lib/components/SearchInput.dart
Normal file
@ -0,0 +1,372 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import '../common/Style.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,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
final T value;
|
||||||
|
final String text;
|
||||||
|
final IconData icon;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return new Container(
|
||||||
|
child: new Row(
|
||||||
|
children: <Widget>[
|
||||||
|
new Container(width: 30.0, child: new Icon(icon)),
|
||||||
|
new Expanded(child: new Text(text, style: Theme.of(context).textTheme.subhead)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
height: 64.0,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
@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: _loading
|
||||||
|
? new Center(
|
||||||
|
child: new Padding(
|
||||||
|
padding: const EdgeInsets.only(top: 50.0),
|
||||||
|
child: new CircularProgressIndicator()
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: new SingleChildScrollView(
|
||||||
|
child: new Column(
|
||||||
|
children: results.map((MaterialSearchResult result) {
|
||||||
|
return new InkWell(
|
||||||
|
onTap: () => widget.onSelect(result.value),
|
||||||
|
child: result,
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
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(
|
||||||
|
child: new Row(
|
||||||
|
children: <Widget>[
|
||||||
|
new Padding(
|
||||||
|
padding: new EdgeInsets.only(right: 10.0, top: 3.0),
|
||||||
|
child: new Icon(Icons.search, size: 24.0, color: Theme.of(context).primaryColorDark),
|
||||||
|
),
|
||||||
|
new Expanded(
|
||||||
|
child: new MaterialSearchInput(
|
||||||
|
placeholder: '搜索 flutter 组件',
|
||||||
|
getResults: getResults,
|
||||||
|
)
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// wigdet干掉.=> componets
|
140
lib/components/homeBanner.dart
Normal file
140
lib/components/homeBanner.dart
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
import 'package:flutter/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: 22.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);
|
78
lib/generated/i18n.dart
Normal file
78
lib/generated/i18n.dart
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
// ignore_for_file: non_constant_identifier_names
|
||||||
|
// ignore_for_file: camel_case_types
|
||||||
|
// ignore_for_file: prefer_single_quotes
|
||||||
|
|
||||||
|
//This file is automatically generated. DO NOT EDIT, all your changes would be lost.
|
||||||
|
|
||||||
|
class S implements WidgetsLocalizations {
|
||||||
|
const S();
|
||||||
|
|
||||||
|
static const GeneratedLocalizationsDelegate delegate =
|
||||||
|
const GeneratedLocalizationsDelegate();
|
||||||
|
|
||||||
|
static S of(BuildContext context) =>
|
||||||
|
Localizations.of<S>(context, WidgetsLocalizations);
|
||||||
|
|
||||||
|
@override
|
||||||
|
TextDirection get textDirection => TextDirection.ltr;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class en extends S {
|
||||||
|
const en();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class GeneratedLocalizationsDelegate extends LocalizationsDelegate<WidgetsLocalizations> {
|
||||||
|
const GeneratedLocalizationsDelegate();
|
||||||
|
|
||||||
|
List<Locale> get supportedLocales {
|
||||||
|
return const <Locale>[
|
||||||
|
|
||||||
|
const Locale("en", ""),
|
||||||
|
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
LocaleResolutionCallback resolution({Locale fallback}) {
|
||||||
|
return (Locale locale, Iterable<Locale> supported) {
|
||||||
|
final Locale languageLocale = new Locale(locale.languageCode, "");
|
||||||
|
if (supported.contains(locale))
|
||||||
|
return locale;
|
||||||
|
else if (supported.contains(languageLocale))
|
||||||
|
return languageLocale;
|
||||||
|
else {
|
||||||
|
final Locale fallbackLocale = fallback ?? supported.first;
|
||||||
|
return fallbackLocale;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<WidgetsLocalizations> load(Locale locale) {
|
||||||
|
final String lang = getLang(locale);
|
||||||
|
switch (lang) {
|
||||||
|
|
||||||
|
case "en":
|
||||||
|
return new SynchronousFuture<WidgetsLocalizations>(const en());
|
||||||
|
|
||||||
|
default:
|
||||||
|
return new SynchronousFuture<WidgetsLocalizations>(const S());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool isSupported(Locale locale) => supportedLocales.contains(locale);
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool shouldReload(GeneratedLocalizationsDelegate old) => false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String getLang(Locale l) => l.countryCode != null && l.countryCode.isEmpty
|
||||||
|
? l.languageCode
|
||||||
|
: l.toString();
|
150
lib/main.dart
Normal file
150
lib/main.dart
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:fluro/fluro.dart';
|
||||||
|
import 'package:flutter/rendering.dart';
|
||||||
|
|
||||||
|
import 'views/FirstPage.dart';
|
||||||
|
import 'views/widgetPage.dart';
|
||||||
|
import 'views/ThirdPage.dart';
|
||||||
|
import 'views/FourthPage.dart';
|
||||||
|
import 'routers/routers.dart';
|
||||||
|
import 'routers/application.dart';
|
||||||
|
import 'common/provider.dart';
|
||||||
|
import 'model/widget.dart';
|
||||||
|
import 'package:flutter_rookie_book/components/SearchInput.dart';
|
||||||
|
import 'common/Style.dart';
|
||||||
|
|
||||||
|
class MyApp extends StatelessWidget {
|
||||||
|
MyApp() {
|
||||||
|
final router = new Router();
|
||||||
|
Routes.configureRoutes(router);
|
||||||
|
Application.router = router;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return new MaterialApp(
|
||||||
|
title: 'title',
|
||||||
|
theme: new ThemeData(
|
||||||
|
primarySwatch: Colors.blue,
|
||||||
|
),
|
||||||
|
home: new MyHomePage(),
|
||||||
|
onGenerateRoute: Application.router.generator,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var db;
|
||||||
|
|
||||||
|
void main() async{
|
||||||
|
|
||||||
|
final provider = new Provider();
|
||||||
|
await provider.init(true);
|
||||||
|
db = Provider.db;
|
||||||
|
runApp(new MyApp());
|
||||||
|
}
|
||||||
|
|
||||||
|
class MyHomePage extends StatefulWidget {
|
||||||
|
@override
|
||||||
|
State<StatefulWidget> createState() {
|
||||||
|
return _MyHomePageState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _MyHomePageState extends State<MyHomePage>
|
||||||
|
with SingleTickerProviderStateMixin {
|
||||||
|
TabController controller;
|
||||||
|
bool isSearch = false;
|
||||||
|
String data = '无';
|
||||||
|
String data2ThirdPage = '这是传给ThirdPage的值';
|
||||||
|
String appBarTitle = tabData[0]['text'];
|
||||||
|
static List tabData = [
|
||||||
|
{'text': '业界动态', 'icon': new Icon(Icons.language)},
|
||||||
|
{'text': 'WIDGET', 'icon': new Icon(Icons.extension)},
|
||||||
|
{'text': '官网地址', 'icon': new Icon(Icons.home)},
|
||||||
|
{'text': '关于手册', 'icon': new Icon(Icons.favorite)}
|
||||||
|
];
|
||||||
|
|
||||||
|
List<Widget> myTabs = [];
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
// TODO: implement initState
|
||||||
|
super.initState();
|
||||||
|
controller = new TabController(
|
||||||
|
initialIndex: 0, vsync: this, length: 4); // 这里的length 决定有多少个底导 submenus
|
||||||
|
for (int i = 0; i < tabData.length; i++) {
|
||||||
|
myTabs.add(new Tab(text: tabData[i]['text'], icon: tabData[i]['icon']));
|
||||||
|
}
|
||||||
|
controller.addListener(() {
|
||||||
|
if (controller.indexIsChanging) {
|
||||||
|
_onTabChange();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
controller.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
Widget buildSearchInput(){
|
||||||
|
return new SearchInput((value) async{
|
||||||
|
return null;
|
||||||
|
// if(value != ''){
|
||||||
|
// widgetModel = new WidgetModel(db);
|
||||||
|
// List<Map> list = await widgetModel.search(value);
|
||||||
|
// print('list $list');
|
||||||
|
// return list.map((item) => new MaterialSearchResult<String>(
|
||||||
|
// value: item['name'],
|
||||||
|
// text: item['name'] + ' ' + item['cnName'],
|
||||||
|
// )).toList();
|
||||||
|
// }else{
|
||||||
|
// return null;
|
||||||
|
// }
|
||||||
|
|
||||||
|
},(value){},(){});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return new Scaffold(
|
||||||
|
appBar: new AppBar(
|
||||||
|
// backgroundColor: new Color(AppColor.white),
|
||||||
|
title: buildSearchInput()),
|
||||||
|
body: new TabBarView(controller: controller, children: <Widget>[
|
||||||
|
new FirstPage(),
|
||||||
|
new WidgetPage(db),
|
||||||
|
new ThirdPage(
|
||||||
|
data2ThirdPage: data2ThirdPage,
|
||||||
|
callback: (val) => _onDataChange(val)),
|
||||||
|
new FourthPage()
|
||||||
|
]),
|
||||||
|
bottomNavigationBar: new Material(
|
||||||
|
color: const Color(0xFFF0EEEF), //底部导航栏主题颜色
|
||||||
|
child: new Container(
|
||||||
|
height: 65.0,
|
||||||
|
child: new TabBar(
|
||||||
|
controller: controller,
|
||||||
|
indicatorColor: Colors.blue, //tab标签的下划线颜色
|
||||||
|
labelColor: const Color(0xFF000000),
|
||||||
|
tabs: <Tab>[
|
||||||
|
new Tab(text: '业界动态', icon: new Icon(Icons.language)),
|
||||||
|
new Tab(text: '组件', icon: new Icon(Icons.extension)),
|
||||||
|
new Tab(text: '官网地址', icon: new Icon(Icons.home)),
|
||||||
|
new Tab(text: '关于手册', icon: new Icon(Icons.favorite)),
|
||||||
|
]))));
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onTabChange() {
|
||||||
|
this.setState(() {
|
||||||
|
appBarTitle = tabData[controller.index]['text'];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onDataChange(val) {
|
||||||
|
setState(() {
|
||||||
|
data = val;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
11
lib/model/base.dart
Normal file
11
lib/model/base.dart
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import 'package:sqflite/sqflite.dart';
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
class BaseModel{
|
||||||
|
Database db;
|
||||||
|
final String table = '';
|
||||||
|
var query;
|
||||||
|
BaseModel(this.db){
|
||||||
|
query = db.query;
|
||||||
|
}
|
||||||
|
}
|
108
lib/model/cat.dart
Normal file
108
lib/model/cat.dart
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
import 'base.dart';
|
||||||
|
import 'dart:async';
|
||||||
|
import 'dart:convert';
|
||||||
|
import '../common/sql.dart';
|
||||||
|
|
||||||
|
abstract class CatInterface{
|
||||||
|
int get id;
|
||||||
|
//类目名称
|
||||||
|
String get name;
|
||||||
|
//描述
|
||||||
|
String get desc;
|
||||||
|
//第几级类目,默认 1
|
||||||
|
int get depth;
|
||||||
|
//父类目id,没有为 0
|
||||||
|
int get parentId;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Cat implements CatInterface {
|
||||||
|
int id;
|
||||||
|
String name;
|
||||||
|
String desc;
|
||||||
|
int depth;
|
||||||
|
int parentId;
|
||||||
|
|
||||||
|
Cat({this.id, this.name, this.desc, this.depth, this.parentId});
|
||||||
|
|
||||||
|
Cat.fromJSON(Map json)
|
||||||
|
: id = json['id'],
|
||||||
|
name = json['name'],
|
||||||
|
desc = json['desc'],
|
||||||
|
depth = json['depth'],
|
||||||
|
parentId = json['parentId'];
|
||||||
|
|
||||||
|
String toString() {
|
||||||
|
return '(Cat $name)';
|
||||||
|
}
|
||||||
|
|
||||||
|
Map toMap() {
|
||||||
|
return {
|
||||||
|
'id': id,
|
||||||
|
'name': name,
|
||||||
|
'desc': desc,
|
||||||
|
'depth': depth,
|
||||||
|
'parentId': parentId
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Map toSqlCondition() {
|
||||||
|
Map _map = this.toMap();
|
||||||
|
Map condition = {};
|
||||||
|
_map.forEach((k, value) {
|
||||||
|
|
||||||
|
if (value != null) {
|
||||||
|
|
||||||
|
condition[k] = value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (condition.isEmpty) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return condition;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class CatControlModel{
|
||||||
|
final String table = 'cat';
|
||||||
|
Sql sql;
|
||||||
|
CatControlModel() {
|
||||||
|
sql = Sql.setTable(table);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 获取一级类目
|
||||||
|
Future<List> mainList() async{
|
||||||
|
List listJson = await sql.getByCondition(conditions: {'parentId': 0});
|
||||||
|
List<Cat> cats = listJson.map((json) {
|
||||||
|
return new Cat.fromJSON(json);
|
||||||
|
}).toList();
|
||||||
|
return cats;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取Cat不同深度与parent的列表
|
||||||
|
Future<List<Cat>> getList([Cat cat]) async{
|
||||||
|
|
||||||
|
|
||||||
|
if (cat == null) {
|
||||||
|
cat = new Cat(depth: 1, parentId: 0);
|
||||||
|
}
|
||||||
|
print("cat in getList ${cat.toMap()}");
|
||||||
|
|
||||||
|
List listJson = await sql.getByCondition(conditions: cat.toSqlCondition());
|
||||||
|
List<Cat> cats = listJson.map((json) {
|
||||||
|
return new Cat.fromJSON(json);
|
||||||
|
}).toList();
|
||||||
|
return cats;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 通过name获取Cat对象信息
|
||||||
|
Future<Cat> getCatByName(String name) async {
|
||||||
|
List json = await sql.getByCondition(conditions: {'name': name});
|
||||||
|
if (json.isEmpty) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new Cat.fromJSON(json.first);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
21
lib/model/story.dart
Normal file
21
lib/model/story.dart
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
class StoryModel {
|
||||||
|
final String title;
|
||||||
|
final String image;
|
||||||
|
final int id;
|
||||||
|
|
||||||
|
StoryModel(this.id, this.title, {this.image});
|
||||||
|
|
||||||
|
StoryModel.fromJson(Map<String, dynamic> json)
|
||||||
|
: this(json['id'], json['title'],
|
||||||
|
image: json['image'] != null ? json['image'] : (json['images'] != null
|
||||||
|
? json['images'][0]
|
||||||
|
: null));
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return {
|
||||||
|
'id': id,
|
||||||
|
'title': title,
|
||||||
|
'image': image
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
112
lib/model/widget.dart
Normal file
112
lib/model/widget.dart
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
import 'base.dart';
|
||||||
|
import 'dart:async';
|
||||||
|
import '../common/sql.dart';
|
||||||
|
import "package:flutter/material.dart";
|
||||||
|
|
||||||
|
abstract class WidgetInterface{
|
||||||
|
int get id;
|
||||||
|
//组件英文名
|
||||||
|
String get name;
|
||||||
|
//组件中文名
|
||||||
|
String get cnName;
|
||||||
|
//组件截图
|
||||||
|
String get image;
|
||||||
|
//组件markdown 文档
|
||||||
|
String get doc;
|
||||||
|
//类目 id
|
||||||
|
int get catId;
|
||||||
|
}
|
||||||
|
|
||||||
|
class WidgetPoint implements WidgetInterface{
|
||||||
|
int id;
|
||||||
|
//组件英文名
|
||||||
|
String name;
|
||||||
|
//组件中文名
|
||||||
|
String cnName;
|
||||||
|
//组件截图
|
||||||
|
String image;
|
||||||
|
// 路由地址
|
||||||
|
String routerName;
|
||||||
|
//组件markdown 文档
|
||||||
|
String doc;
|
||||||
|
//组件 demo ,多个以 , 分割
|
||||||
|
String demo;
|
||||||
|
//类目 id
|
||||||
|
int catId;
|
||||||
|
final WidgetBuilder buildRouter;
|
||||||
|
WidgetPoint({
|
||||||
|
this.id,
|
||||||
|
this.name,
|
||||||
|
this.cnName,
|
||||||
|
this.image,
|
||||||
|
this.doc,
|
||||||
|
this.catId,
|
||||||
|
this.routerName,
|
||||||
|
this.buildRouter
|
||||||
|
});
|
||||||
|
WidgetPoint.fromJSON(Map json)
|
||||||
|
: id = json['id'],
|
||||||
|
name = json['name'],
|
||||||
|
image = json['image'],
|
||||||
|
cnName = json['cnName'],
|
||||||
|
routerName = json['routerName'],
|
||||||
|
doc = json['doc'],
|
||||||
|
catId = json['catId'],
|
||||||
|
buildRouter = json['buildRouter'];
|
||||||
|
String toString() {
|
||||||
|
return '(WidgetPoint $name)';
|
||||||
|
}
|
||||||
|
|
||||||
|
Object toMap() {
|
||||||
|
return {
|
||||||
|
'id': id,
|
||||||
|
'name': name,
|
||||||
|
'cnName': cnName,
|
||||||
|
'image': image,
|
||||||
|
'doc': doc,
|
||||||
|
'catId': catId
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Map toSqlCondition() {
|
||||||
|
Map _map = this.toMap();
|
||||||
|
Map condition = {};
|
||||||
|
_map.forEach((k, value) {
|
||||||
|
|
||||||
|
if (value != null) {
|
||||||
|
|
||||||
|
condition[k] = value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (condition.isEmpty) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return condition;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class WidgetControlModel{
|
||||||
|
final String table = 'widget';
|
||||||
|
Sql sql;
|
||||||
|
WidgetControlModel() {
|
||||||
|
sql = Sql.setTable(table);
|
||||||
|
}
|
||||||
|
// 获取Widget不同条件的列表
|
||||||
|
Future<List<WidgetPoint>> getList(WidgetPoint widgetPoint) async{
|
||||||
|
List listJson = await sql.getByCondition(conditions: widgetPoint.toSqlCondition());
|
||||||
|
List<WidgetPoint> widgets = listJson.map((json) {
|
||||||
|
return new WidgetPoint.fromJSON(json);
|
||||||
|
}).toList();
|
||||||
|
print("widgets $widgets");
|
||||||
|
return widgets;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 通过name获取Cat对象信息
|
||||||
|
Future<WidgetPoint> getCatByName(String name) async {
|
||||||
|
List json = await sql.getByCondition(conditions: {'name': name});
|
||||||
|
if (json.isEmpty) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new WidgetPoint.fromJSON(json.first);
|
||||||
|
}
|
||||||
|
}
|
5
lib/routers/application.dart
Normal file
5
lib/routers/application.dart
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import 'package:fluro/fluro.dart';
|
||||||
|
|
||||||
|
class Application {
|
||||||
|
static Router router;
|
||||||
|
}
|
20
lib/routers/router_handler.dart
Normal file
20
lib/routers/router_handler.dart
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:fluro/fluro.dart';
|
||||||
|
import '../views/category.dart';
|
||||||
|
import '../widgets/404.dart';
|
||||||
|
|
||||||
|
var categoryHandler = new Handler(
|
||||||
|
handlerFunc: (BuildContext context, Map<String, List<String>> params) {
|
||||||
|
print("params $params");
|
||||||
|
String name = params["type"]?.first;
|
||||||
|
print("type::: $name");
|
||||||
|
|
||||||
|
return new CategoryHome(name);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
var widgetNotFoundHandler = new Handler(
|
||||||
|
handlerFunc: (BuildContext context, Map<String, List<String>> params) {
|
||||||
|
return new WidgetNotFound();
|
||||||
|
}
|
||||||
|
);
|
30
lib/routers/routers.dart
Normal file
30
lib/routers/routers.dart
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
|
||||||
|
import 'package:fluro/fluro.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import '../widgets/index.dart';
|
||||||
|
import '../model/widget.dart';
|
||||||
|
import './router_handler.dart';
|
||||||
|
|
||||||
|
class Routes {
|
||||||
|
static String root = "/";
|
||||||
|
|
||||||
|
static void configureRoutes(Router router) {
|
||||||
|
List widgetDemosList = new WidgetDemoList().getDemos();
|
||||||
|
router.notFoundHandler = new Handler(
|
||||||
|
handlerFunc: (BuildContext context, Map<String, List<String>> params) {
|
||||||
|
print("ROUTE WAS NOT FOUND !!!");
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
router.define('/category/:type', handler: categoryHandler);
|
||||||
|
router.define('/category/error/404', handler: widgetNotFoundHandler);
|
||||||
|
widgetDemosList.forEach((demo) {
|
||||||
|
Handler handler = new Handler(
|
||||||
|
handlerFunc: (BuildContext context, Map<String, List<String>> params) {
|
||||||
|
return demo.buildRouter(context);
|
||||||
|
});
|
||||||
|
router.define('${demo.routerName}', handler: handler);
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
22
lib/views/Detail.dart
Normal file
22
lib/views/Detail.dart
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class Detail extends StatelessWidget {
|
||||||
|
|
||||||
|
final String id ;
|
||||||
|
Detail(this.id) ;
|
||||||
|
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return new Scaffold(
|
||||||
|
appBar: new AppBar(
|
||||||
|
title: new Text('List Detail'),
|
||||||
|
),
|
||||||
|
body: new Center(
|
||||||
|
child: new Text('msg:'+ 'id='+id),
|
||||||
|
),
|
||||||
|
) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
38
lib/views/FirstPage.dart
Normal file
38
lib/views/FirstPage.dart
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_rookie_book/components/List.dart';
|
||||||
|
import 'package:flutter_rookie_book/components/Pagination.dart';
|
||||||
|
|
||||||
|
import '../common/sql.dart';
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
class FirstPage extends StatefulWidget {
|
||||||
|
@override
|
||||||
|
FirstPageState createState() => new FirstPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class FirstPageState extends State<FirstPage> {
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
// TODO: implement initState
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return new Column(
|
||||||
|
children: <Widget>[
|
||||||
|
new Container(
|
||||||
|
child: new Pagination(),
|
||||||
|
),
|
||||||
|
new Expanded(
|
||||||
|
child: new List(),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
22
lib/views/FourthPage.dart
Normal file
22
lib/views/FourthPage.dart
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import '../components/List.dart';
|
||||||
|
|
||||||
|
|
||||||
|
class FourthPage extends StatefulWidget {
|
||||||
|
@override
|
||||||
|
FourthPageState createState() => new FourthPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class FourthPageState extends State<FourthPage> {
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return new Container(
|
||||||
|
child: new List()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
69
lib/views/ThirdPage.dart
Normal file
69
lib/views/ThirdPage.dart
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import '../common/eventBus.dart';
|
||||||
|
|
||||||
|
class ThirdPage extends StatefulWidget {
|
||||||
|
ThirdPage({Key key, this.data2ThirdPage, this.callback}) : super(key: key);
|
||||||
|
final callback;
|
||||||
|
String data2ThirdPage;
|
||||||
|
|
||||||
|
@override
|
||||||
|
ThirdPageState createState() => new ThirdPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class ThirdPageState extends State<ThirdPage> {
|
||||||
|
|
||||||
|
String data = '';
|
||||||
|
String inputTxt;
|
||||||
|
TextEditingController controller = new TextEditingController();
|
||||||
|
|
||||||
|
void initState() {
|
||||||
|
//print('data4Two' + widget.data2ThirdPage);
|
||||||
|
data = widget.data2ThirdPage;
|
||||||
|
}
|
||||||
|
|
||||||
|
void firedA() {
|
||||||
|
widget.callback('$inputTxt');
|
||||||
|
}
|
||||||
|
|
||||||
|
void firedB() {
|
||||||
|
eventBus.fire(new MyEvent('$inputTxt'));
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onChanged(String value) {
|
||||||
|
setState(() {
|
||||||
|
inputTxt = value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return new Center(
|
||||||
|
child: new Column(children: <Widget>[
|
||||||
|
new Container(
|
||||||
|
padding: new EdgeInsets.only(bottom: 15.0),
|
||||||
|
child: new Text('子组件2'),
|
||||||
|
),
|
||||||
|
new Container(
|
||||||
|
padding: new EdgeInsets.only(bottom: 10.0),
|
||||||
|
child: new Text('父传子:' + data),
|
||||||
|
),
|
||||||
|
new Container(
|
||||||
|
margin: new EdgeInsets.only(bottom: 40.0),
|
||||||
|
child: new TextField(
|
||||||
|
controller: controller,
|
||||||
|
onChanged: _onChanged,
|
||||||
|
decoration: (new InputDecoration(labelText: '请输入你要发送的值')))),
|
||||||
|
new Container(
|
||||||
|
child: new RaisedButton(
|
||||||
|
onPressed: firedA, child: new Text('to父组件'))),
|
||||||
|
new Container(
|
||||||
|
child: new RaisedButton(
|
||||||
|
onPressed: firedB, child: new Text('to兄弟组件')))
|
||||||
|
]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
251
lib/views/category.dart
Normal file
251
lib/views/category.dart
Normal file
@ -0,0 +1,251 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import '../routers/application.dart';
|
||||||
|
import '../model/cat.dart';
|
||||||
|
import '../model/widget.dart';
|
||||||
|
import '../widgets/index.dart';
|
||||||
|
|
||||||
|
|
||||||
|
enum CateOrWigdet {
|
||||||
|
Cat,
|
||||||
|
WidgetDemo
|
||||||
|
}
|
||||||
|
class CategoryHome extends StatefulWidget {
|
||||||
|
CategoryHome(this.name);
|
||||||
|
final String name;
|
||||||
|
|
||||||
|
@override
|
||||||
|
_CategoryHome createState() => new _CategoryHome();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CategoryHome extends State<CategoryHome> {
|
||||||
|
String title = '';
|
||||||
|
// 显示列表 cat or widget;
|
||||||
|
List<Cat> categories = [];
|
||||||
|
List<WidgetPoint> widgetPoints = [];
|
||||||
|
List<Cat> catHistory = new List();
|
||||||
|
|
||||||
|
CatControlModel catControl = new CatControlModel();
|
||||||
|
WidgetControlModel widgetControl = new WidgetControlModel();
|
||||||
|
// 所有的可用demos;
|
||||||
|
List widgetDemosList = new WidgetDemoList().getDemos();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
// 初始化加入顶级的name
|
||||||
|
this.getCatByName(widget.name).then((Cat cat) {
|
||||||
|
catHistory.add(cat);
|
||||||
|
searchCatOrWigdet();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Cat> getCatByName(String name) async {
|
||||||
|
return await catControl.getCatByName(name);
|
||||||
|
}
|
||||||
|
Future<bool> back() {
|
||||||
|
if (catHistory.length == 1) {
|
||||||
|
return Future<bool>.value(true);
|
||||||
|
}
|
||||||
|
catHistory.removeLast();
|
||||||
|
searchCatOrWigdet();
|
||||||
|
return Future<bool>.value(false);
|
||||||
|
|
||||||
|
}
|
||||||
|
void go(Cat cat) {
|
||||||
|
catHistory.add(cat);
|
||||||
|
searchCatOrWigdet();
|
||||||
|
}
|
||||||
|
void searchCatOrWigdet() async {
|
||||||
|
// 假设进入这个界面的parent一定存在
|
||||||
|
Cat parentCat = catHistory.last;
|
||||||
|
|
||||||
|
int depth = catHistory.length;
|
||||||
|
|
||||||
|
// 继续搜索显示下一级depth: depth + 1, parentId: parentCat.id
|
||||||
|
List<Cat> _categories = await catControl.getList(new Cat(parentId: parentCat.id, depth: depth + 1));
|
||||||
|
List<WidgetPoint> _widgetPoints = new List();
|
||||||
|
if (_categories.isEmpty) {
|
||||||
|
_widgetPoints = await widgetControl.getList(new WidgetPoint(catId: parentCat.id));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
this.setState(() {
|
||||||
|
categories = _categories;
|
||||||
|
title = parentCat.name;
|
||||||
|
widgetPoints = _widgetPoints;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void onCatgoryTap(Cat cat) {
|
||||||
|
go(cat);
|
||||||
|
}
|
||||||
|
void onWidgetTap(WidgetPoint widgetPoint) {
|
||||||
|
String targetName = widgetPoint.name;
|
||||||
|
String targetRouter = '/category/error/404';
|
||||||
|
widgetDemosList.forEach((item) {
|
||||||
|
if (item.name == targetName) {
|
||||||
|
targetRouter = item.routerName;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
print("router> ${targetRouter}");
|
||||||
|
Application.router.navigateTo(context, "${targetRouter}");
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text(title),
|
||||||
|
),
|
||||||
|
body: WillPopScope(
|
||||||
|
onWillPop: () {
|
||||||
|
return back();
|
||||||
|
},
|
||||||
|
child: new Container(
|
||||||
|
child: new CategoryOrWidgetList(
|
||||||
|
categorys: categories,
|
||||||
|
widgetPoints: widgetPoints,
|
||||||
|
onCatgoryTap: onCatgoryTap,
|
||||||
|
onWidgetTap: onWidgetTap
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class CategoryOrWidgetList extends StatelessWidget {
|
||||||
|
|
||||||
|
List<Cat> categorys = [];
|
||||||
|
List<WidgetPoint> widgetPoints = [];
|
||||||
|
|
||||||
|
var onCatgoryTap;
|
||||||
|
var onWidgetTap;
|
||||||
|
CategoryOrWidgetList({
|
||||||
|
this.categorys,
|
||||||
|
this.widgetPoints,
|
||||||
|
this.onCatgoryTap,
|
||||||
|
this.onWidgetTap,
|
||||||
|
});
|
||||||
|
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
print("categorys $categorys");
|
||||||
|
return GridView.builder(
|
||||||
|
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||||
|
crossAxisCount: 2, //每行2个
|
||||||
|
mainAxisSpacing: 0.0, //主轴(竖直)方向间距
|
||||||
|
crossAxisSpacing: 0.0, //纵轴(水平)方向间距
|
||||||
|
childAspectRatio: 0.8 //纵轴缩放比例
|
||||||
|
),
|
||||||
|
itemCount: widgetPoints.length == 0 ? categorys.length : widgetPoints.length,
|
||||||
|
itemBuilder: (BuildContext context, int index) {
|
||||||
|
if (widgetPoints.length > 0) {
|
||||||
|
return new ListItemWidget(
|
||||||
|
widgetPoint: widgetPoints[index],
|
||||||
|
onTap: () {
|
||||||
|
onWidgetTap(widgetPoints[index]);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return new ListCatWidget(
|
||||||
|
cat: categorys[index],
|
||||||
|
onTap: () {
|
||||||
|
onCatgoryTap(categorys[index]);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class ListCatWidget extends StatelessWidget {
|
||||||
|
final Cat cat;
|
||||||
|
final VoidCallback onTap;
|
||||||
|
|
||||||
|
ListCatWidget({
|
||||||
|
this.cat,
|
||||||
|
this.onTap
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return new Container(
|
||||||
|
color: Colors.green,
|
||||||
|
child: Container(
|
||||||
|
decoration: new BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
border: Border(
|
||||||
|
right: const BorderSide(width: 1.0, color: const Color(0xFFFF000000)),
|
||||||
|
bottom: const BorderSide(width: 1.0, color: const Color(0xFFFF000000)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: new RaisedButton(
|
||||||
|
onPressed: () {
|
||||||
|
onTap();
|
||||||
|
},
|
||||||
|
child: new Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: <Widget>[
|
||||||
|
Icon(
|
||||||
|
Icons.add
|
||||||
|
),
|
||||||
|
Text(cat.name),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class ListItemWidget extends StatelessWidget {
|
||||||
|
final WidgetPoint widgetPoint;
|
||||||
|
final VoidCallback onTap;
|
||||||
|
|
||||||
|
ListItemWidget({
|
||||||
|
this.widgetPoint,
|
||||||
|
this.onTap
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return new Container(
|
||||||
|
color: Colors.green,
|
||||||
|
child: Container(
|
||||||
|
decoration: new BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
border: Border(
|
||||||
|
right: const BorderSide(width: 1.0, color: const Color(0xFFFF000000)),
|
||||||
|
bottom: const BorderSide(width: 1.0, color: const Color(0xFFFF000000)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: new RaisedButton(
|
||||||
|
onPressed: () {
|
||||||
|
onTap();
|
||||||
|
},
|
||||||
|
child: new Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: <Widget>[
|
||||||
|
Icon(
|
||||||
|
Icons.add
|
||||||
|
),
|
||||||
|
Text(widgetPoint.name),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
119
lib/views/widgetPage.dart
Normal file
119
lib/views/widgetPage.dart
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import '../routers/application.dart';
|
||||||
|
import '../model/cat.dart';
|
||||||
|
import '../widgets/index.dart';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class WidgetPage extends StatefulWidget {
|
||||||
|
final db;
|
||||||
|
final CatControlModel catModel;
|
||||||
|
WidgetPage(this.db): catModel = new CatControlModel(),super();
|
||||||
|
|
||||||
|
@override
|
||||||
|
SecondPageState createState() => new SecondPageState(catModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
class SecondPageState extends State<WidgetPage> {
|
||||||
|
CatControlModel catModel;
|
||||||
|
SecondPageState(this.catModel): super();
|
||||||
|
|
||||||
|
TextEditingController controller;
|
||||||
|
String active = 'test';
|
||||||
|
String data = '无';
|
||||||
|
|
||||||
|
List<Cat> categories = [];
|
||||||
|
|
||||||
|
|
||||||
|
void initState() {
|
||||||
|
renderCats();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void renderCats(){
|
||||||
|
catModel.getList().then((List data){
|
||||||
|
if(data.isNotEmpty){
|
||||||
|
setState(() {
|
||||||
|
categories = data;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
if (categories.length == 0) {
|
||||||
|
return new Container();
|
||||||
|
}
|
||||||
|
print("categories in widgetPage : ${categories[0]}");
|
||||||
|
return GridView.builder(
|
||||||
|
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||||
|
crossAxisCount: 2, //每行2个
|
||||||
|
mainAxisSpacing: 0.0, //主轴(竖直)方向间距
|
||||||
|
crossAxisSpacing: 0.0, //纵轴(水平)方向间距
|
||||||
|
childAspectRatio: 0.8 //纵轴缩放比例
|
||||||
|
),
|
||||||
|
itemCount: categories.length,
|
||||||
|
itemBuilder: (BuildContext context, int index) {
|
||||||
|
return new ListItemWidget(
|
||||||
|
category: categories[index],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onChanged(String value) {
|
||||||
|
setState(() {
|
||||||
|
active = value;
|
||||||
|
data = '90';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class ListItemWidget extends StatelessWidget {
|
||||||
|
|
||||||
|
final Cat category;
|
||||||
|
|
||||||
|
ListItemWidget({this.category});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return new Container(
|
||||||
|
color: Colors.green,
|
||||||
|
child: Container(
|
||||||
|
decoration: new BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
border: Border(
|
||||||
|
right: const BorderSide(width: 1.0, color: const Color(0xFFFF000000)),
|
||||||
|
bottom: const BorderSide(width: 1.0, color: const Color(0xFFFF000000)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: new RaisedButton(
|
||||||
|
onPressed: () {
|
||||||
|
Application.router.navigateTo(context, "/category/${category.name}");
|
||||||
|
// Application.router.navigateTo(context, "/category/${category.name}");
|
||||||
|
},
|
||||||
|
child: new Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: <Widget>[
|
||||||
|
Icon(
|
||||||
|
Icons.add,
|
||||||
|
),
|
||||||
|
Text(category.name),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
16
lib/widgets/404.dart
Normal file
16
lib/widgets/404.dart
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
|
||||||
|
class WidgetNotFound extends StatelessWidget {
|
||||||
|
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text("widget not found"),
|
||||||
|
),
|
||||||
|
body: Container(
|
||||||
|
child: new Text("widget not found")
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
0
lib/widgets/components/index.dart
Normal file
0
lib/widgets/components/index.dart
Normal file
20
lib/widgets/elements/Form/Button/FlatButton/index.dart
Normal file
20
lib/widgets/elements/Form/Button/FlatButton/index.dart
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class Demo extends StatefulWidget {
|
||||||
|
static const String routeName = '/element/Form/Button/FlatButton';
|
||||||
|
_Demo createState() => _Demo();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _Demo extends State<Demo> {
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text("FlatButton"),
|
||||||
|
),
|
||||||
|
body: Container(
|
||||||
|
child: RaisedButton(onPressed: () {}, child: Text("FlatButton"))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
21
lib/widgets/elements/Form/Button/RaisedButton/index.dart
Normal file
21
lib/widgets/elements/Form/Button/RaisedButton/index.dart
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class Demo extends StatefulWidget {
|
||||||
|
static const String routeName = '/element/Form/Button/RaisedButton';
|
||||||
|
_Demo createState() => _Demo();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _Demo extends State<Demo> {
|
||||||
|
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text("FlatButton"),
|
||||||
|
),
|
||||||
|
body: Container(
|
||||||
|
child: RaisedButton(onPressed: () {}, child: Text("BUtton"))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
19
lib/widgets/elements/Form/Button/index.dart
Normal file
19
lib/widgets/elements/Form/Button/index.dart
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import '../../../../model/widget.dart';
|
||||||
|
import "package:flutter/material.dart";
|
||||||
|
|
||||||
|
import 'FlatButton/index.dart' as FlatButton;
|
||||||
|
import 'RaisedButton/index.dart' as RaisedButton;
|
||||||
|
|
||||||
|
|
||||||
|
List<WidgetPoint> widgetPoints = [
|
||||||
|
WidgetPoint(
|
||||||
|
name: 'FlatButton',
|
||||||
|
routerName: FlatButton.Demo.routeName,
|
||||||
|
buildRouter: (BuildContext context) => FlatButton.Demo(),
|
||||||
|
),
|
||||||
|
WidgetPoint(
|
||||||
|
name: 'RaisedButton',
|
||||||
|
routerName: RaisedButton.Demo.routeName,
|
||||||
|
buildRouter: (BuildContext context) => RaisedButton.Demo(),
|
||||||
|
),
|
||||||
|
];
|
1
lib/widgets/elements/Form/CheckBox/index.dart
Normal file
1
lib/widgets/elements/Form/CheckBox/index.dart
Normal file
@ -0,0 +1 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
14
lib/widgets/elements/Form/Input/TextField/index.dart
Normal file
14
lib/widgets/elements/Form/Input/TextField/index.dart
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class Demo extends StatefulWidget {
|
||||||
|
_Demo createState() => _Demo();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _Demo extends State<Demo> {
|
||||||
|
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
child: TextField()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
1
lib/widgets/elements/Form/Input/index.dart
Normal file
1
lib/widgets/elements/Form/Input/index.dart
Normal file
@ -0,0 +1 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
1
lib/widgets/elements/Form/Radio/index.dart
Normal file
1
lib/widgets/elements/Form/Radio/index.dart
Normal file
@ -0,0 +1 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
1
lib/widgets/elements/Form/Slider/index.dart
Normal file
1
lib/widgets/elements/Form/Slider/index.dart
Normal file
@ -0,0 +1 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
1
lib/widgets/elements/Form/Switch/index.dart
Normal file
1
lib/widgets/elements/Form/Switch/index.dart
Normal file
@ -0,0 +1 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
20
lib/widgets/elements/Form/Text/RichText/index.dart
Normal file
20
lib/widgets/elements/Form/Text/RichText/index.dart
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class Demo extends StatefulWidget {
|
||||||
|
static const String routeName = '/element/Form/Text/RichText';
|
||||||
|
_Demo createState() => _Demo();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _Demo extends State<Demo> {
|
||||||
|
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text("FlatButton"),
|
||||||
|
),
|
||||||
|
body: Container(
|
||||||
|
child: Text("this is RichText")
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
20
lib/widgets/elements/Form/Text/Text/index.dart
Normal file
20
lib/widgets/elements/Form/Text/Text/index.dart
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class Demo extends StatefulWidget {
|
||||||
|
static const String routeName = '/element/Form/Text/Text';
|
||||||
|
_Demo createState() => _Demo();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _Demo extends State<Demo> {
|
||||||
|
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text("FlatButton"),
|
||||||
|
),
|
||||||
|
body: Container(
|
||||||
|
child: Text("this is Text")
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
19
lib/widgets/elements/Form/Text/index.dart
Normal file
19
lib/widgets/elements/Form/Text/index.dart
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import '../../../../model/widget.dart';
|
||||||
|
import "package:flutter/material.dart";
|
||||||
|
|
||||||
|
import 'RichText/index.dart' as RichText;
|
||||||
|
import 'Text/index.dart' as Text;
|
||||||
|
|
||||||
|
|
||||||
|
List<WidgetPoint> widgetPoints = [
|
||||||
|
WidgetPoint(
|
||||||
|
name: 'RichText',
|
||||||
|
routerName: RichText.Demo.routeName,
|
||||||
|
buildRouter: (BuildContext context) => RichText.Demo(),
|
||||||
|
),
|
||||||
|
WidgetPoint(
|
||||||
|
name: 'Text',
|
||||||
|
routerName: Text.Demo.routeName,
|
||||||
|
buildRouter: (BuildContext context) => Text.Demo(),
|
||||||
|
),
|
||||||
|
];
|
9
lib/widgets/elements/Form/index.dart
Normal file
9
lib/widgets/elements/Form/index.dart
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import 'Button/index.dart' as Button;
|
||||||
|
import 'Text/index.dart' as Text;
|
||||||
|
|
||||||
|
List getWidgets() {
|
||||||
|
List result = [];
|
||||||
|
result.addAll(Button.widgetPoints);
|
||||||
|
result.addAll(Text.widgetPoints);
|
||||||
|
return result;
|
||||||
|
}
|
1
lib/widgets/elements/Frame/Align/index.dart
Normal file
1
lib/widgets/elements/Frame/Align/index.dart
Normal file
@ -0,0 +1 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
1
lib/widgets/elements/Frame/Axis/index.dart
Normal file
1
lib/widgets/elements/Frame/Axis/index.dart
Normal file
@ -0,0 +1 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
1
lib/widgets/elements/Frame/Box/index.dart
Normal file
1
lib/widgets/elements/Frame/Box/index.dart
Normal file
@ -0,0 +1 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
1
lib/widgets/elements/Frame/Expanded/index.dart
Normal file
1
lib/widgets/elements/Frame/Expanded/index.dart
Normal file
@ -0,0 +1 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
1
lib/widgets/elements/Frame/Layout/index.dart
Normal file
1
lib/widgets/elements/Frame/Layout/index.dart
Normal file
@ -0,0 +1 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
1
lib/widgets/elements/Frame/Stack/index.dart
Normal file
1
lib/widgets/elements/Frame/Stack/index.dart
Normal file
@ -0,0 +1 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
1
lib/widgets/elements/Frame/Table/index.dart
Normal file
1
lib/widgets/elements/Frame/Table/index.dart
Normal file
@ -0,0 +1 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
1
lib/widgets/elements/Frame/spacing/index.dart
Normal file
1
lib/widgets/elements/Frame/spacing/index.dart
Normal file
@ -0,0 +1 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
1
lib/widgets/elements/Media/Canvas/index.dart
Normal file
1
lib/widgets/elements/Media/Canvas/index.dart
Normal file
@ -0,0 +1 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
1
lib/widgets/elements/Media/Icon/index.dart
Normal file
1
lib/widgets/elements/Media/Icon/index.dart
Normal file
@ -0,0 +1 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
1
lib/widgets/elements/Media/Image/index.dart
Normal file
1
lib/widgets/elements/Media/Image/index.dart
Normal file
@ -0,0 +1 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
7
lib/widgets/elements/index.dart
Normal file
7
lib/widgets/elements/index.dart
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import 'Form/index.dart' as Form;
|
||||||
|
|
||||||
|
List getWidgets() {
|
||||||
|
List result = [];
|
||||||
|
result.addAll(Form.getWidgets());
|
||||||
|
return result;
|
||||||
|
}
|
8
lib/widgets/index.dart
Normal file
8
lib/widgets/index.dart
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import 'elements/index.dart' as elements;
|
||||||
|
|
||||||
|
class WidgetDemoList {
|
||||||
|
WidgetDemoList();
|
||||||
|
List getDemos() {
|
||||||
|
return elements.getWidgets();
|
||||||
|
}
|
||||||
|
}
|
0
lib/widgets/themes/index.dart
Normal file
0
lib/widgets/themes/index.dart
Normal file
72
pubspec.yaml
Normal file
72
pubspec.yaml
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
name: flutter_rookie_book
|
||||||
|
description: flutter_rookie_book
|
||||||
|
|
||||||
|
# The following defines the version and build number for your application.
|
||||||
|
# A version number is three numbers separated by dots, like 1.2.43
|
||||||
|
# followed by an optional build number separated by a +.
|
||||||
|
# Both the version and the builder number may be overridden in flutter
|
||||||
|
# build by specifying --build-name and --build-number, respectively.
|
||||||
|
# Read more about versioning at semver.org.
|
||||||
|
version: 0.0.3
|
||||||
|
|
||||||
|
environment:
|
||||||
|
sdk: ">=2.0.0-dev.68.0 <3.0.0"
|
||||||
|
|
||||||
|
dependencies:
|
||||||
|
flutter:
|
||||||
|
sdk: flutter
|
||||||
|
|
||||||
|
# The following adds the Cupertino Icons font to your application.
|
||||||
|
# Use with the CupertinoIcons class for iOS style icons.
|
||||||
|
cupertino_icons: ^0.1.2
|
||||||
|
event_bus: ^1.0.1
|
||||||
|
fluro: ^1.3.4
|
||||||
|
image_picker: ^0.4.10
|
||||||
|
sqflite: ^0.12.1
|
||||||
|
dev_dependencies:
|
||||||
|
flutter_test:
|
||||||
|
sdk: flutter
|
||||||
|
|
||||||
|
|
||||||
|
# For information on the generic Dart part of this file, see the
|
||||||
|
# following page: https://www.dartlang.org/tools/pub/pubspec
|
||||||
|
|
||||||
|
# The following section is specific to Flutter.
|
||||||
|
flutter:
|
||||||
|
|
||||||
|
# The following line ensures that the Material Icons font is
|
||||||
|
# included with your application, so that you can use the icons in
|
||||||
|
# the material Icons class.
|
||||||
|
uses-material-design: true
|
||||||
|
assets:
|
||||||
|
- assets/app.db
|
||||||
|
# To add assets to your application, add an assets section, like this:
|
||||||
|
# assets:
|
||||||
|
# - images/a_dot_burr.jpeg
|
||||||
|
# - images/a_dot_ham.jpeg
|
||||||
|
|
||||||
|
# An image asset can refer to one or more resolution-specific "variants", see
|
||||||
|
# https://flutter.io/assets-and-images/#resolution-aware.
|
||||||
|
|
||||||
|
# For details regarding adding assets from package dependencies, see
|
||||||
|
# https://flutter.io/assets-and-images/#from-packages
|
||||||
|
|
||||||
|
# To add custom fonts to your application, add a fonts section here,
|
||||||
|
# in this "flutter" section. Each entry in this list should have a
|
||||||
|
# "family" key with the font family name, and a "fonts" key with a
|
||||||
|
# list giving the asset and other descriptors for the font. For
|
||||||
|
# example:
|
||||||
|
# fonts:
|
||||||
|
# - family: Schyler
|
||||||
|
# fonts:
|
||||||
|
# - asset: fonts/Schyler-Regular.ttf
|
||||||
|
# - asset: fonts/Schyler-Italic.ttf
|
||||||
|
# style: italic
|
||||||
|
# - family: Trajan Pro
|
||||||
|
# fonts:
|
||||||
|
# - asset: fonts/TrajanPro.ttf
|
||||||
|
# - asset: fonts/TrajanPro_Bold.ttf
|
||||||
|
# weight: 700
|
||||||
|
#
|
||||||
|
# For details regarding fonts from package dependencies,
|
||||||
|
# see https://flutter.io/custom-fonts/#from-packages
|
1
res/values/strings_en.arb
Normal file
1
res/values/strings_en.arb
Normal file
@ -0,0 +1 @@
|
|||||||
|
{}
|
0
test/imp.dart
Normal file
0
test/imp.dart
Normal file
1
test/imp2.dart
Normal file
1
test/imp2.dart
Normal file
@ -0,0 +1 @@
|
|||||||
|
var router = [12,13,14];
|
0
test/test.dart
Normal file
0
test/test.dart
Normal file
29
test/widget_test.dart
Normal file
29
test/widget_test.dart
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
// This is a basic Flutter widget test.
|
||||||
|
// To perform an interaction with a widget in your test, use the WidgetTester utility that Flutter
|
||||||
|
// provides. For example, you can send tap and scroll gestures. You can also use WidgetTester to
|
||||||
|
// find child widgets in the widget tree, read text, and verify that the values of widget properties
|
||||||
|
// are correct.
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
|
import 'package:flutter_rookie_book/main.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
|
||||||
|
// Build our app and trigger a frame.
|
||||||
|
await tester.pumpWidget(new MyApp());
|
||||||
|
|
||||||
|
// Verify that our counter starts at 0.
|
||||||
|
expect(find.text('0'), findsOneWidget);
|
||||||
|
expect(find.text('1'), findsNothing);
|
||||||
|
|
||||||
|
// Tap the '+' icon and trigger a frame.
|
||||||
|
await tester.tap(find.byIcon(Icons.add));
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
// Verify that our counter has incremented.
|
||||||
|
expect(find.text('0'), findsNothing);
|
||||||
|
expect(find.text('1'), findsOneWidget);
|
||||||
|
});
|
||||||
|
}
|
Reference in New Issue
Block a user