一个自定义分享页面引发的思考
引言
相信绝大多数人都用过或者正使用着UMeng分享,但是往往UMeng提供的分享样式满足不了我们的需求,例如我们想额外填加一些按钮(复制链接、举报等)。
目前在做的这个项目一开始是使用的UMeng的分享样式,准备上架时由于审核要求,我们需要加一个举报按钮,所以将"分享"按钮改为"更多"按钮,然后需要将举报放在分享的下面一行,并且查看别人的内容的时候需要显示举报,查看自己的内容的时候是不需要显示举报按钮的(谁还需要举报自己啊,哈哈),所以一个页面有两种状态;
同时因为有些平台不支持网页跳转登录,所以我们需要检查用户手机上面是否有安装该平台软件来显示页面,大致效果如下图:
当时需求只有微信、朋友圈、短信三个分享,为了赶进度,十分钟写完,当时的思路是:
整个页面是个UIView,点击更多的时候进行初始化,然后add到window上面;
页面最底下放置一个UIView来实现出现和隐藏的时候透明度在0-0.3之间渐变,添加点击手势响应Remove操作;
下面的主要操作区域放置一个背景颜色为rgb都是240的UIView,根据传入的type计算总高度,中间放置一个颜色为rgb都是224的UILabel做分割线,垂直方向动画移入和移出页面;
三个分享按钮+举报按钮都使用UIButton,设置图片和标题的EdgeInsets属性为UI所需样式,举报按钮根据传入的type控制;
布局页面的时候判断手机是否安装有微信,没有的话只显示短信分享;
使用delegate与调用分享的Controller通信;
然后适配一下,这样写最直接,但是代码量大,纯代码设置每个按钮的各项属性,还要根据用户是否安装某些软件来配置显示的按钮的坐标,扩展性不强,按钮不多还好,要是随着业务发展加入更多的分享平台,就很坑爹了。
当然有很多人使用的是UIActionSheet+UIScrollView实现,同样的道理,这样实现需要根据按钮是否显示来动态布局页面,需求变更就得重新布局,代码写着不爽。
下面说说我的思路。
正题
前几天群里有个哥们问我怎么在UMeng的界面上面加个复制按钮?显然不太好弄,于是本着负责任的态度,结合我这一年来学到的知识,重新梳理了一遍整个需求:
每组按钮可能需要组头来放置文字提示;
每个分享的按钮的图文样式需要方便随时调节;
根据用户手机是否安装某些平台来控制是否生成/显示某些按钮(所有按钮的坐标需要动态控制);
可能有两行可能有一行,也可能有很多行(后期可能会有其他需求);
一组按钮数量过多时,可能需要一行横向滑动显示,也可能需要纵向多行排布;
需要有显示和隐藏的动画效果;
最底部可能需要有个取消或者"X"按钮;
前面提到的几种方法,一旦更改需求,比如横向滑动改成纵向排布,代码写起来就会很痛苦,还是那句话,代码写起来要自己觉得爽才行,下面看看这些需求对应的解决方案:
组头、组尾、可能单行也可能多行的需求,最底部有个取消按钮,一个UITableView就能满足了,header、section、footer,根据dataSource可以非常方便地控制显示什么和显示与否;
按钮样式的调节和有可能横向排布或纵向排布,使用UICollectionView可以完美解决,UITableView的每一行里面放置一个UICollectionView,UICollectionViewCell就是按钮样式,调节样式改一个地方就行,排布方式setScrollDirection即可;
根据软件的安装状态来动态控制显示按钮,用到这两个控件,很显然我们只需要控制数据源就好了;
所以数据源的结构应该是这样的:
值得一提的思路
由于目前在重构公司项目,所以文章结尾给出来的Demo中,分享按钮事件没有使用Delegate去操作Controller,而是采用的OC的runtime反射调用,根据方法名反过来构造SEL方法,然后判断传入actionVC是否响应该方法,响应就performSelector执行;
同样的道理,其实model一样可以有个方法属性,但是这样写的话构造数据源所在的类必须声明实现该方法,并且需要引用model文件,本人的想法是简化操作,不要写太多没有必要的代码。
看看代码:
对于Controller的引用
@property (nonatomic, weak) id actionVC;
A.使用Dictionary
1.构造数据源
NSMutableDictionary *wechatDic = [[NSMutableDictionary alloc]initWithDictionary:@{@"imageName":@"wechat_icon", @"title":@"微信", @"actionName":@"shareToWeChatAction"}];
2.Item点击交互
NSDictionary *dic = _dataSource[indexPath.row];
NSString *actionStr = dic[@"actionName"];
SEL action = NSSelectorFromString(actionStr);
if ([self.actionVC respondsToSelector:action]) {
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"//去除警告
[self.actionVC performSelector:action withObject:nil];
}
B.使用model(使用的地方需要引入头文件和实现响应selector构造的方法)
1.构造数据源
M_Share *wechatModel = [[M_Share alloc]init];
wechatModel.title = @"微信";
wechatModel.imageName = @"wechat_icon";
wechatModel.selector = @selector(shareToWeChatAction);//所在类需要声明/实现该方法
[sectionOne addObject:wechatModel];
[_dataSource addObject:sectionOne];
2.Item点击交互
M_Share *shareModel = _dataSource[indexPath.row];
if ([self.actionVC respondsToSelector:shareModel.selector]) {
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"//去除警告
[self.actionVC performSelector:shareModel.selector withObject:nil];
}
值得一提的是,这里从逻辑上来讲没有任何问题,但是系统始终会报一个警告,看了一下前辈们的解决办法是加了一行代码去除leaks警告:
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
所以顺便了解一一下去除项目中不必要的警告的方法,比如方法的废弃警告,找到项目Target中的Build Phases下的Compile Sources,将里面想要过滤警告的item后面编辑写入-w后保存该文件里面的警告就过滤掉了。
最后
抽时间整理成Demo出来放到github上面了:UMengDiyShareDemo
感谢阅读,希望本文对你有帮助!
本人坐标杭州,后续我会陆续把工作中遇到的问题及解决方案分享出来,互相交流学习,本人QQ:815187811,欢迎结交[笑脸].