美文网首页iOS学习iOS Developerios实用开发技巧
iOS 优化分享面板和提示小红点

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

作者: 李周 | 来源:发表于2017-07-01 16:19 被阅读404次

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


分享

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.区别简述

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

相关文章

网友评论

    本文标题:iOS 优化分享面板和提示小红点

    本文链接:https://www.haomeiwen.com/subject/kbticxtx.html