ソースを参照

0208 新增朋友圈分享样式

tags/0.0.5
23028876916@qq.com 3年前
コミット
9ba63c4f93
5個のファイルの変更618行の追加8行の削除
  1. +9
    -7
      lib/template/goods_share_template/goods_share_template.dart
  2. +39
    -0
      lib/template/goods_share_template/qr_code.dart
  3. +1
    -1
      lib/widgets/share/models/share_data_model.dart
  4. +15
    -0
      lib/widgets/share/models/share_select_pic_model.dart
  5. +554
    -0
      lib/widgets/share/share_alert_select.dart

+ 9
- 7
lib/template/goods_share_template/goods_share_template.dart ファイルの表示

@@ -4,6 +4,7 @@ import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:zhiying_base_widget/pages/goods_share_page/models/goods_share_poster_model.dart';
import 'package:zhiying_base_widget/pages/goods_share_page/models/goods_share_poster_style_model.dart';
import 'package:zhiying_base_widget/template/goods_share_template/qr_code.dart';
import 'package:zhiying_base_widget/widgets/home/home_quick_entry/cached_network_image_util.dart';
import 'package:zhiying_comm/zhiying_comm.dart';

@@ -116,13 +117,14 @@ class GoodsShareTemplate extends StatelessWidget {
),
Column(
children: <Widget>[
Container(
margin: EdgeInsets.only(bottom: 12),
width: 124,
height: 124,
// color: Colors.redAccent,
child: Image.memory(convert.base64Decode(model.qrcode)),
),
QrCode(model.qrcode),
// Container(
// margin: EdgeInsets.only(bottom: 12),
// width: 124,
// height: 124,
// // color: Colors.redAccent,
// child: Image.memory(convert.base64Decode(model.qrcode)),
// ),
Container(
child: Row(
children: <Widget>[


+ 39
- 0
lib/template/goods_share_template/qr_code.dart ファイルの表示

@@ -0,0 +1,39 @@
import 'dart:typed_data';

import 'package:flutter/material.dart';
import 'dart:convert' as convert;

class QrCode extends StatefulWidget {
final String qrcode;

const QrCode(this.qrcode, {Key key}) : super(key: key);

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

class _QrCodeState extends State<QrCode> with AutomaticKeepAliveClientMixin {
Uint8List src;

@override
void initState() {
// TODO: implement initState
src = convert.base64Decode(widget.qrcode);
super.initState();
}

@override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.only(bottom: 12),
width: 124,
height: 124,
// color: Colors.redAccent,
child: Image.memory(src),
);
}

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

+ 1
- 1
lib/widgets/share/models/share_data_model.dart ファイルの表示

@@ -9,7 +9,7 @@ class ShareDataModel {
String title;
String content;
Uint8List poster; // 海报
List image; // 图片地址列表
List<String> image; // 图片地址列表
String url;

ShareDataModel({


+ 15
- 0
lib/widgets/share/models/share_select_pic_model.dart ファイルの表示

@@ -0,0 +1,15 @@
import 'package:zhiying_base_widget/pages/goods_share_page/models/goods_share_poster_model.dart';

class ShareSelectPicModel {
List<SharePicItem> picList;
GoodsSharePosterModel posterModel;

ShareSelectPicModel(this.posterModel, this.picList);
}

class SharePicItem {
String pic;
bool select = false;

SharePicItem(this.pic, this.select);
}

+ 554
- 0
lib/widgets/share/share_alert_select.dart ファイルの表示

@@ -0,0 +1,554 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
import 'dart:ui';
import 'dart:ui' as ui;

import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:flutter_swiper/flutter_swiper.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:share_extend/share_extend.dart';
import 'package:sharesdk_plugin/sharesdk_plugin.dart';
import 'package:zhiying_base_widget/dialog/loading/loading.dart';
import 'package:zhiying_base_widget/utils/image_download_util/image_download_util.dart';
import 'package:zhiying_base_widget/widgets/share/models/share_alert_model.dart';
import 'package:zhiying_base_widget/widgets/share/models/share_data_model.dart';
import 'package:zhiying_base_widget/widgets/share/models/share_icon_model.dart';
import 'package:zhiying_base_widget/widgets/share/share_alert_content.dart';
import 'package:zhiying_comm/zhiying_comm.dart';
import 'package:zhiying_base_widget/widgets/share/models/share_select_pic_model.dart';
import 'package:zhiying_base_widget/template/goods_share_template/goods_share_template.dart';

class ShareAlertSelect extends StatefulWidget {
final String skipIdentifier;
final bool isContentShow;
final ShareDataModel model;
final bool isPicShow;
final ShareSelectPicModel selectPicModel;

const ShareAlertSelect(this.model, this.skipIdentifier,
{Key key, this.isContentShow = false, this.selectPicModel, this.isPicShow})
: super(key: key); // 中间视图

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

class _ShareAlertSelectState extends State<ShareAlertSelect> {
ShareAlertModel _iconModel;
bool isPicShow;
ShareSelectPicModel selectPicModel;
GlobalKey _globalKey = GlobalKey();

@override
void initState() {
NetUtil.request('/api/v1/mod/${widget.skipIdentifier}', method: NetMethod.GET,
onCache: (data) {
// try{
// _parseData(data);
// }catch(e){
// print(e);
// }
}, onSuccess: (data) {
print(data);
_parseData(data);
}, onError: (err) {});

if (!EmptyUtil.isEmpty(widget.isPicShow)) {
isPicShow = widget.isPicShow;
} else {
isPicShow = false;
}
selectPicModel = widget.selectPicModel;
super.initState();
}

void _parseData(Map<String, dynamic> data) {
List modList = data['mod_list'];
Map d = modList.first;
if (d != null) {
String dString = d['data'];
_iconModel =
ShareAlertModel.fromJson(Map<String, dynamic>.from(jsonDecode(dString)));

setState(() {});
}
}

_selectPic(List<SharePicItem> picList, int position) async {
ShareDataModel model = ShareDataModel();
model.image = [];
for (int i = 0; i < picList.length; i++) {
if (picList[i].select) {
if (i == 0) {
ShareDataModel shareDataModel = await _updateModel(_globalKey);
model.poster = shareDataModel.poster;
} else {
model.image.add(picList[i].pic);
}
}
}
EventUtil.instance.fire(model);
}

Future<ShareDataModel> _updateModel(GlobalKey _globalKey) async {
ShareDataModel _shareModel = ShareDataModel();
BuildContext buildContext = _globalKey.currentContext;
if (null != buildContext) {
RenderRepaintBoundary boundary = buildContext.findRenderObject();
ui.Image image = await boundary.toImage(pixelRatio: 1);
// 注意:png是压缩后格式,如果需要图片的原始像素数据,请使用rawRgba
ByteData byteData = await image.toByteData(format: ui.ImageByteFormat.png);
Uint8List pngBytes = byteData.buffer.asUint8List();
_shareModel.poster = pngBytes;
} else {
_shareModel.poster = null;
}
// _shareModel.content = _isContentSelected ? _content : '';
return _shareModel;
}

@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async {
Loading.dismiss();
Navigator.canPop(context);
return true;
},
child: GestureDetector(
child: Scaffold(
backgroundColor: Colors.transparent,
body: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5), //背景
child: Container(
child: Column(
children: <Widget>[
widget.isContentShow
? Expanded(
child: Center(child: ShareAlertContent(_iconModel)),
)
: Container(),
isPicShow
? Expanded(
child: Swiper(
loop: false,
itemBuilder: (BuildContext context, int index) {
Widget picWidget;
if (index == 0) {
picWidget = Expanded(
child: Transform.scale(
alignment: Alignment.center,
scale: 0.75,
child: GoodsShareTemplate(
selectPicModel.posterModel,
contentKey: _globalKey,
),
),
);
} else {
picWidget = CachedNetworkImage(
imageUrl: selectPicModel.picList[index].pic,
fit: BoxFit.fitWidth,
);
}
return Container(
alignment: Alignment.bottomCenter,
margin: EdgeInsets.only(top: 50, bottom: 10),
child: Stack(
children: <Widget>[
picWidget,
// CachedNetworkImage(
// imageUrl: selectPicModel.picList[index].pic,
// fit: BoxFit.fitWidth,
// ),
Positioned(
bottom: 10,
right: 15,
child: GestureDetector(
onTap: () {
selectPicModel.picList[index].select =
!selectPicModel.picList[index].select;
setState(() {});
_selectPic(selectPicModel.picList, index);
},
child: Container(
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(50),
color: selectPicModel.picList[index].select
? Colors.red
: Colors.grey,
),
child: Icon(
CupertinoIcons.check_mark,
color: Colors.white,
),
),
),
)
],
),
);
},
itemCount: selectPicModel.picList.length,
viewportFraction: 0.8,
scale: 0.8,
),
)
: Container(),
_ShareAlertContent(
widget.model, widget.skipIdentifier, _iconModel, isPicShow),
],
),
), // 模糊化
),
),
onTap: () {
// Navigator.of(context).pop();
},
),
);
}
}

class _ShareAlertContent extends StatefulWidget {
final ShareDataModel model;
final String skipIdentifier;
final ShareAlertModel iconModel;
final bool isSelectPic;

const _ShareAlertContent(
this.model, this.skipIdentifier, this.iconModel, this.isSelectPic,
{Key key})
: super(key: key);

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

class _ShareAlertContentState extends State<_ShareAlertContent> {
StreamSubscription listen;
bool isSelectPic;

ShareDataModel _shareDataModel;

@override
void dispose() {
// TODO: implement dispose
listen?.cancel();
super.dispose();
}

@override
void initState() {
// TODO: implement initState
isSelectPic = widget.isSelectPic;

if (isSelectPic) {
_shareDataModel = null;
} else {
_shareDataModel = widget?.model;
}
listen = EventUtil.instance.on<ShareDataModel>().listen((ShareDataModel event) {
if (isSelectPic) {
_shareDataModel = event;
}
});

super.initState();
}

@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {},
child: Container(
width: double.infinity,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(12),
topRight: Radius.circular(12),
),
),
child: SafeArea(
top: false,
child: Column(
children: <Widget>[
Container(
margin: EdgeInsets.only(top: 8, bottom: 8),
width: 62,
height: 4,
decoration: BoxDecoration(
color: Color(0xffd8d8d8), borderRadius: BorderRadius.circular(2)),
),
Text(
'分享至',
style: TextStyle(
fontSize: 15, color: Color(0xff333333), fontWeight: FontWeight.bold),
),
Container(
margin: EdgeInsets.only(left: 12, right: 12, top: 10, bottom: 10),
child: _createIcons(),
),
GestureDetector(
child: Container(
margin: EdgeInsets.only(left: 12, right: 12, bottom: 10),
padding: EdgeInsets.all(12),
decoration: BoxDecoration(
color: Color(0xfff3f3f3), borderRadius: BorderRadius.circular(8)),
child: Center(
child: Text(
'取消',
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
color: Color(0xff999999)),
),
),
),
onTap: () {
Navigator.of(context).pop();
},
)
],
),
),
),
);
}

Widget _createIcons() {
return Wrap(
spacing: 10,
runSpacing: 10,
children: widget.iconModel?.icons?.map((item) {
return _createIcon(item);
})?.toList() ??
[],
);
}

Widget _createIcon(ShareIconModel item) {
return GestureDetector(
child: Container(
width: 60,
child: Column(
children: <Widget>[
Container(
width: 40,
height: 40,
child: CachedNetworkImage(
imageUrl: item.icon,
fit: BoxFit.contain,
),
),
Padding(
padding: const EdgeInsets.only(top: 2, bottom: 2),
child: Text(
item.name,
style: TextStyle(
fontSize: 12, color: Color(0xff333333), fontWeight: FontWeight.bold),
),
),
],
),
),
onTap: () async {
//检查是否有存储权限
var status = await Permission.storage.status;
if (!status.isGranted) {
status = await Permission.storage.request();
print(status);
return;
}

if (item.type == 'wx') {
_shareByMob(ShareSDKPlatforms.wechatSession);
} else if (item.type == 'pyq') {
_shareByMob(ShareSDKPlatforms.wechatTimeline);
} else if (item.type == 'qq') {
_shareByMob(ShareSDKPlatforms.qq);
} else if (item.type == 'qq_space') {
_shareByMob(ShareSDKPlatforms.qZone);
} else if (item.type == 'weibo') {
_shareByMob(ShareSDKPlatforms.sina);
} else if (item.type == 'more_setting') {
_shareBySystem();
}
},
);
}

// mob分享,只能单图分享,多图分享调用系统分享
void _shareByMob(ShareSDKPlatform plateform) async {
if (isSelectPic &&
EmptyUtil.isEmpty(_shareDataModel) &&
EmptyUtil.isEmpty(_shareDataModel?.poster) &&
EmptyUtil.isEmpty(_shareDataModel?.image)) {
Fluttertoast.showToast(msg: '请选择分享图片');
return;
}
int count = 0;
if (_shareDataModel.poster != null) {
count++;
}
count += (_shareDataModel?.image?.length ?? 0);
// 多图分享
if (count > 1) {
_shareMultipleImages();
return;
}

Loading.show(context);
Timer(Duration(milliseconds: 2000), () {
Loading.dismiss();
});

SSDKMap params;
if (_shareDataModel.poster != null) {
String path = await _savePoster();
if (path != null && path != '') {
params = SSDKMap()
..setGeneral(
_shareDataModel?.title ?? '',
_shareDataModel?.content ?? '',
Platform.isIOS ? path : null,
null,
Platform.isAndroid ? path : null,
null,
null,
null,
null,
null,
SSDKContentTypes.image,
);
}
} else {
var type = SSDKContentTypes.auto;

if (_shareDataModel?.image?.first != null && _shareDataModel?.url != null) {
type = SSDKContentTypes.webpage;
} else if (_shareDataModel?.image?.first != null) {
type = SSDKContentTypes.image;
} else if (_shareDataModel?.title != null || _shareDataModel?.content != null) {
type = SSDKContentTypes.text;
}
if (plateform == ShareSDKPlatforms.qZone) {
_shareDataModel?.title = null;
type = SSDKContentTypes.message;
}

params = SSDKMap()
..setGeneral(
_shareDataModel?.title ?? '',
_shareDataModel?.content ?? '',
Platform.isIOS ? _shareDataModel.image : null,
Platform.isAndroid ? _shareDataModel?.image?.first : null,
null,
_shareDataModel.url,
null,
null,
null,
null,
type,
);
}
SharesdkPlugin.share(plateform, params,
(SSDKResponseState state, Map userdata, Map contentEntity, SSDKError error) {
print(error);
if (state == SSDKResponseState.Fail) {
Fluttertoast.showToast(msg: '分享失败');
} else if (state == SSDKResponseState.Success) {
//Fluttertoast.showToast(msg: '分享成功');
} else if (state == SSDKResponseState.Cancel) {
Fluttertoast.showToast(msg: '取消分享');
}
Logger.debug('${state}, ${error.rawData}');
Loading.dismiss();
});
}

// 系统分享,只能分享图片或者文字,不能组合分享
void _shareBySystem() async {
if (isSelectPic &&
EmptyUtil.isEmpty(_shareDataModel) &&
EmptyUtil.isEmpty(_shareDataModel?.poster) &&
EmptyUtil.isEmpty(_shareDataModel?.image)) {
Fluttertoast.showToast(msg: '请选择分享图片');
return;
}
int count = 0;
if (_shareDataModel.poster != null) {
count++;
}
count += (_shareDataModel?.image?.length ?? 0);
// 多图分享
if (count > 1) {
_shareMultipleImages();
return;
}

if (_shareDataModel.poster != null) {
String path = await _savePoster();
if (path != null && path != '') {
ShareExtend.share(path, 'image');
}
} else {
ShareExtend.share(_shareDataModel.content, 'text');
}
}

Future<String> _savePoster() async {
String path;
if (_shareDataModel.poster != null) {
// 检查并请求权限
var status = await Permission.storage.status;
if (status != PermissionStatus.granted) {
status = await Permission.storage.request();
}
if (status == PermissionStatus.denied) {
Fluttertoast.showToast(msg: '暂无权限,分享失败');
return null;
}

try {
// 保存到本地路径
final tempDir = await getTemporaryDirectory();
final file = await File('${tempDir.path}/image.jpg').create();
file.writeAsBytesSync(_shareDataModel.poster);

path = file.path;
Logger.debug(file.path);
} catch (err, s) {
Logger.error(err.toString(), s.toString());
Fluttertoast.showToast(msg: '分享失败');
return null;
}
}
return path;
}

// 多图分享,调用系统分享
void _shareMultipleImages() async {
List<String> paths = List();
String path = await _savePoster();
if (path != null && path != '') {
paths.add(path);
}

Loading.show(context);
List<String> downPaths = await ImageDownloadUtil.download(_shareDataModel.image);
paths.addAll(downPaths);
ShareExtend.shareMultiple(paths, "image", subject: "");
Loading.dismiss();
}
}

読み込み中…
キャンセル
保存