Переглянути джерело

1.优化多眼导航

tags/0.0.4+7
“yanghuaxuan” 3 роки тому
джерело
коміт
1a3d171f80
19 змінених файлів з 1684 додано та 134 видалено
  1. +2
    -2
      example/android/app/build.gradle
  2. +1
    -0
      lib/pages/custom_page/custom_item_page.dart
  3. +5
    -1
      lib/pages/custom_page/custom_page.dart
  4. +1
    -0
      lib/pages/home_page/home_page.dart
  5. +1
    -0
      lib/pages/main_page/main_page.dart
  6. +2
    -2
      lib/pages/orders_page/bloc/order_content_bloc.dart
  7. +1
    -1
      lib/pages/orders_page/bloc/order_page_bloc.dart
  8. +4
    -0
      lib/pages/orders_page/models/order_model.dart
  9. +10
    -1
      lib/pages/orders_page/order_content_page.dart
  10. +36
    -36
      lib/pages/orders_page/views/order_item_widget.dart
  11. +0
    -1
      lib/pages/search_page/search_page.dart
  12. +574
    -51
      lib/widgets/custom/multi_nav/custom_quick_entry.dart
  13. +4
    -0
      lib/widgets/custom/multi_nav/model/custom_quick_entry_model.dart
  14. +2
    -1
      lib/widgets/goods_details/footer/goods_details_footer_widget.dart
  15. +5
    -4
      lib/widgets/goods_details/upgrade_tip/upgrade_tip_widget.dart
  16. +34
    -31
      lib/widgets/mine/mine_header/mine_header_container.dart
  17. +2
    -0
      lib/widgets/mine/mine_header/model/mine_header_model.dart
  18. +980
    -0
      lib/widgets/primary_page_view/primary_page_view.dart
  19. +20
    -3
      lib/widgets/share/share_alert.dart

+ 2
- 2
example/android/app/build.gradle Переглянути файл

@@ -112,9 +112,9 @@ android {
// 智夜生活
zhiying {
applicationId "cn.zhios.zhiying"
versionCode 32
versionCode 33
dimension "app"
versionName '1.2.32'
versionName '1.2.33'
// 签名信息
signingConfig signingConfigs.zhiying
}


+ 1
- 0
lib/pages/custom_page/custom_item_page.dart Переглянути файл

@@ -136,6 +136,7 @@ class __CustomItemPageContainerState extends State<_CustomItemPageContainer> wit
},
builder: (context, state) {
if (state is CustomItemPageLoadedState) {
Logger.log('custom item page current state = ' + state?.toString());
if (EmptyUtil.isEmpty(state.model))
return _buildEmptyWidget();
else


+ 5
- 1
lib/pages/custom_page/custom_page.dart Переглянути файл

@@ -59,7 +59,7 @@ class _CommonPageContainer extends StatefulWidget {
__CommonPageContainerState createState() => __CommonPageContainerState();
}

class __CommonPageContainerState extends State<_CommonPageContainer> with SingleTickerProviderStateMixin {
class __CommonPageContainerState extends State<_CommonPageContainer> with SingleTickerProviderStateMixin ,AutomaticKeepAliveClientMixin{
TabController _tabController;

// 是否有AppBar
@@ -418,6 +418,10 @@ class __CommonPageContainerState extends State<_CommonPageContainer> with Single
}
}
}

@override
// TODO: implement wantKeepAlive
bool get wantKeepAlive =>true;
}

/// 回到顶部的icon


+ 1
- 0
lib/pages/home_page/home_page.dart Переглянути файл

@@ -336,4 +336,5 @@ class _HomePageState extends State<HomePage> with WidgetsBindingObserver, Ticker
)
]));
}

}

+ 1
- 0
lib/pages/main_page/main_page.dart Переглянути файл

@@ -110,6 +110,7 @@ class _MainPageContainerState extends State<_MainPageContainer> {
return StreamBuilder<List<Map<String, dynamic>>>(
stream: _bloc.outData,
builder: (BuildContext context, AsyncSnapshot snapshot) {
print("mainPageBuild");
List widgets = _createContent(context, snapshot.data ?? []);
_refreshController.refreshCompleted();
Widget bgWidget = validateBgWidget(context, snapshot.data ?? []);


+ 2
- 2
lib/pages/orders_page/bloc/order_content_bloc.dart Переглянути файл

@@ -35,7 +35,7 @@ class OrderContentBloc extends BlocBase {
params['state'] = _state;
NetUtil.request('/api/v1/order', method: NetMethod.POST, params: params,
onCache: (data) {
_parseData(data);
//_parseData(data);
}, onSuccess: (data) {
_parseData(data);
});
@@ -66,6 +66,6 @@ class OrderContentBloc extends BlocBase {
return OrderModel.fromJson(Map<String, dynamic>.from(item));
}).toList());

_ordersController.add(_orders);
_ordersController?.add(_orders);
}
}

+ 1
- 1
lib/pages/orders_page/bloc/order_page_bloc.dart Переглянути файл

@@ -22,7 +22,7 @@ class OrderPageBloc extends BlocBase {
void loadData(String skipIdentifier) async {
NetUtil.request('/api/v1/mod/${skipIdentifier.toString()}',
method: NetMethod.GET, onCache: (data) {
_loadData(data);
// _loadData(data);
}, onSuccess: (data) {
_loadData(data);
});


+ 4
- 0
lib/pages/orders_page/models/order_model.dart Переглянути файл

@@ -20,6 +20,8 @@ class OrderModel {
String confirmAt;
String settleAt;
String thumbnail;
int priceType;
String priceName;
Map<String, dynamic> data; // 保存原始数据

OrderModel({
@@ -69,6 +71,8 @@ class OrderModel {
confirmAt = json['confirm_at'];
settleAt = json['settle_at'];
thumbnail = json['thumbnail'];
priceType=json['price_type'];
priceName=json['price_name'];
data = json;
}



+ 10
- 1
lib/pages/orders_page/order_content_page.dart Переглянути файл

@@ -1,3 +1,5 @@
import 'dart:async';

import 'package:event_bus/event_bus.dart';
import 'package:flutter/material.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
@@ -59,13 +61,15 @@ class _OrderContentContainerState extends State<OrderContentContainer> {
OrderContentBloc _bloc;
RefreshController _refreshController =
RefreshController(initialRefresh: false);
StreamSubscription streamSubscription;

@override
void initState() {
_bloc = BlocProvider.of(context);
_bloc.refresh(widget.state, widget.filter);

widget.eventBus.on<int>().listen((index) {
streamSubscription= widget.eventBus.on<int>().listen((index) {
print('eventbus' + index.toString());
if (index == widget.index) {
_bloc.refresh(widget.state, widget.filter);
}
@@ -73,6 +77,11 @@ class _OrderContentContainerState extends State<OrderContentContainer> {

super.initState();
}
@override
void dispose() {
streamSubscription.cancel();
super.dispose();
}

@override
Widget build(BuildContext context) {


+ 36
- 36
lib/pages/orders_page/views/order_item_widget.dart Переглянути файл

@@ -1,3 +1,5 @@
import 'dart:io';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:fluttertoast/fluttertoast.dart';
@@ -18,8 +20,7 @@ class OrderItemWidget extends StatelessWidget {
margin: EdgeInsets.only(left: 12.5, right: 12.5, top: 4, bottom: 4),
padding: EdgeInsets.all(10),
width: double.infinity,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(7.5), color: Colors.white),
decoration: BoxDecoration(borderRadius: BorderRadius.circular(7.5), color: Colors.white),
child: Column(
children: <Widget>[
_createHeader(),
@@ -48,21 +49,35 @@ class OrderItemWidget extends StatelessWidget {
}

List<OrderStateModel> states = style.list.orderState;
OrderStateModel state =
states.firstWhere((element) => element.type == model.state.toString());
OrderStateModel state = states.firstWhere((element) => element.type == model.state.toString());
return Padding(
padding: const EdgeInsets.only(bottom: 8),
child: Row(
children: <Widget>[
Expanded(
child: Text(
type ?? '',
maxLines: 1,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
color: Color(0xff333333),
),
child: Row(
children: <Widget>[
Text(
type ?? '',
maxLines: 1,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
color: Color(0xff333333),
),
),
model?.priceName == null
? Container()
: Container(
decoration: BoxDecoration(color: Colors.red, borderRadius: BorderRadius.circular(4)),
margin: EdgeInsets.only(left: 4),
padding: EdgeInsets.all(3),
child: Text(
model?.priceName ?? "",
style: TextStyle(color: HexColor.fromHex("#FFFFFF"), fontSize: 9, height: 1),
),
)
],
),
),
Text(
@@ -102,8 +117,7 @@ class OrderItemWidget extends StatelessWidget {
_createTitle(),
Row(
children: <Widget>[
_creteText(
'${style?.list?.textOrderNo ?? ''}${model?.ordId ?? ''}'),
_creteText('${style?.list?.textOrderNo ?? ''}${model?.ordId ?? ''}'),
GestureDetector(
onTap: () {
if (model?.ordId != null && model.ordId.length > 0) {
@@ -132,10 +146,8 @@ class OrderItemWidget extends StatelessWidget {
)
],
),
_creteText(
'${style?.list?.textOrderTime ?? ''}${model?.createAt ?? ''}'),
_creteText(
'${style?.list?.textFinishTime ?? ''}${model?.confirmAt ?? ''}'),
_creteText('${style?.list?.textOrderTime ?? ''}${model?.createAt ?? ''}'),
_creteText('${style?.list?.textFinishTime ?? ''}${model?.confirmAt ?? ''}'),
],
),
)
@@ -147,10 +159,7 @@ class OrderItemWidget extends StatelessWidget {
List<InlineSpan> list = List();
String shop = '';
if (model?.provider != null && model.provider != '') {
shop = style.filter.providerType
.firstWhere((element) => element.type == model.provider)
?.name ??
'';
shop = style.filter.providerType.firstWhere((element) => element.type == model.provider)?.name ?? '';
}
if (shop != '') {
list.add(WidgetSpan(
@@ -162,23 +171,17 @@ class OrderItemWidget extends StatelessWidget {
style: TextStyle(
fontSize: 9,
height: 1,
color:
HexColor.fromHex(style.list.colorProviderFont ?? '#ffffff'),
color: HexColor.fromHex(style.list.colorProviderFont ?? '#ffffff'),
),
),
decoration: BoxDecoration(
color: HexColor.fromHex(style.list.colorProviderBg ?? '#ffffff'),
borderRadius: BorderRadius.circular(2.5)),
decoration: BoxDecoration(color: HexColor.fromHex(style.list.colorProviderBg ?? '#ffffff'), borderRadius: BorderRadius.circular(2.5)),
),
));
}
list.add(
TextSpan(
text: model?.itemTitle ?? '',
style: TextStyle(
fontSize: 15,
color: Color(0xff333333),
fontWeight: FontWeight.bold),
style: TextStyle(fontSize: 15, color: Color(0xff333333), fontWeight: FontWeight.bold),
),
);
return RichText(
@@ -205,8 +208,7 @@ class OrderItemWidget extends StatelessWidget {

Widget _createTips() {
List<OrderStateModel> states = style.list.orderState;
OrderStateModel state =
states.firstWhere((element) => element.type == model.state.toString());
OrderStateModel state = states.firstWhere((element) => element.type == model.state.toString());
if (state == null || state.tips == null || state.tips == '') {
return Container();
}
@@ -214,9 +216,7 @@ class OrderItemWidget extends StatelessWidget {
margin: EdgeInsets.only(top: 8),
padding: EdgeInsets.only(left: 8, right: 8, top: 2, bottom: 2),
width: double.infinity,
decoration: BoxDecoration(
color: HexColor.fromHex(style.list.colorTipsBg ?? '#f5f5f5'),
borderRadius: BorderRadius.circular(4)),
decoration: BoxDecoration(color: HexColor.fromHex(style.list.colorTipsBg ?? '#f5f5f5'), borderRadius: BorderRadius.circular(4)),
child: Text(
state?.tips ?? '',
style: TextStyle(color: Color(0xff666666), fontSize: 10),


+ 0
- 1
lib/pages/search_page/search_page.dart Переглянути файл

@@ -77,7 +77,6 @@ class _SearchPageContianerState extends State<SearchPageContianer> {
Widget build(BuildContext context) {
//设置搜索bar应该选择哪个type的item
Logger.log("数据2: " + json.encode(widget.data));
Logger.log("类型: " + widget.data['default_pvd']);
if(!EmptyUtil.isEmpty(widget.data['default_pvd'])){
Provider.of<SearchTagNotifier>(context, listen: false).setType(widget.data['default_pvd']);
}


+ 574
- 51
lib/widgets/custom/multi_nav/custom_quick_entry.dart Переглянути файл

@@ -1,3 +1,4 @@
import 'dart:async';
import 'dart:math';

import 'package:flutter/cupertino.dart';
@@ -5,6 +6,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_swiper/flutter_swiper.dart';
import 'package:tab_indicator_styler/tab_indicator_styler.dart';
import 'package:zhiying_base_widget/widgets/primary_page_view/primary_page_view.dart';
import 'package:zhiying_comm/zhiying_comm.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'custom_quick_entry_sk.dart';
@@ -19,9 +21,9 @@ class CustomQuickEntry extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocProvider<CustomQuickEntryBloc>(
create: (_) =>
CustomQuickEntryBloc(repository: CustomQuickEntryRepository())
..add(CustomQuickEntryInitEvent(model: model)),
create: (_) {
return CustomQuickEntryBloc(repository: CustomQuickEntryRepository())..add(CustomQuickEntryInitEvent(model: model));
},
child: _CustomQuickEntryContainer(model),
);
}
@@ -30,13 +32,13 @@ class CustomQuickEntry extends StatelessWidget {
class _CustomQuickEntryContainer extends StatefulWidget {
final Map<String, dynamic> model;

_CustomQuickEntryContainer(this.model);
_CustomQuickEntryContainer(this.model, {Key key}) : super(key: key);

@override
__CustomQuickEntryContainerState createState() => __CustomQuickEntryContainerState();
}

class __CustomQuickEntryContainerState extends State<_CustomQuickEntryContainer> {
class __CustomQuickEntryContainerState extends State<_CustomQuickEntryContainer> with TickerProviderStateMixin, AutomaticKeepAliveClientMixin {
/// Icon点击事件
void _itemIconClick(ListStyle model) {
print("item type = ${model.skipIdentifier}");
@@ -49,12 +51,14 @@ class __CustomQuickEntryContainerState extends State<_CustomQuickEntryContainer>
@override
void initState() {
_controller = SwiperController();

super.initState();
}

@override
void dispose() {
_controller?.dispose();

super.dispose();
}

@@ -63,14 +67,24 @@ class __CustomQuickEntryContainerState extends State<_CustomQuickEntryContainer>
return BlocConsumer<CustomQuickEntryBloc, CustomQuickEntryState>(
listener: (context, state) {},
buildWhen: (prev, current) {
if (prev is CustomQuickEntryLoadedState) {
return false;
}
return true;
},
builder: (context, state) {
print("构建");
if (state is CustomQuickEntryCachedState) {
return _getMainWidget(state.model);
}
if (state is CustomQuickEntryLoadedState) {
return _getMainWidget(state.model);
if (state.model.isShowCategory == "1") {
return CustomQuickCateEntry(
model: state.model,
);
} else {
return _getMainWidget(state.model);
}
}
if (state is CustomQuickEntryErrorState) {
return Container();
@@ -91,15 +105,15 @@ class __CustomQuickEntryContainerState extends State<_CustomQuickEntryContainer>
int columSize = int.parse(model?.columSize ?? '5');

//计算实际显示行数
if(totalRowSize*columSize>totalDataSize){
for(int index=1;index<=totalRowSize;index++){
if(index*columSize>=totalDataSize){
totalRowSize=index;
if (totalRowSize * columSize > totalDataSize) {
for (int index = 1; index <= totalRowSize; index++) {
if (index * columSize >= totalDataSize) {
totalRowSize = index;
break;
}
}
}
print("行数"+totalRowSize.toString());
print("行数" + totalRowSize.toString());

// 图标的高度
double iconHeight = 40.0;
@@ -128,7 +142,7 @@ class __CustomQuickEntryContainerState extends State<_CustomQuickEntryContainer>
// 总体高度 = 行数 * (子元素高度 + 边距高度) + 进度条的高度
double totalHeight = totalRowSize * (itemHeight + barMargin);
if (totalPage > 1 && !EmptyUtil.isEmpty(model?.pagination) && model.pagination != 'type_null' /*model.pagination_open == '0'*/) {
totalHeight = totalRowSize * (itemHeight + barMargin);
totalHeight = totalRowSize * (itemHeight + barMargin)+8;
}

// 分类导航高度
@@ -150,10 +164,7 @@ class __CustomQuickEntryContainerState extends State<_CustomQuickEntryContainer>
double marginLeftRight = model?.isLeftRightMargin == "1" ? double.tryParse(model?.leftRightMargin ?? "0") : 0;
double marginTop = model?.isTopMargin == "1" ? double.tryParse(model?.topMargin ?? "0") : 0;
return Container(

margin: EdgeInsets.only(top: marginTop,
left: marginLeftRight,
right: marginLeftRight),
margin: EdgeInsets.only(top: marginTop, left: marginLeftRight, right: marginLeftRight),
decoration: BoxDecoration(
color: HexColor.fromHex(model?.bgColor ?? ''),
//color: Colors.green,
@@ -162,10 +173,9 @@ class __CustomQuickEntryContainerState extends State<_CustomQuickEntryContainer>
topLeft: Radius.circular(ParseUtil.stringParseDouble(model?.topLeftRadius)),
bottomLeft: Radius.circular(ParseUtil.stringParseDouble(model?.bottomLeftRadius)),
bottomRight: Radius.circular(ParseUtil.stringParseDouble(model?.bottomRightRadius)),
)
),
)),
child: Container(
margin: EdgeInsets.only(top: !hasCategory ? 15 : 0, bottom: totalPage > 1 ? 15 : 0),
margin: EdgeInsets.only(top: !hasCategory ? 15 : 0, bottom: totalPage > 1 ? 8 : 0),
height: totalHeight,
// 总体高度
width: double.infinity,
@@ -173,12 +183,11 @@ class __CustomQuickEntryContainerState extends State<_CustomQuickEntryContainer>
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[

// 左上角标题
Visibility(
visible: !EmptyUtil.isEmpty(model?.moduleTitleName),
child: Padding(
padding: const EdgeInsets.only(left: 12.5, bottom: 10),
padding: const EdgeInsets.only(left: 12.5, bottom: 10),
child: Text(model?.moduleTitleName ?? '', style: TextStyle(color: HexColor.fromHex(model?.moduleTitleColor), fontWeight: FontWeight.bold, fontSize: 15))),
),

@@ -272,7 +281,6 @@ class __CustomQuickEntryContainerState extends State<_CustomQuickEntryContainer>
// )),
// ),
// )

],
),
),
@@ -311,16 +319,17 @@ class __CustomQuickEntryContainerState extends State<_CustomQuickEntryContainer>
}

/// 行的数据
Widget _getRowWidget({double titleHeight,
double iconHeight,
int totalPage,
int currentPage,
int columSize,
int totalRowSize,
int totalDataSize,
CustomQuickEntryModel model,
int currentRow,
double itemHeight}) {
Widget _getRowWidget(
{double titleHeight,
double iconHeight,
int totalPage,
int currentPage,
int columSize,
int totalRowSize,
int totalDataSize,
CustomQuickEntryModel model,
int currentRow,
double itemHeight}) {
List itemList = [];
for (int i = 0; i < columSize; i++) {
itemList.add(i);
@@ -348,19 +357,18 @@ class __CustomQuickEntryContainerState extends State<_CustomQuickEntryContainer>
}

/// item 的数据
Widget _getColumWidget({
double titleHeight,
double iconHeight,
int totalPage,
int currentPage,
int columSize,
int totalRowSize,
int totalDataSize,
CustomQuickEntryModel model,
int currentRow,
int currentColum,
double itemHeight,
}) {
Widget _getColumWidget(
{double titleHeight,
double iconHeight,
int totalPage,
int currentPage,
int columSize,
int totalRowSize,
int totalDataSize,
CustomQuickEntryModel model,
int currentRow,
int currentColum,
double itemHeight}) {
// 当前index = 当前的页数+1 * 当前的行数 + 当前的列数
// int currentIndex = (currentPage + 1) * currentRow + currentColum + currentRow*columSize;
// int currentIndex = currentPage != 0 ? currentPage * (columSize * totalRowSize) + columSize + currentRow * columSize :
@@ -389,7 +397,6 @@ class __CustomQuickEntryContainerState extends State<_CustomQuickEntryContainer>
// color: Colors.red,
child: Column(
children: <Widget>[

/// 图标
MyNetWorkImage(item.img),

@@ -481,6 +488,10 @@ class __CustomQuickEntryContainerState extends State<_CustomQuickEntryContainer>
);
});
}

@override
// TODO: implement wantKeepAlive
bool get wantKeepAlive => true;
}

///
@@ -495,14 +506,10 @@ class MyNetWorkImage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return RepaintBoundary(
child: CachedNetworkImage(
width: width,
imageUrl: imgUrl
),
child: CachedNetworkImage(width: width, imageUrl: imgUrl),
);
}


// Widget _getMainWidget(CustomQuickEntryModel model) {
// // 数据总数
// int totalDataSize = model?.listStyle?.length ?? 0;
@@ -580,3 +587,519 @@ class MyNetWorkImage extends StatelessWidget {
// }

}

class CustomQuickCateEntry extends StatefulWidget {
final CustomQuickEntryModel model;

const CustomQuickCateEntry({Key key, this.model}) : super(key: key);

@override
_CustomQuickCateEntryState createState() => _CustomQuickCateEntryState();
}

class _CustomQuickCateEntryState extends State<CustomQuickCateEntry> with TickerProviderStateMixin, AutomaticKeepAliveClientMixin {
TabController tabController;

PrimaryPageController primaryPageController;

bool isOnTap = false;

Timer onTapTimer;

SwiperController _controller;

List<PageItem> pageList = List();

@override
void initState() {
// primaryPageController = PrimaryPageController(keepPage: true);
if (widget?.model != null) {
tabController = TabController(length: widget?.model?.typeList?.length ?? 0, vsync: this);
tabController.addListener(() {});
}
_controller = SwiperController();

// primaryPageController.addListener(() {
// if (isOnTap) {
// return;
// }
// if ((primaryPageController.page - tabController.index).abs() > 0.9) {
// tabController.animateTo(primaryPageController.page.floor());
// }
// });
super.initState();
}

@override
void dispose() {
tabController?.dispose();
primaryPageController?.dispose();
for (var item in widget.model?.typeList) {
item.primaryPageController?.dispose();
item.primaryPageController = null;
}
super.dispose();
}

@override
Widget build(BuildContext context) {
super.build(context);
print("构建数据");
return _getMainHasCategoryWidget(widget?.model);
}

Widget _getMainHasCategoryWidget(CustomQuickEntryModel model) {
bool hasCategory = false;
if (!EmptyUtil.isEmpty(model?.typeList) && model.typeList.length >= 2) {
hasCategory = true;
}

int maxTotal = 0;

///分类
if (model.typeList != null) {
for (var item in model?.typeList) {
item.listStyle = List();
if (item.primaryPageController == null) {
item.primaryPageController = PrimaryPageController(keepPage: true);
}
for (var listItem in model?.listStyle) {
if (listItem?.typeListKey == item.key) {
item.listStyle.add(listItem);
}
}
if (item.listStyle.length > maxTotal) {
maxTotal = item.listStyle.length;
}
}
}
pageList.clear();

// 数据总数
int totalDataSize = maxTotal;

// 展示的列数
int columSize = int.parse(model?.columSize ?? '5');

// 展示的总行数
int totalRowSize = int.parse(model?.rowSize ?? '2');

//计算实际显示行数
if (totalRowSize * columSize > totalDataSize) {
for (int index = 1; index <= totalRowSize; index++) {
if (index * columSize >= totalDataSize) {
totalRowSize = index;
break;
}
}
}

//计算实际显示行数
print("行数" + totalRowSize.toString());

// 图标的高度
double iconHeight = 40.0;
// 标题的高度
double titleHeight = 20.0;

// 子元素的高度
double itemHeight = iconHeight;

// 如果有一级标题
if (!EmptyUtil.isEmpty(model?.isShowTitle) && model.isShowTitle == '1') {
itemHeight = iconHeight + titleHeight;
}

//如果有二级标题
if (!EmptyUtil.isEmpty(model?.isShowSubTitle) && model.isShowSubTitle == '1') {
itemHeight = iconHeight + titleHeight * 2;
}

// 进度条的边距
double barMargin = 10.0;
// 总页数
int totalPage = totalDataSize % (totalRowSize * columSize) == 0 ? totalDataSize ~/ (totalRowSize * columSize) : (totalDataSize ~/ (totalRowSize * columSize)) + 1;

Logger.log('totalPage = ' + totalPage?.toString());
// 总体高度 = 行数 * (子元素高度 + 边距高度) + 进度条的高度
double totalHeight = totalRowSize * (itemHeight + barMargin);
if (totalPage > 1 && !EmptyUtil.isEmpty(model?.pagination) && model.pagination != 'type_null' /*model.pagination_open == '0'*/) {
totalHeight = totalRowSize * (itemHeight + barMargin)+8;
}

// 分类导航高度
double categoryHeight = 24;
// 分类导航到多眼导航的边距
double categoryBottomMargin = 20.0;

if (!EmptyUtil.isEmpty(model?.typeList) && model.typeList.length >= 2) {
totalHeight = totalHeight + categoryHeight + categoryBottomMargin;
hasCategory = true;
}

// 如果有左上角标题
double moduleTitleHeight = 22 + 10.0;
if (!EmptyUtil.isEmpty(model?.moduleTitleName)) {
totalHeight = totalHeight + moduleTitleHeight;
}

double marginLeftRight = model?.isLeftRightMargin == "1" ? double.tryParse(model?.leftRightMargin ?? "0") : 0;
double marginTop = model?.isTopMargin == "1" ? double.tryParse(model?.topMargin ?? "0") : 0;

int currentTypeIndex = 0;

for (var item in model.typeList) {
if ((item?.listStyle?.length??0) == 0) {
pageList.add(PageItem(index: currentTypeIndex, listStyle: List()));
currentTypeIndex++;
continue;
}

if (item.listStyle.length > totalRowSize) {
for (int index = 0; index < (item.listStyle.length / (columSize * totalRowSize)).ceil(); index++) {
var list = List<ListStyle>();
var startIndex = index * columSize * totalRowSize;
for (var i = 0; i < columSize * totalRowSize; i++) {
if (item.listStyle.length > startIndex + i) {
list.add(item.listStyle[startIndex+i]);
} else {
break;
}
}
pageList.add(PageItem(index: currentTypeIndex, listStyle: list));
}
}else{
pageList.add(PageItem(index: currentTypeIndex, listStyle: item?.listStyle));
}
currentTypeIndex++;
}

return Container(
margin: EdgeInsets.only(top: marginTop, left: marginLeftRight, right: marginLeftRight),
decoration: BoxDecoration(
color: HexColor.fromHex(model?.bgColor ?? ''),
//color: Colors.green,
borderRadius: BorderRadius.only(
topRight: Radius.circular(ParseUtil.stringParseDouble(model?.topRightRadius)),
topLeft: Radius.circular(ParseUtil.stringParseDouble(model?.topLeftRadius)),
bottomLeft: Radius.circular(ParseUtil.stringParseDouble(model?.bottomLeftRadius)),
bottomRight: Radius.circular(ParseUtil.stringParseDouble(model?.bottomRightRadius)),
)),
child: Container(
height: totalHeight+(totalRowSize*5),
margin: EdgeInsets.only(bottom: model?.pagination=="type_null"?0:8),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
hasCategory
? Container(
height: categoryHeight,
margin: EdgeInsets.only(top: 10,bottom: 10),
child: TabBar(
isScrollable: true,
onTap: (value) {
onTapTimer?.cancel();
isOnTap=true;
onTapTimer = Timer(Duration(milliseconds: 300), () {
isOnTap = false;
});
int current = 0;
for (var pageItem in pageList) {
if (pageItem.index == value) {
_controller.move(current);
print("跳转到" + current.toString());
break;
}
current++;
}
},
labelColor: HexColor.fromHex("#FFFFFF"),
unselectedLabelColor: HexColor.fromHex("#FF333333"),
labelStyle: TextStyle(fontSize: 14),
tabs: _buildTab(model),
controller: tabController,
indicatorSize: TabBarIndicatorSize.label,
indicatorColor: Colors.transparent,
indicator: BubbleTabIndicator(indicatorColor: HexColor.fromHex("#FF4242")),
),
)
: Container(),
Expanded(
child: Swiper(
controller: _controller,
itemCount: pageList.length ?? 0,
physics: BouncingScrollPhysics(),
loop: false,
onIndexChanged: (currentIndex) {
if (isOnTap) {
return;
}
tabController.animateTo(pageList[currentIndex].index);
},
itemBuilder: (context, index) {
var totalDataSize = pageList[index].listStyle.length ?? 0;
return Container(
height: double.infinity,
width: double.infinity,
padding: const EdgeInsets.symmetric(horizontal: 4),
child: _getCategoryPageWidget(
iconHeight: iconHeight,
titleHeight: titleHeight,
totalDataSize: totalDataSize,
totalPage: pageList?.length??0,
currentPage: index,
totalRowSize: totalRowSize,
columSize: columSize,
model: model,
itemHeight: itemHeight,
),
);
},
pagination: _getSwiperPaginationContorl(model, model?.typeList?.length ?? 0),
)),
],
),
),
);
}

_buildTab(CustomQuickEntryModel model) {
List<Widget> listWidget = List();
for (var item in model?.typeList) {
listWidget.add(Tab(
text: item.name,
));
}
return listWidget;
}

/// 获取有分类页
_getCategoryPageWidget(
{double titleHeight,
double iconHeight,
int totalPage,
int currentPage,
int columSize,
int totalRowSize,
int totalDataSize,
CustomQuickEntryModel model,
double itemHeight}) {
List rowList = [];
for (int i = 0; i < totalRowSize; i++) {
rowList.add(i);
}

return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: rowList.map((currentRow) {
return Container(
padding: EdgeInsets.only(bottom: 15),
width: double.infinity,
child: _buildHasCategoryRowWidget(
titleHeight: titleHeight,
iconHeight: iconHeight,
totalPage: totalPage,
currentPage: currentPage,
columSize: columSize,
totalRowSize: totalRowSize,
totalDataSize: totalDataSize,
model: model,
currentRow: currentRow,
itemHeight: itemHeight),
);
}).toList(),
);
}

///有分类行构建
Widget _buildHasCategoryRowWidget(
{double titleHeight,
double iconHeight,
int totalPage,
int currentPage,
int columSize,
int totalRowSize,
int totalDataSize,
CustomQuickEntryModel model,
int currentRow,
double itemHeight}) {
List itemList = [];
for (int i = 0; i < columSize; i++) {
itemList.add(i);
}
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: itemList.map((currentIndex) {
return _getHasCategoryColumWidget(
titleHeight: titleHeight,
iconHeight: iconHeight,
totalPage: totalPage,
currentPage: currentPage,
totalDataSize: totalDataSize,
columSize: columSize,
totalRowSize: totalRowSize,
model: model,
currentRow: currentRow,
currentColum: currentIndex,
itemHeight: itemHeight,
);
}).toList(),
);
}

/// item 的数据
Widget _getHasCategoryColumWidget({
double titleHeight,
double iconHeight,
int totalPage,
int currentPage,
int columSize,
int totalRowSize,
int totalDataSize,
CustomQuickEntryModel model,
int currentRow,
int currentColum,
double itemHeight,
}) {
// 当前index = 当前的页数+1 * 当前的行数 + 当前的列数
// int currentIndex = (currentPage + 1) * currentRow + currentColum + currentRow*columSize;
// int currentIndex = currentPage != 0 ? currentPage * (columSize * totalRowSize) + columSize + currentRow * columSize :
// currentColum + currentRow * columSize;

// 当前元素的下表 = 当前的列数 + 当前的行数 * 列数 + 当前的页数 * 当前的行数 + 当前的列数
int currentIndex = currentColum + currentRow * columSize ;
print("当前页"+currentPage.toString()+"当前点"+currentIndex.toString());

// print('current Index sss = $currentIndex');

if (currentIndex >= totalDataSize) {
return Container(
height: itemHeight,
width: 60,
);
}

ListStyle item = pageList[currentPage].listStyle[currentIndex];

return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () => _itemIconClick(item),
child: Container(
height: itemHeight,
width: 60,
// color: Colors.red,
child: Column(
children: <Widget>[
/// 图标
MyNetWorkImage(item.img),

/// 一级标题
Visibility(
visible: !EmptyUtil.isEmpty(model?.isShowTitle) && model.isShowTitle == '1',
child: Padding(
padding: const EdgeInsets.only(top: 5),
child: Text(
item?.title ?? '',
style: TextStyle(fontSize: 10, color: HexColor.fromHex(model?.titleColor)),
),
),
),

/// 二级标题
Visibility(
visible: !EmptyUtil.isEmpty(model?.isShowSubTitle) && model.isShowSubTitle == '1',
child: Padding(
padding: const EdgeInsets.only(top: 5),
child: Text(
item?.subTitle ?? '',
style: TextStyle(fontSize: 10, color: HexColor.fromHex(model?.subTitleColor)),
),
),
)
],
),
),
);
}

/// Icon点击事件
void _itemIconClick(ListStyle model) {
print("item type = ${model.skipIdentifier}");
// Navigator.push(context, CupertinoPageRoute(builder: (_) => CommonPage(null)));
RouterUtil.route(model, model.toJson(), context);
}

/// 进度条
SwiperPlugin _getSwiperPaginationContorl(CustomQuickEntryModel model, int pageCount) {
if (EmptyUtil.isEmpty(model?.pagination) || model.pagination == 'type_null' /*model.pagination_open == '0'*/) {
return null;
}

if (model.pagination == 'type_point') {
// 点点点进度条
return _swiperPaginationDot(model);
} else {
// 自定义进度条
return _swiperCustomPagination(pageCount);
}
}

// 进度条 圆形
SwiperPagination _swiperPaginationDot(CustomQuickEntryModel model) {
return SwiperPagination(
margin: const EdgeInsets.only(),
builder: DotSwiperPaginationBuilder(
color: HexColor.fromHex(model?.paginationUnselectColor), activeColor: HexColor.fromHex(model?.paginationSelectColor), size: 8, activeSize: 8));
}

// 自定义进度条 条形
SwiperPlugin _swiperCustomPagination(int pageCount) {
List list = [];
for (int i = 0; i < pageCount; i++) {
list.add(i);
}

return SwiperCustomPagination(builder: (BuildContext context, SwiperPluginConfig config) {
return Align(
alignment: Alignment(0.0, 1),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: list.map((index) {
var borderRadius;
if (index == 0) {
borderRadius = BorderRadius.only(topLeft: Radius.circular(2), bottomLeft: Radius.circular(2));
}
if (index == list.length - 1) {
borderRadius = BorderRadius.only(topRight: Radius.circular(2), bottomRight: Radius.circular(2));
}

if (index == config.activeIndex) {
borderRadius = BorderRadius.all(Radius.circular(2));
}

return Container(
height: 4,
width: 25,
decoration: BoxDecoration(borderRadius: borderRadius, color: index == config.activeIndex ? HexColor.fromHex('#FF4242') : HexColor.fromHex('#FFFFFF')),
);
}).toList(),
),
);
});
}

@override
// TODO: implement wantKeepAlive
bool get wantKeepAlive => true;
}

class PageItem {
int index;

PageItem({this.index, this.listStyle});

List<ListStyle> listStyle;
}

+ 4
- 0
lib/widgets/custom/multi_nav/model/custom_quick_entry_model.dart Переглянути файл

@@ -1,4 +1,5 @@
import 'package:zhiying_base_widget/dialog/global_dialog/intellect_search_goods_dialog/model/no_goods_dialog_style_model.dart';
import 'package:zhiying_base_widget/widgets/primary_page_view/primary_page_view.dart';
import 'package:zhiying_comm/zhiying_comm.dart';

class CustomQuickEntryModel {
@@ -191,6 +192,9 @@ class ListStyle extends SkipModel{
class TypeList {
String name;
String key;
List<ListStyle> listStyle;
PrimaryPageController primaryPageController;
int index;

TypeList({this.name, this.key});



+ 2
- 1
lib/widgets/goods_details/footer/goods_details_footer_widget.dart Переглянути файл

@@ -21,7 +21,7 @@ import 'package:zhiying_comm/util/turn_chain/turn_chain_util.dart';
class GoodsDetailsFooterWidget extends StatelessWidget {
final Map<String, dynamic> model;
final bool isFree;
const GoodsDetailsFooterWidget(this.model,{this.isFree});
const GoodsDetailsFooterWidget(this.model,{this.isFree=false});

@override
Widget build(BuildContext context) {
@@ -34,6 +34,7 @@ class GoodsDetailsFooterWidget extends StatelessWidget {
child: _GoodsDetailsFooterContainer(
model,
key: UniqueKey(),
isFree: isFree,
),
),
);


+ 5
- 4
lib/widgets/goods_details/upgrade_tip/upgrade_tip_widget.dart Переглянути файл

@@ -144,7 +144,7 @@ class _UpgradeTipWidgetState extends State<UpgradeTipWidget> {
return _isiOSReview ? Container() : Container(
width: double.infinity,
margin: EdgeInsets.only(top: ParseUtil.stringParseDouble(widget._model?.topMargin), left: ParseUtil.stringParseDouble(widget._model?.leftRightMargin), right: ParseUtil.stringParseDouble(widget._model?.leftRightMargin)),
padding: const EdgeInsets.only(left: 12.5, right: 12.5, top: 6, bottom: 6),
padding: const EdgeInsets.only(left: 10, right: 10, top: 0, bottom: 0),
decoration: BoxDecoration(
color: HexColor.fromHex(widget._model?.bgColor),
// color: Colors.white,
@@ -163,7 +163,7 @@ class _UpgradeTipWidgetState extends State<UpgradeTipWidget> {
color: HexColor.fromHex(widget._model?.bulletinBgColor ?? '#FFEFDA'),
borderRadius: BorderRadius.circular(30),
),
padding: const EdgeInsets.only(left: 10, right: 13, top: 10, bottom: 10),
padding: const EdgeInsets.only(left: 10,right: 10,top: 9.5, bottom: 9.5),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
@@ -185,19 +185,20 @@ class _UpgradeTipWidgetState extends State<UpgradeTipWidget> {
CachedNetworkImage(
imageUrl: model?.icon ?? '',
width: 15,
fit: BoxFit.fitWidth,
),

const SizedBox(width: 7.5),

/// 文字
Text(model?.bulletinText ?? '下载APP升级运营商,享受更多收益', style: TextStyle(color: HexColor.fromHex(model?.bulletinTextColor ?? '#C09023'), fontSize: 11))
Text(model?.bulletinText ?? '下载APP升级运营商,享受更多收益', style: TextStyle(color: HexColor.fromHex(model?.bulletinTextColor ?? '#C09023'), height: 1,fontSize: 11))
],
);
}

/// 右边的视图
Widget _getRightWidget(UpgradeTipModel model) {
return Text(model?.goText ?? '前往下载', style: TextStyle(color: HexColor.fromHex(model?.bulletinTextColor ?? '#C09023'), fontSize: 11));
return Text(model?.goText ?? '前往下载', style: TextStyle(color: HexColor.fromHex(model?.bulletinTextColor ?? '#C09023'),height: 1, fontSize: 11));
// return Row(
// children: <Widget>[
// Text(model?.go_text ??'前往下载', style: TextStyle(color: HexColor.fromHex('#C09023'), fontSize: 11)),


+ 34
- 31
lib/widgets/mine/mine_header/mine_header_container.dart Переглянути файл

@@ -102,38 +102,41 @@ class _MineHeaderContainerState extends State<MineHeaderContainer> {
fontSize: 17, color: HexColor.fromHex(widget.staticModel.userNameColor)),
),
),
Container(
height: 18,
margin: EdgeInsets.only(left: 6),
padding: EdgeInsets.only(left: 6, right: 6),
decoration: boxDecoration,
// BoxDecoration(
// image: DecorationImage(
// fit: BoxFit.fitWidth,
// image: NetworkImage(
// widget.staticModel.lvBgImage,
//
// )),
// // color: HexColor.fromHex(widget.staticModel.bgColor),
// // borderRadius: BorderRadius.circular(9)
// ),
child: Row(
children: <Widget>[
Container(
width: 12,
height: 12,
margin: EdgeInsets.only(right: 2),
child: CachedNetworkImage(
imageUrl: profile?.userLvIcon ?? '',
fit: BoxFit.contain,
Visibility(
visible: (widget?.staticModel?.status??"1")=="1"?true:false,
child: Container(
height: 18,
margin: EdgeInsets.only(left: 6),
padding: EdgeInsets.only(left: 6, right: 6),
decoration: boxDecoration,
// BoxDecoration(
// image: DecorationImage(
// fit: BoxFit.fitWidth,
// image: NetworkImage(
// widget.staticModel.lvBgImage,
//
// )),
// // color: HexColor.fromHex(widget.staticModel.bgColor),
// // borderRadius: BorderRadius.circular(9)
// ),
child: Row(
children: <Widget>[
Container(
width: 12,
height: 12,
margin: EdgeInsets.only(right: 2),
child: CachedNetworkImage(
imageUrl: profile?.userLvIcon ?? '',
fit: BoxFit.contain,
),
),
),
Text(
profile?.userLvName ?? '',
style: TextStyle(
fontSize: 10, color: HexColor.fromHex(widget.staticModel.lvNameColor)),
)
],
Text(
profile?.userLvName ?? '',
style: TextStyle(
fontSize: 10, color: HexColor.fromHex(widget.staticModel.lvNameColor)),
)
],
),
),
),
],


+ 2
- 0
lib/widgets/mine/mine_header/model/mine_header_model.dart Переглянути файл

@@ -30,6 +30,7 @@ class MineHeaderModel {
int requiredLogin;
int requiredTaobaoAuth;
String skipIdentifier;
String status;

MineHeaderModel(
{this.name,
@@ -96,6 +97,7 @@ class MineHeaderModel {
requiredLogin = json['required_login'];
requiredTaobaoAuth = json['required_taobao_auth'];
skipIdentifier = json['skip_identifier'];
status=json['status'];
}

Map<String, dynamic> toJson() {


+ 980
- 0
lib/widgets/primary_page_view/primary_page_view.dart Переглянути файл

@@ -0,0 +1,980 @@

import 'dart:async';
import 'dart:math' as math;

import 'package:flutter/material.dart';
import 'package:flutter/physics.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/gestures.dart' show Drag, DragStartBehavior;
import 'package:flutter/foundation.dart' show precisionErrorTolerance;

///支持嵌套滑动的pageView
///需要开启Primary=true
class PrimaryPageController extends ScrollController {
PrimaryPageController({
this.initialPage = 0,
this.keepPage = true,
this.viewportFraction = 1.0,
this.coordinator,
}) : assert(initialPage != null),
assert(keepPage != null),
assert(viewportFraction != null),
assert(viewportFraction > 0.0);

int initialPage;

final bool keepPage;

final double viewportFraction;

PrimaryPageCoordinator coordinator;

List<PrimaryPageController> childPageController = [];

double get page {
assert(
positions.isNotEmpty,
'PrimaryPageController.page cannot be accessed before a NestedPrimaryPageView is built with it.',
);
assert(
positions.length == 1,
'The page property cannot be read when multiple PageViews are attached to '
'the same PrimaryPageController.',
);
final PrimaryPagePosition position = this.position;
return position.page;
}

Future<void> animateToPage(
int page, {
@required Duration duration,
@required Curve curve,
}) {
final PrimaryPagePosition position = this.position;
return position.animateTo(
position.getPixelsFromPage(page.toDouble()),
duration: duration,
curve: curve,
);
}

void jumpToPage(int page) {
final PrimaryPagePosition position = this.position;
position.jumpTo(position.getPixelsFromPage(page.toDouble()));
}

Future<void> nextPage({@required Duration duration, @required Curve curve}) {
return animateToPage(page.round() + 1, duration: duration, curve: curve);
}

Future<void> previousPage(
{@required Duration duration, @required Curve curve}) {
return animateToPage(page.round() - 1, duration: duration, curve: curve);
}

@override
ScrollPosition createScrollPosition(ScrollPhysics physics,
ScrollContext context, ScrollPosition oldPosition) {
PrimaryPagePosition result = PrimaryPagePosition(
physics: physics,
context: context,
initialPage: initialPage,
keepPage: keepPage,
viewportFraction: viewportFraction,
oldPosition: oldPosition,
)..coordinator = coordinator;

return result;
}

@override
void attach(ScrollPosition position) {
super.attach(position);
final PrimaryPagePosition pagePosition = position;
pagePosition.viewportFraction = viewportFraction;

if (position is PrimaryPagePosition) {
position.coordinator = coordinator;
}
}

@override
void detach(ScrollPosition position) {
super.detach(position);
}
}

class PrimaryPagePosition extends ScrollPosition
implements PageMetrics, ScrollActivityDelegate {
PrimaryPagePosition({
ScrollPhysics physics,
ScrollContext context,
this.initialPage = 0,
bool keepPage = true,
double viewportFraction = 1.0,
double initialPixels = 0.0,
ScrollPosition oldPosition,
}) : assert(initialPage != null),
assert(keepPage != null),
assert(viewportFraction != null),
assert(viewportFraction > 0.0),
_viewportFraction = viewportFraction,
_pageToUseOnStartup = initialPage.toDouble(),
super(
physics: physics,
context: context,
keepScrollOffset: keepPage,
oldPosition: oldPosition,
) {
if (activity == null) goIdle();
assert(activity != null);
}

final int initialPage;
double _pageToUseOnStartup;

@override
double get viewportFraction => _viewportFraction;
double _viewportFraction;

PrimaryPageCoordinator coordinator;

set viewportFraction(double value) {
if (_viewportFraction == value) return;
final double oldPage = page;
_viewportFraction = value;
if (oldPage != null) forcePixels(getPixelsFromPage(oldPage));
}

double get _initialPageOffset =>
math.max(0, viewportDimension * (viewportFraction - 1) / 2);

ScrollActivity get scrollActivity => activity;

double getPageFromPixels(double pixels, double viewportDimension) {
final double actual = math.max(0.0, pixels - _initialPageOffset) /
math.max(1.0, viewportDimension * viewportFraction);
final double round = actual.roundToDouble();
if ((actual - round).abs() < precisionErrorTolerance) {
return round;
}
return actual;
}

double getPixelsFromPage(double page) {
return page * viewportDimension * viewportFraction + _initialPageOffset;
}

@override
double get page {
assert(
pixels == null || (minScrollExtent != null && maxScrollExtent != null),
'Page value is only available after content dimensions are established.',
);
return pixels == null
? null
: getPageFromPixels(
pixels.clamp(minScrollExtent, maxScrollExtent), viewportDimension);
}

@override
void saveScrollOffset() {
PageStorage.of(context.storageContext)?.writeState(
context.storageContext, getPageFromPixels(pixels, viewportDimension));
}

@override
void restoreScrollOffset() {
if (pixels == null) {
final double value = PageStorage.of(context.storageContext)
?.readState(context.storageContext);
if (value != null) _pageToUseOnStartup = value;
}
}

@override
bool applyViewportDimension(double viewportDimension) {
final double oldViewportDimensions = this.viewportDimension;
final bool result = super.applyViewportDimension(viewportDimension);
final double oldPixels = pixels;
final double page = (oldPixels == null || oldViewportDimensions == 0.0)
? _pageToUseOnStartup
: getPageFromPixels(oldPixels, this.viewportDimension);
final double newPixels = getPixelsFromPage(page);

if (newPixels != oldPixels) {
correctPixels(newPixels);
return false;
}
return result;
}

@override
bool applyContentDimensions(double minScrollExtent, double maxScrollExtent) {
final double newMinScrollExtent = minScrollExtent + _initialPageOffset;
return super.applyContentDimensions(
newMinScrollExtent,
math.max(newMinScrollExtent, maxScrollExtent - _initialPageOffset),
);
}

@override
PageMetrics copyWith({
double minScrollExtent,
double maxScrollExtent,
double pixels,
double viewportDimension,
AxisDirection axisDirection,
double viewportFraction,
}) {
return PageMetrics(
minScrollExtent: minScrollExtent ?? this.minScrollExtent,
maxScrollExtent: maxScrollExtent ?? this.maxScrollExtent,
pixels: pixels ?? this.pixels,
viewportDimension: viewportDimension ?? this.viewportDimension,
axisDirection: axisDirection ?? this.axisDirection,
viewportFraction: viewportFraction ?? this.viewportFraction,
);
}

/// Velocity from a previous activity temporarily held by [hold] to potentially
/// transfer to a next activity.
double _heldPreviousVelocity = 0.0;

@override
AxisDirection get axisDirection => context.axisDirection;

@override
double setPixels(double newPixels) {
print("current position:" + newPixels.toString());

return super.setPixels(newPixels);
}

@override
void absorb(ScrollPosition other) {
super.absorb(other);
if (other is! ScrollPositionWithSingleContext) {
goIdle();
return;
}
activity.updateDelegate(this);
final PrimaryPagePosition typedOther = other;
_userScrollDirection = typedOther._userScrollDirection;
assert(_currentDrag == null);
if (typedOther._currentDrag != null) {
_currentDrag = typedOther._currentDrag;
_currentDrag.updateDelegate(this);
typedOther._currentDrag = null;
}
}

@override
void applyNewDimensions() {
super.applyNewDimensions();
context.setCanDrag(physics.shouldAcceptUserOffset(this));
}

@override
void beginActivity(ScrollActivity newActivity) {
_heldPreviousVelocity = 0.0;
if (newActivity == null) return;
super.beginActivity(newActivity);
_currentDrag?.dispose();
_currentDrag = null;
if (!activity.isScrolling) updateUserScrollDirection(ScrollDirection.idle);
}

@override
void applyUserOffset(double delta) {
updateUserScrollDirection(
delta > 0.0 ? ScrollDirection.forward : ScrollDirection.reverse);
setPixels(pixels - physics.applyPhysicsToUserOffset(this, delta));
}

@override
void goIdle() {
beginActivity(IdleScrollActivity(this));
}

/// Start a physics-driven simulation that settles the [pixels] position,
/// starting at a particular velocity.
///
/// This method defers to [ScrollPhysics.createBallisticSimulation], which
/// typically provides a bounce simulation when the current position is out of
/// bounds and a friction simulation when the position is in bounds but has a
/// non-zero velocity.
///
/// The velocity should be in logical pixels per second.
@override
void goBallistic(double velocity) {
assert(pixels != null);
final Simulation simulation =
physics.createBallisticSimulation(this, velocity);
if (simulation != null) {
beginActivity(BallisticScrollActivity(this, simulation, context.vsync));
} else {
goIdle();
}
}

@override
ScrollDirection get userScrollDirection => _userScrollDirection;
ScrollDirection _userScrollDirection = ScrollDirection.idle;

/// Set [userScrollDirection] to the given value.
///
/// If this changes the value, then a [UserScrollNotification] is dispatched.
@protected
@visibleForTesting
void updateUserScrollDirection(ScrollDirection value) {
assert(value != null);
if (userScrollDirection == value) return;
_userScrollDirection = value;
didUpdateScrollDirection(value);
}

@override
Future<void> animateTo(
double to, {
@required Duration duration,
@required Curve curve,
}) {
if (nearEqual(to, pixels, physics.tolerance.distance)) {
// Skip the animation, go straight to the position as we are already close.
jumpTo(to);
return Future<void>.value();
}

final DrivenScrollActivity activity = DrivenScrollActivity(
this,
from: pixels,
to: to,
duration: duration,
curve: curve,
vsync: context.vsync,
);
beginActivity(activity);
return activity.done;
}

@override
void jumpTo(double value) {
goIdle();
if (pixels != value) {
final double oldPixels = pixels;
forcePixels(value);
notifyListeners();
didStartScroll();
didUpdateScrollPositionBy(pixels - oldPixels);
didEndScroll();
}
goBallistic(0.0);
}

@Deprecated(
'This will lead to bugs.') // ignore: flutter_deprecation_syntax, https://github.com/flutter/flutter/issues/44609
@override
void jumpToWithoutSettling(double value) {
goIdle();
if (pixels != value) {
final double oldPixels = pixels;
forcePixels(value);
notifyListeners();
didStartScroll();
didUpdateScrollPositionBy(pixels - oldPixels);
didEndScroll();
}
}

@override
ScrollHoldController hold(VoidCallback holdCancelCallback) {
if (coordinator != null && coordinator.isOuterControllerEnable()) {
return coordinator.hold(holdCancelCallback);
} else {
final double previousVelocity = activity.velocity;
final HoldScrollActivity holdActivity = HoldScrollActivity(
delegate: this,
onHoldCanceled: holdCancelCallback,
);
beginActivity(holdActivity);
_heldPreviousVelocity = previousVelocity;
return holdActivity;
}
}

ScrollDragController _currentDrag;

@override
Drag drag(DragStartDetails details, VoidCallback dragCancelCallback) {
if (coordinator != null && coordinator.isOuterControllerEnable()) {
return coordinator.drag(details, dragCancelCallback);
} else {
final ScrollDragController drag = ScrollDragController(
delegate: this.coordinator ?? this,
details: details,
onDragCanceled: dragCancelCallback,
carriedVelocity: physics.carriedMomentum(_heldPreviousVelocity),
motionStartDistanceThreshold: physics.dragStartDistanceMotionThreshold,
);
beginActivity(DragScrollActivity(this, drag));
assert(_currentDrag == null);
_currentDrag = drag;
return drag;
}
}

@override
void dispose() {
_currentDrag?.dispose();
_currentDrag = null;
super.dispose();
}

@override
void debugFillDescription(List<String> description) {
super.debugFillDescription(description);
description.add('${context.runtimeType}');
description.add('$physics');
description.add('$activity');
description.add('$userScrollDirection');
}

// Returns the amount of delta that was not used.
//
// Positive delta means going down (exposing stuff above), negative delta
// going up (exposing stuff below).
double applyClampedDragUpdate(double delta) {
assert(delta != 0.0);
// If we are going towards the maxScrollExtent (negative scroll offset),
// then the furthest we can be in the minScrollExtent direction is negative
// infinity. For example, if we are already overscrolled, then scrolling to
// reduce the overscroll should not disallow the overscroll.
//
// If we are going towards the minScrollExtent (positive scroll offset),
// then the furthest we can be in the minScrollExtent direction is wherever
// we are now, if we are already overscrolled (in which case pixels is less
// than the minScrollExtent), or the minScrollExtent if we are not.
//
// In other words, we cannot, via applyClampedDragUpdate, _enter_ an
// overscroll situation.
//
// An overscroll situation might be nonetheless entered via several means.
// One is if the physics allow it, via applyFullDragUpdate (see below). An
// overscroll situation can also be forced, e.g. if the scroll position is
// artificially set using the scroll controller.
final double min =
delta < 0.0 ? -double.infinity : math.min(minScrollExtent, pixels);
// The logic for max is equivalent but on the other side.
final double max =
delta > 0.0 ? double.infinity : math.max(maxScrollExtent, pixels);
final double oldPixels = pixels;
final double newPixels = (pixels - delta).clamp(min, max);
final double clampedDelta = newPixels - pixels;
if (clampedDelta == 0.0) return delta;
final double overscroll = physics.applyBoundaryConditions(this, newPixels);
final double actualNewPixels = newPixels - overscroll;
final double offset = actualNewPixels - oldPixels;
if (offset != 0.0) {
forcePixels(actualNewPixels);
didUpdateScrollPositionBy(offset);
}
return delta + offset;
}

// Returns the overscroll.
double applyFullDragUpdate(double delta) {
assert(delta != 0.0);
final double oldPixels = pixels;
// Apply friction:
final double newPixels =
pixels - physics.applyPhysicsToUserOffset(this, delta);
if (oldPixels == newPixels)
return 0.0; // delta must have been so small we dropped it during floating point addition
// Check for overscroll:
final double overscroll = physics.applyBoundaryConditions(this, newPixels);
final double actualNewPixels = newPixels - overscroll;
if (actualNewPixels != oldPixels) {
forcePixels(actualNewPixels);
didUpdateScrollPositionBy(actualNewPixels - oldPixels);
}
if (overscroll != 0.0) {
didOverscrollBy(overscroll);
return overscroll;
}
return 0.0;
}
}

class PrimaryPageCoordinator
implements ScrollActivityDelegate, ScrollHoldController {
PrimaryPageController _outerController;
PrimaryPageController _selfController;

ScrollDragController _currentDrag;

bool isOperateBody = false;

PrimaryPageCoordinator(PrimaryPageController selfController,
PrimaryPageController parentController) {
_selfController = selfController;
_selfController.coordinator = this;

_outerController = parentController;
_outerController.coordinator = this;

if (!_outerController.childPageController.contains(_selfController)) {
_outerController.childPageController.add(_selfController);
}
}

PrimaryPageController getOuterController() {
return _outerController;
}

bool isOuterControllerEnable() {
return _outerController != null && _outerController.hasClients;
}

PrimaryPageController getInnerController() {
return _selfController;
}

bool isInnerControllerEnable() {
return _selfController != null && _selfController.hasClients;
}

@override
void applyUserOffset(double delta) {
updateUserScrollDirection(
delta > 0.0 ? ScrollDirection.forward : ScrollDirection.reverse);

// PrimaryPagePosition innerPosition =
// (getInnerController().position as PrimaryPagePosition);
PrimaryPagePosition outPosition = isOuterControllerEnable()
? (getOuterController().position as PrimaryPagePosition)
: null;

// /// 如果不在头尾,且内部page可滑动
// if ((outPosition.pixels > outPosition?.minScrollExtent &&
// outPosition.pixels < outPosition?.maxScrollExtent) &&
// (delta < 0
// ? innerPosition.pixels < innerPosition.maxScrollExtent
// : innerPosition.pixels > innerPosition.minScrollExtent)) {
// isOperateBody = true;
// innerPosition.applyUserOffset(delta);
// return;
// }

/// 如果快速滑动,没结束掉动画那种,那么在这里判断下是否需要传给子Page
if ((outPosition.pixels >= outPosition?.minScrollExtent &&
outPosition.pixels <= outPosition?.maxScrollExtent)) {
// if (outPosition.pixels % outPosition.viewportDimension != 0) {
// outPosition.applyUserOffset(delta);
// return;
// }

if (getOuterController().childPageController.length >
outPosition.page.round()) {
PrimaryPageController currentChildPageController =
getOuterController().childPageController[outPosition.page.round()];

PrimaryPagePosition currentInnerPosition =
currentChildPageController.position;

if (delta < 0
? currentInnerPosition.pixels < currentInnerPosition.maxScrollExtent
: currentInnerPosition.pixels >
currentInnerPosition.minScrollExtent) {
isOperateBody = true;
outPosition.goBallistic(0.0);
currentInnerPosition.applyUserOffset(delta);
return;
}
}
}

/// 都不符合,那才通过外部滑动
isOperateBody = false;
outPosition.applyUserOffset(delta);
}

@override
AxisDirection get axisDirection => _outerController.position.axisDirection;

@override
void cancel() {
goBallistic(0.0);
}

@override
void goBallistic(double velocity) {
PrimaryPagePosition outPosition = isOuterControllerEnable()
? (getOuterController().position as PrimaryPagePosition)
: null;

if (getOuterController().childPageController.length >
outPosition.page.round()) {
PrimaryPageController currentChildPageController =
getOuterController().childPageController[outPosition.page.round()];

PrimaryPagePosition currentInnerPosition =
currentChildPageController.position;

// if (isOperateBody) {
if (!isOperateBody &&
(outPosition != null) &&
(outPosition.pixels > outPosition.minScrollExtent &&
outPosition.pixels < outPosition.maxScrollExtent)) {
outPosition.goBallistic(velocity);
currentInnerPosition.goBallistic(0.0);

_currentDrag?.dispose();
_currentDrag = null;

return;
}

if (isOperateBody && velocity > 0) {
if (currentInnerPosition.pixels < currentInnerPosition.maxScrollExtent &&
currentInnerPosition.pixels > currentInnerPosition.minScrollExtent) {
outPosition.goBallistic(0.0);
currentInnerPosition.goBallistic(velocity);
} else {
outPosition?.goBallistic(velocity);
currentInnerPosition.goBallistic(0.0);
}
} else {
if (currentInnerPosition.pixels < currentInnerPosition.maxScrollExtent) {
outPosition.goBallistic(0.0);
currentInnerPosition.goBallistic(velocity);
} else {
outPosition?.goBallistic(velocity);
currentInnerPosition.goBallistic(0.0);
}
}
}
_currentDrag?.dispose();
_currentDrag = null;
}

@override
void goIdle() {
beginActivity(IdleScrollActivity(this), IdleScrollActivity(this));
}

@override
double setPixels(double pixels) {
return 0.0;
}

ScrollHoldController hold(VoidCallback holdCancelCallback) {
beginActivity(
HoldScrollActivity(delegate: this, onHoldCanceled: holdCancelCallback),
HoldScrollActivity(delegate: this, onHoldCanceled: holdCancelCallback));

return this;
}

Drag drag(DragStartDetails details, VoidCallback dragCancelCallback) {
final ScrollDragController drag = ScrollDragController(
delegate: this,
details: details,
onDragCanceled: dragCancelCallback,
);

beginActivity(
DragScrollActivity(this, drag), DragScrollActivity(this, drag));

assert(_currentDrag == null);
_currentDrag = drag;
return drag;
}

void beginActivity(
ScrollActivity newOuterActivity, ScrollActivity newInnerActivity) {
getInnerController().position.beginActivity(newInnerActivity);
if (isOuterControllerEnable()) {
getOuterController().position.beginActivity(newOuterActivity);
}

_currentDrag?.dispose();
_currentDrag = null;

if ((newOuterActivity == null || !newOuterActivity.isScrolling) &&
(newInnerActivity == null || !newInnerActivity.isScrolling)) {
updateUserScrollDirection(ScrollDirection.idle);
}
}

ScrollDirection get userScrollDirection => _userScrollDirection;
ScrollDirection _userScrollDirection = ScrollDirection.idle;

void updateUserScrollDirection(ScrollDirection value) {
assert(value != null);
if (userScrollDirection == value) return;
_userScrollDirection = value;
getOuterController().position.didUpdateScrollDirection(value);
if (isOuterControllerEnable()) {
getInnerController().position.didUpdateScrollDirection(value);
}
}
}

const PageScrollPhysics _kPagePhysics = PageScrollPhysics();

class PrimaryPageView extends StatefulWidget {
/// Creates a scrollable list that works page by page from an explicit [List]
/// of widgets.
///
/// This constructor is appropriate for page views with a small number of
/// children because constructing the [List] requires doing work for every
/// child that could possibly be displayed in the page view, instead of just
/// those children that are actually visible.
PrimaryPageView({
Key key,
this.scrollDirection = Axis.horizontal,
this.reverse = false,
PrimaryPageController controller,
this.physics,
this.pageSnapping = true,
this.onPageChanged,
this.primary = false,
List<Widget> children = const <Widget>[],
this.dragStartBehavior = DragStartBehavior.start,
}) : childrenDelegate = SliverChildListDelegate(children),
super(key: key) {
if (controller == null) {
this.controller = PrimaryPageController();
} else {
this.controller = controller;
}
}

/// Creates a scrollable list that works page by page using widgets that are
/// created on demand.
///delta
/// This constructor is appropriate for page views with a large (or infinite)
/// number of children because the builder is called only for those children
/// that are actually visible.
///
/// Providing a non-null [itemCount] lets the [PrimaryPageView] compute the maximum
/// scroll extent.
///
/// [itemBuilder] will be called only with indices greater than or equal to
/// zero and less than [itemCount].
///
/// [PrimaryPageView.builder] by default does not support child reordering. If
/// you are planning to change child order at a later time, consider using
/// [PrimaryPageView] or [PrimaryPageView.custom].
PrimaryPageView.builder({
Key key,
this.scrollDirection = Axis.horizontal,
this.reverse = false,
PrimaryPageController controller,
this.physics,
this.pageSnapping = true,
this.onPageChanged,
@required IndexedWidgetBuilder itemBuilder,
int itemCount,
this.primary = false,
this.dragStartBehavior = DragStartBehavior.start,
}) : childrenDelegate =
SliverChildBuilderDelegate(itemBuilder, childCount: itemCount),
super(key: key) {
if (controller == null) {
this.controller = PrimaryPageController();
} else {
this.controller = controller;
}
}

PrimaryPageView.custom({
Key key,
this.scrollDirection = Axis.horizontal,
this.reverse = false,
PrimaryPageController controller,
this.physics,
this.pageSnapping = true,
this.onPageChanged,
@required this.childrenDelegate,
this.primary = false,
this.dragStartBehavior = DragStartBehavior.start,
}) : assert(childrenDelegate != null),
super(key: key) {
if (controller == null) {
this.controller = PrimaryPageController();
} else {
this.controller = controller;
}
}

/// The axis along which the page view scrolls.
///
/// Defaults to [Axis.horizontal].
final Axis scrollDirection;

/// Whether the page view scrolls in the reading direction.
///
/// For example, if the reading direction is left-to-right and
/// [scrollDirection] is [Axis.horizontal], then the page view scrolls from
/// left to right when [reverse] is false and from right to left when
/// [reverse] is true.
///
/// Similarly, if [scrollDirection] is [Axis.vertical], then the page view
/// scrolls from top to bottom when [reverse] is false and from bottom to top
/// when [reverse] is true.
///
/// Defaults to false.
final bool reverse;

/// An object that can be used to control the position to which this page
/// view is scrolled.
PrimaryPageController controller;

/// How the page view should respond to user input.
///
/// For example, determines how the page view continues to animate after the
/// user stops dragging the page view.
///
/// The physics are modified to snap to page boundaries using
/// [PageScrollPhysics] prior to being used.
///
/// Defaults to matching platform conventions.
final ScrollPhysics physics;

/// Set to false to disable page snapping, useful for custom scroll behavior.
final bool pageSnapping;

/// Called whenever the page in the center of the viewport changes.
final ValueChanged<int> onPageChanged;

/// A delegate that provides the children for the [PrimaryPageView].
///
/// The [PrimaryPageView.custom] constructor lets you specify this delegate
/// explicitly. The [PrimaryPageView] and [PrimaryPageView.builder] constructors create a
/// [childrenDelegate] that wraps the given [List] and [IndexedWidgetBuilder],
/// respectively.
final SliverChildDelegate childrenDelegate;

/// {@macro flutter.widgets.scrollable.dragStartBehavior}
final DragStartBehavior dragStartBehavior;

final bool primary;

@override
_PageViewState createState() => _PageViewState();
}

class _PageViewState extends State<PrimaryPageView> {
int _lastReportedPage = 0;

@override
void initState() {
super.initState();
_lastReportedPage = widget.controller.initialPage;
}

@override
void didChangeDependencies() {
super.didChangeDependencies();
}

AxisDirection _getDirection(BuildContext context) {
switch (widget.scrollDirection) {
case Axis.horizontal:
assert(debugCheckHasDirectionality(context));
final TextDirection textDirection = Directionality.of(context);
final AxisDirection axisDirection =
textDirectionToAxisDirection(textDirection);
return widget.reverse
? flipAxisDirection(axisDirection)
: axisDirection;
case Axis.vertical:
return widget.reverse ? AxisDirection.up : AxisDirection.down;
}
return null;
}

@override
Widget build(BuildContext context) {
final AxisDirection axisDirection = _getDirection(context);
final ScrollPhysics physics = widget.pageSnapping
? _kPagePhysics.applyTo(widget.physics)
: widget.physics;

final ScrollController scrollController = widget.primary
? PrimaryScrollController.of(context)
: widget.controller;

if (widget.primary && scrollController is PrimaryPageController) {
scrollController.initialPage = _lastReportedPage;
PrimaryPageCoordinator(widget.controller, scrollController);
}

return NotificationListener<ScrollNotification>(
onNotification: (ScrollNotification notification) {
if (notification.depth == 0 &&
widget.onPageChanged != null &&
notification is ScrollUpdateNotification) {
final PageMetrics metrics = notification.metrics;
final int currentPage = metrics.page.round();
if (currentPage != _lastReportedPage) {
_lastReportedPage = currentPage;
widget.onPageChanged(currentPage);
}
}
return false;
},
child: Scrollable(
/// magic code,魔法代码勿动……这个key很重要
/// 如果PrimaryPageView下面还有多个同级PrimaryPageView,
/// 那么竟然会导致父PrimaryPageView识别为子PrimaryPageView
/// 进而在didUpdateWidget中解绑父PrimaryPageView中controller绑定的position
/// 并将其赋予给子PrimaryPageView的controller
/// 这样就导致父PrimaryPageView就这么神奇的丢失了自己的position……
/// 进而无法触发任何父PrimaryPageView的滑动事件
/// 不知道是我的问题还是flutter的问题
/// 不过既然知道原因了
/// 用key打个补丁,加上个身份证就好了……有空研究下这个神奇的问题
key: Key(widget.controller.toString()),
dragStartBehavior: widget.dragStartBehavior,
axisDirection: axisDirection,
controller: widget.controller,
physics: physics,
viewportBuilder: (BuildContext context, ViewportOffset position) {
return Viewport(
cacheExtent: 0.0,
axisDirection: axisDirection,
offset: position,
slivers: <Widget>[
PrimaryScrollController(
controller: widget.controller,
child: SliverFillViewport(
viewportFraction: widget.controller.viewportFraction,
delegate: widget.childrenDelegate,
)),
],
);
},
),
);
}

@override
void debugFillProperties(DiagnosticPropertiesBuilder description) {
super.debugFillProperties(description);
description
.add(EnumProperty<Axis>('scrollDirection', widget.scrollDirection));
description.add(
FlagProperty('reverse', value: widget.reverse, ifTrue: 'reversed'));
description.add(DiagnosticsProperty<PrimaryPageController>(
'controller', widget.controller,
showName: false));
description.add(DiagnosticsProperty<ScrollPhysics>(
'physics', widget.physics,
showName: false));
description.add(FlagProperty('pageSnapping',
value: widget.pageSnapping, ifFalse: 'snapping disabled'));
}
}

+ 20
- 3
lib/widgets/share/share_alert.dart Переглянути файл

@@ -34,8 +34,14 @@ class _ShareAlertState extends State<ShareAlert> {
@override
void initState() {
NetUtil.request('/api/v1/mod/${widget.skipIdentifier}', method: NetMethod.GET, onCache: (data) {
_parseData(data);
// try{
// _parseData(data);
// }catch(e){
// print(e);
// }

}, onSuccess: (data) {
print(data);
_parseData(data);
}, onError: (err) {});

@@ -247,9 +253,20 @@ class _ShareAlertContentState extends State<_ShareAlertContent> {
);
}
} else {

var type=SSDKContentTypes.auto;

if(widget?.model?.image?.first!=null&&widget.model?.url!=null){
type=SSDKContentTypes.webpage;
}else if(widget?.model?.image?.first!=null){
type=SSDKContentTypes.image;
}else if(widget?.model?.title!=null||widget.model?.content!=null){
type=SSDKContentTypes.text;
}

params = SSDKMap()
..setGeneral(
widget.model?.title ?? '',
widget.model?.title ?? '123',
widget.model?.content ?? '',
Platform.isIOS ? widget.model.image : null,
Platform.isAndroid ? widget?.model?.image?.first : null,
@@ -259,7 +276,7 @@ class _ShareAlertContentState extends State<_ShareAlertContent> {
null,
null,
null,
SSDKContentTypes.auto,
type,
);
}
SharesdkPlugin.share(plateform, params, (SSDKResponseState state, Map userdata, Map contentEntity, SSDKError error) {


Завантаження…
Відмінити
Зберегти