iOS 优化分享面板和提示小红点

这个星期根据项目的需求了解了几个新的知识点,基本上都有让我“哇”出声,趁着双休日整理了一些,现在记录下来。


分享

1.UIActivityViewController实现分享面板
2.微信分享
3.分享对比(Umeng、系统原生)

- tabBar提示小红点

1.系统原生实现方法
2.自定义实现
3.区别简述

分享

1.UIActivityViewController实现分享面板

关于UIActivityViewController的讲解(英)
cocoachina关于UIActivityViewController的翻译

苹果系统原生分享

在使用苹果相册的时候会发现分享的功能,但是一只没有深究。估计有很多人跟我一样一直使用类似Umeng的平台,并不知道或者没有研究过苹果原生的分享控件。这个分享控件是苹果在iOS 7就引入的,弹出的格式基本如上图,里面框架为:

整体弹出框 ---- UIActivityViewController类 --- 的子类
类似(“李周微信”)的分享项是---UIActivity类 ---- 的子类。

所以在实现一个分享弹出框的界面时,只需要提供对应相关分享平台的item,再将其添加到弹出框类中,最后present即可。

逻辑大概知道后,接下来就是如何实现。

步骤一 为微信分享创建一个item
#import "WxActivity.h"

static NSString *const LZActivityType_WX = @"LZActivityType_WX";

@implementation WxActivity

-(UIActivityType)activityType
{
    return LZActivityType_WX;
}

+(UIActivityCategory)activityCategory
{
    return UIActivityCategoryShare;
}
-(NSString *)activityTitle
{
    return @"李周微信";
}
-(UIImage *)activityImage
{
    return [UIImage imageNamed:@"weChat"];
}
-(void)performActivity
{
    [self activityDidFinish:YES];
}

上面的代码中出现了两个比较重要的属性:
activityCategory:

typedef NS_ENUM(NSInteger, UIActivityCategory) {
    UIActivityCategoryAction,   //行为
    UIActivityCategoryShare,  //分享
} NS_ENUM_AVAILABLE_IOS(7_0) __TVOS_PROHIBITED;

UIActivityCategoryAction -> activityType

UIActivityTypePrint   //打印机
UIActivityTypeCopyToPasteboard  //剪贴板
UIActivityTypeAssignToContact  //联系人
UIActivityTypeSaveToCameraRoll   //相机
UIActivityTypeAddToReadingList   //阅读清单
UIActivityTypeAirDrop    //AirDrop

UIActivityCategoryShare -> activityType:

UIActivityTypeMessage //分享到信息
UIActivityTypeMail   //分享到邮件
UIActivityTypePostToFacebook   //分享到Facebook
UIActivityTypePostToTwitter    //分享到Twitter
UIActivityTypePostToFlickr     //分享到Flickr
UIActivityTypePostToVimeo   //分享到Vimeo
UIActivityTypePostToTencentWeibo    //分享到腾讯微博
UIActivityTypePostToWeibo   //分享到微博

步骤二 创建分享弹出框,并添加items

-(instancetype)initWithActivityControllerWithContent:(NSArray *)activityContent
{
    NSArray *items = @[self.wxShareItem];
    
    if (self = [super initWithActivityItems:activityContent applicationActivities:items]) {
        
    }
    return self;
}

但是在将该弹框present出来时,会发现分享面板中item的图标并没有显示我们设置的图片。


图标不显示问题

是由于item是自定义项,所以在item的子类中需要重写:

-(BOOL)canPerformWithActivityItems:(NSArray *)activityItems
{
        return YES;
}

2.微信分享

微信分享官方文档

了解了系统原生的弹出框,生成了分享面板之后,就不需要一些第三方平台的操作显示了,可以直接和需要分享的平台进行交互。所以直接整理了微信的官方文档,其实结构、说明非常的简单清晰。以下将我理解框架的步骤和问题列举出来:

步骤一 理解你是主动发送消息给微信还是被动

如果你想要主动从自己的移动客户端发送如分享数据到微信中,那么使用 ----sendReq方法 ----发送数据

/*! @brief 发送请求到微信,等待微信返回onResp
 *
 * 函数调用后,会切换到微信的界面。第三方应用程序等待微信返回onResp。微信在异步处理完成后一定会调用onResp。支持以下类型
 * SendMessageToWXReq。
 * @param req 具体的发送请求,在调用函数后,请自己释放。
 * @return 成功返回YES,失败返回NO。
 */
+(BOOL) sendReq:(BaseReq*)req;

那么对应的,从微信端收到你的数据之后的回应以---onResp方法给你的应用端:

/*! @brief 发送一个sendReq后,收到微信的回应
 *
 * 收到一个来自微信的处理结果。调用一次sendReq后会收到onResp。
 * 可能收到的处理结果有SendMessageToWXResp、SendAuthResp等。
 * @param resp具体的回应内容,是自动释放的
 */
-(void) onResp:(BaseResp*)resp;

其实很好理解 send之后,等待on,request之后,等待response。

那么如果你是被动的话,可能会先收到来自微信端的请求 ---onReq方法;客户端接受到请求后,将需要的数据响应给微信端 ---sendResp方法。

步骤二 了解你要发送什么内容给微信
/*! @brief 第三方程序发送消息至微信终端程序的消息结构体
 *
 * 第三方程序向微信发送信息需要传入SendMessageToWXReq结构体,信息类型包括文本消息和多媒体消息,
 * 分别对应于text和message成员。调用该方法后,微信处理完信息会向第三方程序发送一个处理结果。
 * @see SendMessageToWXResp
 */
@interface SendMessageToWXReq : BaseReq

如果是主动发送消息给微信端,那么一定是SendMessageToWXReq类作为sendReq的参数,有三个值得注意的属性:

/** 发送消息的文本内容
 * @note 文本长度必须大于0且小于10K
 */
@property (nonatomic, retain) NSString* text;
/** 发送消息的多媒体内容
 * @see WXMediaMessage
 */
@property (nonatomic, retain) WXMediaMessage* message;
/** 发送消息的类型,包括文本消息和多媒体消息两种,两者只能选择其一,不能同时发送文本和多媒体消息 */
@property (nonatomic, assign) BOOL bText;

如果只是分享 文本内容,那么直接设置text,并且设置bText为YES
如果是其他的内容,需要设置message属性,并设置bText为NO
其他内容就包括


可发送给微信的消息类型

3.分享对比(Umeng、系统原生)

如果你只是需要分享到类似微信的第三方平台,那么你会发现UIActivityViewController类只是将分享面板进行了封装,那么你势必要直接面对需要分享平台的开发操作以及流程等,当然1-2个平台的话这样做还不算很复杂;但是Umeng是将整个分享的流程进行了封装,只需要面对一套逻辑,就能处理所有平台的分享。
但是如果你有一些行为上的操作,发送message、mail或者打印等那么直接使用UIActivityViewController的相关行为类,让所有的操作变的更简单。
所有的选择还是需要基于你的需求而定。

tabBar提示小红点

在很多的项目中都会通过底部tabBar的小红点对用户进行一定行为上的引导,以下的两种方法是基于系统原生的tabBar而言,但是原理都是将小红点的View添加到相应的位置上。

① 系统原生小红点

 // 默认为nil
@property(nullable, nonatomic, copy) NSString *badgeValue; 
 //iOS 10引入,该设置的颜色为badge的背景色,如果设置为nil,显示默认的颜色--红色
@property (nonatomic, readwrite, copy, nullable) UIColor *badgeColor NS_AVAILABLE_IOS(10_0) 
//iOS 10 引入,根据控制状态以及提供的文本属性绘制badge文本
- (void)setBadgeTextAttributes:(nullable NSDictionary<NSString *,id> *)textAttributes forState:(UIControlState)state NS_AVAILABLE_IOS(10_0) 
//iOS 10 引入,放回之前setBadgeTextAttributes:forState:设置的状态
- (nullable NSDictionary<NSString *,id> *)badgeTextAttributesForState:(UIControlState)state NS_AVAILABLE_IOS(10_0) 

根据苹果提供的方法基本上能实现对小红点的控制,但是还是存在一些细节控制方面的问题。

问题1:小红点的位置
小红点显示位置图

咋一看的话,小红点好像是微微的覆盖了tabBarItem的image图层上面,切换来具体的来看看层级关系:


层级关系图

tabBarItem的image和badge都添加在UITabBarButton上,之间是处于同一层的关系。那么覆盖的效果是由于两者之间设置的默认相对位置。接下来我将小红点添加到第二个图标上,可以更明显的看到两者间的相对位置关系:


两个小红点对比图

前面三个图标都是带有白色的背景色,而最后一个只是单一的图标,所以很明显可是知道两者之间的相对位置设置。但是并没有发现直接能控制badge偏移量的值,应该是固定的默认值。

问题2:小红点的形状

上图已经很清楚的看出小红点是类似于一个椭圆的效果,并且会随着里面文本的长度变换而加宽,但是一般的应用而言超过100的提示文本都会设置为"99+",所以在宽度方面还OK。
如果你希望实现的小红点是规规矩矩的圆点或者固定大小而自适应字体的话,那么系统原生设置并不能满足你。

问题3:文本的设置

在小红点的文本设置中,苹果提供了设置TextAttributes的自定义方法,并且能基于不同的状态。如点击状态下的文本颜色:


点击状态下的文本设置图
问题4:小红点的消失

引导的作用就是在用户点击item的时候,使得该item上的小红点消失,但是没有发现系统提供的直接方法。

-(void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item
{
    if (item.tag == 3) {
        [self.changeVC.tabBarItem setBadgeColor:[UIColor clearColor]];
    }
}

① 自定义小红点

tabBar的层级结构

首先,明确一点:
小红点 -> UIView (添加到) UIView的子类上
而层级结构中,很明确的指出,有两个可以添加小红点的view:
UITabBarButton 和 UITabBarSwappableImageView
当然实现的过程中,也会出现一些问题。

问题1 如何选择添加到哪个View上
-(UIView *)bottomView
{
    UIView *tabBarItemBottom = [self valueForKey:@"_view"];
    for (UIView *subView in tabBarItemBottom.subviews) {
        if ([subView isKindOfClass:NSClassFromString(@"UITabBarSwappableImageView")]) {
            subView.layer.masksToBounds = 8;
            return subView;
        }
    }
    return tabBarItemBottom;
}

默认会添加到UITabBarSwappableImageView上。


效果图

我明明设置了在第二个item和第四个item上都设置了badge,为什么会只出现一个?

层级结构图

对于UITabBarSwappableImageView而言,会根据图标的大小而改变

UITabBarSwappableImageView的大小

所以如果你item的图片包括了背景色,添加到UITabBarSwappableImageView。
反之添加到UITabBarButton上。

问题2 实现过程

既然是在系统的tabBarItem上添加view,肯定是对UITabBarItem的扩展

#import "UITabBarItem+lzBottomTabBarItem.h"
#import "UIView+LzBadgeView.h"

@implementation UITabBarItem (lzBottomTabBarItem)

-(void)lz_showText:(NSString *)text
{
    [[self bottomView] lz_addBadgeWithText:text];
    [[self bottomView] lz_moveBadgeWithX:4 Y:3]; // 默认为系统badge所在的位置
}

-(void)hidden{
    [[self bottomView] pp_hiddenBadge];
}

-(UIView *)bottomView
{
    UIView *tabBarItemBottom = [self valueForKey:@"_view"];
    
    for (UIView *subView in tabBarItemBottom.subviews) {
        if ([subView isKindOfClass:NSClassFromString(@"UITabBarSwappableImageView")]) {
            subView.layer.masksToBounds = 8;
            
            return subView;
        }
    }
    return tabBarItemBottom;
}

3.区别简述

其实看苹果官方文档会发现,其实苹果可以帮我们做很多事,并且也能从每一个处理的细节中发现我们可以实现的最优解。当然所有的最优解永远基于你的需求。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,711评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,079评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,194评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,089评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,197评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,306评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,338评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,119评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,541评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,846评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,014评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,694评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,322评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,026评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,257评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,863评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,895评论 2 351

推荐阅读更多精彩内容