Merge branch 'develop' of github.com:alibaba/flutter-common-widgets-app into develop

This commit is contained in:
sanfan.hx
2019-01-15 10:30:15 +08:00
24 changed files with 837 additions and 83 deletions

BIN
assets/images/calendar.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 555 B

BIN
assets/images/house.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 978 B

BIN
assets/images/p1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

BIN
assets/images/p2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 853 KiB

BIN
assets/images/p3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 871 KiB

BIN
assets/images/plane.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -14,8 +14,6 @@ import 'package:flutter/services.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:flutter/material.dart';
const String _kStartTag = '// START ';
const String _kEndTag = '// END';
Map<String, String> _exampleCode;
String _code;
@ -38,7 +36,6 @@ Future<void> _parseExampleCode(context,String filePath, AssetBundle bundle) asyn
try {
code = await bundle.loadString('lib/widgets/$filePath');
} catch (err) {
print('${Application.github['widgetsURL']} $filePath');
Navigator.of(context).pop();
_launchURL(Application.github['widgetsURL'] + filePath);
}

View File

@ -1,5 +1,14 @@
/*
* @Author: 一凨
* @Date: 2019-01-14 17:53:54
* @Last Modified by: 一凨
* @Last Modified time: 2019-01-14 17:57:51
*/
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';
import '../routers/application.dart';
import '../routers/routers.dart';
import 'dart:core';
class ListViewItem extends StatelessWidget {
final String itemUrl;
@ -9,15 +18,6 @@ class ListViewItem extends StatelessWidget {
const ListViewItem({Key key, this.itemUrl, this.itemTitle, this.data})
: super(key: key);
void _launchURL(String url, BuildContext context) async {
if (await canLaunch(url)) {
await launch(url);
} else {
throw 'Could not launch $url';
}
}
@override
Widget build(BuildContext context) {
@ -27,7 +27,8 @@ class ListViewItem extends StatelessWidget {
margin: new EdgeInsets.symmetric(horizontal: 10.0, vertical: 6.0),
child: ListTile(
onTap: () {
_launchURL(itemUrl, context);
// _launchURL(itemUrl, context);
Application.router.navigateTo(context, '${Routes.webViewPage}?title=${Uri.encodeComponent(itemTitle)}&url=${Uri.encodeComponent(itemUrl)}');
},
title: Padding(
child: Text(

View File

@ -46,7 +46,6 @@ class Provider {
for(int i = 0; i < expectTables.length; i++) {
if (!tables.contains(expectTables[i])) {
print("table lost in app");
return false;
}
}

View File

@ -4,17 +4,14 @@
* 新widget详情页模板
*/
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';
import '../routers/application.dart';
import '../routers/routers.dart';
import '../components/markdown.dart';
import '../model/collection.dart';
import '../widgets/index.dart';
import 'package:fluttertoast/fluttertoast.dart';
import '../event/event-bus.dart';
import '../event/event-model.dart';
import './full_screen_code_dialog.dart';
import '../routers/application.dart';
import '../routers/routers.dart';
import 'dart:core';
class WidgetDemo extends StatefulWidget {
@ -40,10 +37,9 @@ class WidgetDemo extends StatefulWidget {
class _WidgetDemoState extends State<WidgetDemo> {
bool _hasCollected = false;
CollectionControlModel _collectionControl = new CollectionControlModel();
Color _collectionColor;
var _collectionIcons;
List widgetDemosList = new WidgetDemoList().getDemos();
String _router = '';
String _collText = '';
void showInSnackBar(String value) {
Fluttertoast.showToast(
@ -55,13 +51,6 @@ class _WidgetDemoState extends State<WidgetDemo> {
textColor: Colors.white);
}
void _launchURL(String url) async {
if (await canLaunch(url)) {
await launch(url);
} else {
throw 'Could not launch $url';
}
}
List<Widget> _buildContent() {
List<Widget> _list = [
@ -143,24 +132,20 @@ class _WidgetDemoState extends State<WidgetDemo> {
void _selectValue(value){
if(value == 'doc'){
_launchURL(widget.docUrl);
// _launchURL(widget.docUrl);
Application.router.navigateTo(context, '${Routes.webViewPage}?title=${Uri.encodeComponent(widget.title)} Doc&&url=${Uri.encodeComponent(widget.docUrl)}');
}else if(value =='code'){
// _launchURL(Application.github['widgetsURL'] + widget.codeUrl);
Application.router.navigateTo(context, '${Routes.codeView}?filePath=${Uri.encodeComponent(widget.codeUrl)}');
}else{
_getCollection();
}
}
@override
Widget build(BuildContext context) {
if (_hasCollected) {
_collectionColor = Colors.red;
_collText='取消收藏';
_collectionIcons = Icons.favorite;
} else {
_collectionColor =null;
_collText='组件收藏';
_collectionIcons = Icons.favorite_border;
}
return Scaffold(
appBar: AppBar(
@ -173,6 +158,11 @@ class _WidgetDemoState extends State<WidgetDemo> {
},
icon: Icon(Icons.home),
),
new IconButton(
tooltip: 'collection',
onPressed: _getCollection,
icon: Icon(_collectionIcons),
),
PopupMenuButton<String>(
onSelected: _selectValue,
itemBuilder: (BuildContext context) => <PopupMenuEntry<String>>[
@ -191,15 +181,6 @@ class _WidgetDemoState extends State<WidgetDemo> {
title: Text('查看Demo'),
),
),
const PopupMenuDivider(),
PopupMenuItem<String>(
value: 'collection',
child: ListTile(
leading: Icon(Icons.star,size: 22.0,color: _collectionColor,),
title: Text(_collText),
),
),
],
),
],

View File

@ -0,0 +1,192 @@
import 'dart:async';
import 'dart:ui';
import 'package:flutter/material.dart';
import './pager_indicator.dart';
class PageDragger extends StatefulWidget {
final canDragLeftToRight;
final canDragRightToLeft;
final StreamController<SlideUpdate> slideUpdateStream;
PageDragger({
this.canDragLeftToRight,
this.canDragRightToLeft,
this.slideUpdateStream,
});
@override
_PageDraggerState createState() => _PageDraggerState();
}
class _PageDraggerState extends State<PageDragger> {
static const FULL_TRANSTITION_PX = 300.0;
Offset dragStart;
SlideDirection slideDirection;
double slidePercent = 0.0;
onDragStart(DragStartDetails details){
dragStart = details.globalPosition;
}
onDragUpdate(DragUpdateDetails details) {
if (dragStart != null) {
final newPosition = details.globalPosition;
final dx = dragStart.dx - newPosition.dx;
if (dx > 0 && widget.canDragRightToLeft) {
slideDirection = SlideDirection.rightToLeft;
} else if (dx < 0 && widget.canDragLeftToRight) {
slideDirection = SlideDirection.leftToRight;
} else {
slideDirection = SlideDirection.none;
}
if (slideDirection != SlideDirection.none){
slidePercent = (dx / FULL_TRANSTITION_PX).abs().clamp(0.0, 1.0);
} else {
slidePercent = 0.0;
}
widget.slideUpdateStream.add(
new SlideUpdate(
UpdateType.dragging,
slideDirection,
slidePercent
));
}
}
onDragEnd(DragEndDetails details){
widget.slideUpdateStream.add(
new SlideUpdate(
UpdateType.doneDragging,
SlideDirection.none,
0.0,
)
);
dragStart = null;
}
@override
Widget build(BuildContext context) {
return GestureDetector(
onHorizontalDragStart: onDragStart ,
onHorizontalDragUpdate: onDragUpdate ,
onHorizontalDragEnd: onDragEnd ,
);
}
}
class AnimatedPageDragger{
static const PERCENT_PER_MILLISECOND = 0.005;
final slideDirection;
final transitionGoal;
AnimationController completionAnimationController;
AnimatedPageDragger({
this.slideDirection,
this.transitionGoal,
slidePercent,
StreamController<SlideUpdate> slideUpdateStream,
TickerProvider vsync,
}) {
final startSlidePercent = slidePercent;
var endSlidePercent;
var duration;
if ( transitionGoal == TransitionGoal.open){
endSlidePercent = 1.0;
final slideRemaining = 1.0 - slidePercent;
duration = new Duration(
milliseconds: (slideRemaining / PERCENT_PER_MILLISECOND).round()
);
} else {
endSlidePercent = 0.0;
duration = new Duration(
milliseconds: (slidePercent / PERCENT_PER_MILLISECOND).round()
);
}
completionAnimationController = new AnimationController(
duration: duration,
vsync: vsync
)
..addListener((){
slidePercent = lerpDouble(
startSlidePercent,
endSlidePercent,
completionAnimationController.value
);
slideUpdateStream.add(
new SlideUpdate(
UpdateType.animating,
slideDirection,
slidePercent,
)
);
})
..addStatusListener((AnimationStatus status){
if(status == AnimationStatus.completed){
slideUpdateStream.add(
new SlideUpdate(
UpdateType.doneAnimating,
slideDirection,
endSlidePercent,
)
);
}
});
}
run(){
completionAnimationController.forward(from: 0.0);
}
dispose(){
completionAnimationController.dispose();
}
}
enum TransitionGoal{
open,
close,
}
enum UpdateType{
dragging,
doneDragging,
animating,
doneAnimating,
}
class SlideUpdate {
final updateType;
final direction;
final slidePercent;
SlideUpdate(
this.updateType,
this.direction,
this.slidePercent
);
}

View File

@ -0,0 +1,53 @@
import 'dart:math';
import 'package:flutter/material.dart';
class PageReveal extends StatelessWidget {
final double revealPercent;
final Widget child;
PageReveal({
this.revealPercent,
this.child
});
@override
Widget build(BuildContext context) {
return ClipOval(
clipper: new CircleRevealClipper(revealPercent),
child: child,
);
}
}
class CircleRevealClipper extends CustomClipper<Rect>{
final double revealPercent;
CircleRevealClipper(
this.revealPercent
);
@override
Rect getClip(Size size) {
final epicenter = new Offset(size.width / 2, size.height * 0.9);
double theta = atan(epicenter.dy / epicenter.dx);
final distanceToCorner = epicenter.dy / sin(theta);
final radius = distanceToCorner * revealPercent;
final diameter = 2 * radius;
return new Rect.fromLTWH(epicenter.dx - radius, epicenter.dy - radius, diameter, diameter);
}
@override
bool shouldReclip(CustomClipper<Rect> oldClipper) {
// TODO: implement shouldReclip
return true;
}
}

View File

@ -0,0 +1,156 @@
import 'dart:ui';
import 'package:flutter/material.dart';
import './pages.dart';
class PagerIndicator extends StatelessWidget {
final PagerIndicatorViewModel viewModel;
PagerIndicator({
this.viewModel,
});
@override
Widget build(BuildContext context) {
List<PageBubble> bubbles = [];
for(var i = 0; i < viewModel.pages.length; ++i ){
final page = viewModel.pages[i];
var percentActive;
if(i == viewModel.activeIndex){
percentActive = 1.0 - viewModel.slidePercent;
} else if (i == viewModel.activeIndex - 1 && viewModel.slideDirection == SlideDirection.leftToRight){
percentActive = viewModel.slidePercent;
} else if (i == viewModel.activeIndex + 1 && viewModel.slideDirection == SlideDirection.rightToLeft){
percentActive = viewModel.slidePercent;
}else {
percentActive = 0.0;
}
bool isHollow = i > viewModel.activeIndex || (i == viewModel.activeIndex && viewModel.slideDirection == SlideDirection.leftToRight);
bubbles.add(
new PageBubble(
viewModel: new PageBubbleViewModel(
page.iconAssetPath,
page.color,
isHollow,
percentActive,
),
),
);
}
final BUBBLE_WIDHT = 55.0 ;
final baseTranslation = ((viewModel.pages.length * BUBBLE_WIDHT) / 2) - (BUBBLE_WIDHT / 2) ;
var translation = baseTranslation - (viewModel.activeIndex * BUBBLE_WIDHT);
if (viewModel.slideDirection == SlideDirection.leftToRight){
translation += BUBBLE_WIDHT * viewModel.slidePercent;
}else if (viewModel.slideDirection == SlideDirection.rightToLeft){
translation -= BUBBLE_WIDHT * viewModel.slidePercent;
}
return new Column(
children: <Widget>[
new Expanded(child: new Container()),
new Transform(
transform: new Matrix4.translationValues(translation, 0.0, 0.0),
child: new Row(
mainAxisAlignment: MainAxisAlignment.center,
children: bubbles,
),
),
],
);
}
}
enum SlideDirection{
leftToRight,
rightToLeft,
none,
}
class PagerIndicatorViewModel{
final List<PageViewModel> pages;
final int activeIndex;
final SlideDirection slideDirection;
final double slidePercent;
PagerIndicatorViewModel(
this.pages,
this.activeIndex,
this.slideDirection,
this.slidePercent
);
}
class PageBubble extends StatelessWidget {
final PageBubbleViewModel viewModel;
PageBubble({
this.viewModel
});
@override
Widget build(BuildContext context) {
return new Container(
width: 55.0,
height: 65.0,
child: new Center(
child: new Container(
width: lerpDouble(20.0,45.0,viewModel.activePercent),
height: lerpDouble(20.0,45.0,viewModel.activePercent),
decoration: new BoxDecoration(
shape: BoxShape.circle,
color: viewModel.isHollow
? const Color(0x88FFFFFF).withAlpha(0x88 * viewModel.activePercent.round())
: const Color(0x88FFFFFF),
border: new Border.all(
color: viewModel.isHollow
? const Color(0x88FFFFFF).withAlpha((0x88 * (1.0 - viewModel.activePercent)).round())
: Colors.transparent,
width: 3.0,
),
),
child: new Opacity(
opacity: viewModel.activePercent,
child: Image.asset(
viewModel.iconAssetPath,
color: viewModel.color,
),
),
),
),
);
}
}
class PageBubbleViewModel {
final String iconAssetPath;
final Color color;
final bool isHollow;
final double activePercent;
PageBubbleViewModel (
this.iconAssetPath,
this.color,
this.isHollow,
this.activePercent,
);
}

View File

@ -0,0 +1,136 @@
import 'package:flutter/material.dart';
import '../../routers/application.dart';
import '../../routers/routers.dart';
final pages = [
new PageViewModel(
const Color(0xFFcd344f),
//'assets/mountain.png',
'assets/images/p2.png',
'FlutterGo是什么',
'【FlutterGo】 是由"阿里拍卖"前端团队几位 Flutter 粉丝,用业余时间开发的一款,用于 Flutter 教学帮助的App这里没有高大尚的概念只有一个一个亲历的尝试用最直观的方式展示的 Flutter 官方demo',
'assets/images/plane.png'),
new PageViewModel(
const Color(0xFF638de3),
//'assets/world.png',
'assets/images/p1.png',
'FLutterGo的背景',
'🐢 官网文档示例较不够健全,不够直观\n🐞 运行widget demo要到处翻阅资料\n🐌 英文文档翻译生涩难懂,学习资料太少\n',
'assets/images/calendar.png'),
new PageViewModel(
const Color(0xFFFF682D),
//'assets/home.png',
'assets/images/p3.png',
'FlutterGo的特点',
'🐡 详解常用widget多达 130+ 个\n🦋 持续迭代追新官方版本\n🐙 配套Demo详解widget用法\n🚀 一站式搞定所有常用widget,开箱即查\n',
'assets/images/house.png',
),
];
class Page extends StatelessWidget {
final PageViewModel viewModel;
final double percentVisible;
Page({
this.viewModel,
this.percentVisible = 1.0,
});
Widget creatButton(BuildContext context,String txt,IconData iconName,String type){
return RaisedButton.icon(
onPressed: () {
if(type == 'start'){
//Navigator.popUntil(context, ModalRoute.withName('/'));
}else if(type == 'goGithub'){
Application.router.navigateTo(context, '${Routes.webViewPage}?title=${Uri.encodeComponent(txt)} Doc&&url=${Uri.encodeComponent("https://github.com/alibaba/flutter-go")}');
}
},
elevation: 10.0,
color:Colors.black26,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20)),
//如果不手动设置icon和text颜色,则默认使用foregroundColor颜色
icon: new Icon(iconName,color: Colors.white,size:20.0),
label: new Text(txt, maxLines: 1,style: TextStyle(color:Colors.white,fontSize: 16,fontWeight: FontWeight.w700),)
);
}
@override
Widget build(BuildContext context) {
return new Container(
width: double.infinity,
color: viewModel.color,
child: new Opacity(
opacity: percentVisible,
child: new Column(
crossAxisAlignment:CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: [
new Transform(
transform: new Matrix4.translationValues(0.0, 50.0 * (1.0 - percentVisible) ,0.0),
child: new Padding(
padding: new EdgeInsets.only(top: 20.0, bottom: 10.0),
child:
new Image.asset(
viewModel.heroAssetPath,
width: 200.0,
height: 200.0),
),
),
new Transform(
transform: new Matrix4.translationValues(0.0, 30.0 * (1.0 - percentVisible) ,0.0),
child: new Padding(
padding: new EdgeInsets.only(top: 10.0, bottom: 10.0),
child: new Text(
viewModel.title,
style: new TextStyle(
color: Colors.white,
fontFamily: 'FlamanteRoma',
fontSize: 34.0,
),
),
),
),
new Transform(
transform: new Matrix4.translationValues(0.0, 30.0 * (1.0 - percentVisible) ,0.0),
child: new Padding(
padding: new EdgeInsets.only(bottom: 10.0),
child: new Text(
viewModel.body,
textAlign: TextAlign.center,
style: new TextStyle(
height:1.2,
color: Colors.white,
fontFamily: 'FlamanteRomaItalic',
fontSize: 18.0,
),
),
),
),
ButtonBar(
alignment: MainAxisAlignment.center,
children: <Widget>[
creatButton(context,'开始使用',Icons.add_circle_outline,'start'),
creatButton(context,'GitHub',Icons.arrow_forward,'goGithub'),
],)
]),
));
}
}
class PageViewModel {
final Color color;
final String heroAssetPath;
final String title;
final String body;
final String iconAssetPath;
PageViewModel(
this.color,
this.heroAssetPath,
this.title,
this.body,
this.iconAssetPath,
);
}

View File

@ -168,8 +168,8 @@ class _MyHomePageState extends State<MyHomePage>
tabs: <Tab>[
Tab(text: '业界动态', icon: Icon(Icons.language)),
Tab(text: '组件', icon: Icon(Icons.extension)),
Tab(text: '组件收藏', icon: Icon(Icons.star)),
Tab(text: '关于手册', icon: Icon(Icons.favorite)),
Tab(text: '组件收藏', icon: Icon(Icons.favorite)),
Tab(text: '关于手册', icon: Icon(Icons.line_weight)),
],
),
),

View File

@ -3,24 +3,32 @@ import 'package:fluro/fluro.dart';
import '../views/category.dart';
import '../widgets/404.dart';
import '../common/full_screen_code_dialog.dart';
import '../views/web_view_page.dart';
var categoryHandler = new Handler(
handlerFunc: (BuildContext context, Map<String, List<String>> params) {
String name = params["type"]?.first;
handlerFunc: (BuildContext context, Map<String, List<String>> params) {
String name = params["type"]?.first;
return new CategoryHome(name);
},
);
return new CategoryHome(name);
},
);
var widgetNotFoundHandler = new Handler(
handlerFunc: (BuildContext context, Map<String, List<String>> params) {
return new WidgetNotFound();
}
);
handlerFunc: (BuildContext context, Map<String, List<String>> params) {
return new WidgetNotFound();
});
var fullScreenCodeDialog = new Handler(
handlerFunc: (BuildContext context,Map<String, List<String>> params){
String path = params['filePath']?.first;
return new FullScreenCodeDialog(filePath: path,);
}
);
handlerFunc: (BuildContext context, Map<String, List<String>> params) {
String path = params['filePath']?.first;
return new FullScreenCodeDialog(
filePath: path,
);
});
var webViewPageHand = new Handler(
handlerFunc: (BuildContext context, Map<String, List<String>> params) {
String title = params['title']?.first;
String url = params['url']?.first;
return new WebViewPage(url, title);
});

View File

@ -8,6 +8,7 @@ class Routes {
static String root = "/";
static String widgetDemo = '/widget-demo';
static String codeView = '/code-view';
static String webViewPage = '/web-view-page';
static void configureRoutes(Router router) {
List widgetDemosList = new WidgetDemoList().getDemos();
@ -19,6 +20,7 @@ class Routes {
router.define('/category/:type', handler: categoryHandler);
router.define('/category/error/404', handler: widgetNotFoundHandler);
router.define(codeView,handler:fullScreenCodeDialog);
router.define(webViewPage,handler:webViewPageHand);
widgetDemosList.forEach((demo) {
Handler handler = new Handler(
handlerFunc: (BuildContext context, Map<String, List<String>> params) {

View File

@ -2,11 +2,12 @@
* @Author: 一凨
* @Date: 2019-01-08 17:12:58
* @Last Modified by: 一凨
* @Last Modified time: 2019-01-08 20:14:56
* @Last Modified time: 2019-01-14 20:02:46
*/
import 'package:flutter/material.dart';
import '../model/collection.dart';
import '../routers/application.dart';
import '../routers/routers.dart';
import '../event/event-bus.dart';
import '../event/event-model.dart';
import 'package:event_bus/event_bus.dart';
@ -15,8 +16,7 @@ class CollectionPage extends StatefulWidget {
_CollectionPageState createState() => _CollectionPageState();
}
class _CollectionPageState extends State<CollectionPage>
with AutomaticKeepAliveClientMixin {
class _CollectionPageState extends State<CollectionPage> {
_CollectionPageState() {
final eventBus = new EventBus();
ApplicationEvent.event = eventBus;
@ -24,9 +24,7 @@ class _CollectionPageState extends State<CollectionPage>
CollectionControlModel _collectionControl = new CollectionControlModel();
List<Collection> _collectionList = [];
ScrollController _scrollController = new ScrollController();
@override
bool get wantKeepAlive => true;
var _icons;
@override
void initState() {
@ -76,8 +74,17 @@ class _CollectionPageState extends State<CollectionPage>
),
);
}
if (_collectionList[index - 1].router.contains('http')) {
if (_collectionList[index - 1].name.endsWith('Doc')) {
_icons = Icons.library_books;
} else {
_icons = Icons.bookmark;
}
} else {
_icons = Icons.extension;
}
return Container(
padding: const EdgeInsets.all(10.0),
padding: const EdgeInsets.symmetric(vertical: 10.0, horizontal: 5.0),
margin: const EdgeInsets.only(bottom: 7.0),
decoration: BoxDecoration(
color: Colors.white,
@ -91,15 +98,26 @@ class _CollectionPageState extends State<CollectionPage>
],
),
child: ListTile(
leading: Icon(
_icons,
size: 30.0,
color: Theme.of(context).primaryColor,
),
title: Text(
_collectionList[index - 1].name,
overflow: TextOverflow.ellipsis,
style: TextStyle(fontSize: 17.0),
),
trailing:
Icon(Icons.keyboard_arrow_right, color: Colors.grey, size: 30.0),
onTap: () {
Application.router
.navigateTo(context, "${_collectionList[index - 1].router}");
if (_collectionList[index - 1].router.contains('http')) {
Application.router.navigateTo(context,
'${Routes.webViewPage}?title=${Uri.encodeComponent(_collectionList[index - 1].name)}&url=${Uri.encodeComponent(_collectionList[index - 1].router)}');
} else {
Application.router
.navigateTo(context, "${_collectionList[index - 1].router}");
}
},
),
);
@ -107,7 +125,6 @@ class _CollectionPageState extends State<CollectionPage>
@override
Widget build(BuildContext context) {
super.build(context);
if (_collectionList.length == 0) {
return ListView(
children: <Widget>[

View File

@ -1,22 +1,118 @@
import 'dart:async';
import 'package:flutter/material.dart';
import '../components/comp_list.dart';
import 'package:flutter_go/components/fourth_page_feature/page_dragger.dart';
import 'package:flutter_go/components/fourth_page_feature/page_reveal.dart';
import 'package:flutter_go/components/fourth_page_feature/pager_indicator.dart';
import 'package:flutter_go/components/fourth_page_feature/pages.dart';
import '../components/comp_list.dart';
class FourthPage extends StatefulWidget {
@override
FourthPageState createState() => new FourthPageState();
}
class FourthPageState extends State<FourthPage> {
class FourthPageState extends State<FourthPage> with TickerProviderStateMixin {
StreamController<SlideUpdate> slideUpdateStream;
AnimatedPageDragger animatedPageDragger;
int activeIndex = 0 ;
SlideDirection slideDirection = SlideDirection.none;
int nextPageIndex = 0 ;
double slidePercent= 0.0;
FourthPageState(){
slideUpdateStream = new StreamController<SlideUpdate>();
slideUpdateStream.stream.listen((SlideUpdate event){
setState(() {
if( event.updateType == UpdateType.dragging){
slideDirection = event.direction;
slidePercent = event.slidePercent;
if( slideDirection == SlideDirection.leftToRight ){
nextPageIndex = activeIndex - 1;
} else if (slideDirection == SlideDirection.rightToLeft){
nextPageIndex = activeIndex + 1;
} else{
nextPageIndex = activeIndex;
}
} else if( event.updateType == UpdateType.doneDragging){
if(slidePercent > 0.5){
animatedPageDragger = new AnimatedPageDragger(
slideDirection: slideDirection,
transitionGoal: TransitionGoal.open,
slidePercent: slidePercent,
slideUpdateStream: slideUpdateStream,
vsync: this,
);
} else{
animatedPageDragger = new AnimatedPageDragger(
slideDirection: slideDirection,
transitionGoal: TransitionGoal.close,
slidePercent: slidePercent,
slideUpdateStream: slideUpdateStream,
vsync: this,
);
nextPageIndex = activeIndex;
}
animatedPageDragger.run();
}
else if( event.updateType == UpdateType.animating){
slideDirection = event.direction;
slidePercent = event.slidePercent;
}
else if (event.updateType == UpdateType.doneAnimating){
activeIndex = nextPageIndex;
slideDirection = SlideDirection.none;
slidePercent = 0.0;
animatedPageDragger.dispose();
}
});
});
}
@override
Widget build(BuildContext context) {
return new Container(
child: new CompList()
return new Stack(
children: [
new Page( // page 的主要内容
viewModel: pages[activeIndex],
percentVisible: 1.0 ,
),
new PageReveal(
revealPercent: slidePercent,
child: new Page(
viewModel: pages[nextPageIndex],
percentVisible: slidePercent ,
),
),
new PagerIndicator(
viewModel: new PagerIndicatorViewModel(
pages,
activeIndex,
slideDirection,
slidePercent,
),
),
new PageDragger(
canDragLeftToRight: activeIndex > 0 ,
canDragRightToLeft: activeIndex < pages.length - 1 ,
slideUpdateStream: this.slideUpdateStream,
)
],
);
}
}

View File

@ -0,0 +1,120 @@
/*
* @Author: 一凨
* @Date: 2019-01-14 17:44:47
* @Last Modified by: 一凨
* @Last Modified time: 2019-01-14 19:47:14
*/
import 'package:flutter/material.dart';
import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';
import '../model/collection.dart';
import '../event/event-bus.dart';
import '../event/event-model.dart';
import 'package:fluttertoast/fluttertoast.dart';
class WebViewPage extends StatefulWidget {
final String url;
final String title;
WebViewPage(this.url, this.title);
_WebViewPageState createState() => _WebViewPageState();
}
class _WebViewPageState extends State<WebViewPage> {
bool _hasCollected = false;
String _router = '';
var _collectionIcons;
CollectionControlModel _collectionControl = new CollectionControlModel();
void showInSnackBar(String value) {
Fluttertoast.showToast(
msg: value,
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIos: 1,
backgroundColor: Colors.grey,
textColor: Colors.white);
}
@override
void initState() {
super.initState();
_collectionControl.getRouterByName(widget.title.trim()).then((list) {
list.forEach((item) {
if(widget.title.trim() == item['name']){
_router = item['router'];
}
});
if (mounted) {
setState(() {
_hasCollected = list.length > 0;
});
}
});
}
// 点击收藏按钮
_getCollection() {
if (_hasCollected) {
// 删除操作
_collectionControl.deleteByName(widget.title.trim()).then((result) {
if (result > 0 && this.mounted) {
setState(() {
_hasCollected = false;
});
showInSnackBar('已取消收藏');
if (ApplicationEvent.event != null) {
ApplicationEvent.event
.fire(CollectionEvent(widget.title, _router, true));
}
return;
}
print('删除错误');
});
} else {
// 插入操作
_collectionControl
.insert(Collection(name: widget.title.trim(), router: widget.url))
.then((result) {
if (this.mounted) {
setState(() {
_hasCollected = true;
});
if (ApplicationEvent.event != null) {
ApplicationEvent.event
.fire(CollectionEvent(widget.title, _router, false));
}
showInSnackBar('收藏成功');
}
});
}
}
@override
Widget build(BuildContext context) {
if (_hasCollected) {
_collectionIcons = Icons.favorite;
} else {
_collectionIcons = Icons.favorite_border;
}
return WebviewScaffold(
url: widget.url,
appBar: AppBar(
title: Text(widget.title),
actions: <Widget>[
new IconButton(
tooltip: 'goBack home',
onPressed: _getCollection,
icon: Icon(_collectionIcons,),
),
],
),
withZoom: false,
withLocalStorage: true,
withJavascript: true,
);
}
}

View File

@ -96,7 +96,6 @@ class PopupMenuButtonCustom extends StatelessWidget {
: super();
@override
Widget build(BuildContext context) {
print('onSelected1:${widget.options}');
final String selectStr = widget.options['defaultSelect'];
return PopupMenuButton(
//如果提供则用于此按钮的widget。

View File

@ -1,9 +1,6 @@
import 'package:flutter/material.dart';
/*
* 基本示例
*
*/
// 基本示例
class DefaultTextField extends StatelessWidget {
@override
Widget build(BuildContext context) {

View File

@ -20,7 +20,6 @@ class _MemoryImageDemoState extends State<MemoryImageDemo> {
super.initState();
rootBundle.load('assets/images/food01.jpeg').then((data) {
if (mounted) {
print(data);
setState(() {
bytes = data.buffer.asUint8List();
});

View File

@ -29,6 +29,7 @@ dependencies:
# 本地存储、收藏功能
shared_preferences: ^0.4.3
dio: ^1.0.6
flutter_webview_plugin: ^0.3.0+2
dev_dependencies:
flutter_test: