天天看點

iOS截屏分享功能實作

産品經理今天提出一個新的需求,需要實作類似于每日優鮮、淘寶等用戶端的截屏分享的功能,即home+power截屏後彈出分享頁面,同時将截取到的圖檔放在目前頁面中展示,如下效果:

iOS截屏分享功能實作

之前沒有做過這樣的需求,但是實作過截屏相關的功能,故初步考慮擷取系統截屏事件,然後在該事件中利用程式截屏并按一定比例顯示在螢幕上,最後在該事件中調用友盟分享的方式實作了。

首先第一步是考慮如何擷取系統截屏的事件,查找之後發現蘋果在ios7之後提供了一個新的通知類型:UIApplicationUserDidTakeScreenshotNotification,這個通知會告知注冊了此通知的對象已經發生了截屏事件,然後我們就可以在這個事件中實作自己的邏輯。

一、注冊通知:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(screenShot) name:UIApplicationUserDidTakeScreenshotNotification object:nil];
           

二、實作接收到通知的方法

- (void)screenShot
{
    //每次截屏之前,删除之間添加的存放圖檔的imageView,不然重複截屏會不斷的截取到之前的頁面
    [self.photoIV removeFromSuperview];
    self.photoIV = nil;

    //截屏, 擷取所截圖檔(imageWithScreenshot在後面實作)
    UIImage *image = [self imageWithScreenshot];

    //添加顯示
    UIImageView *photoIV = [[UIImageView alloc]initWithImage:image];
    self.photoIV = photoIV;
    photoIV.frame = CGRectMake(, , [UIScreen mainScreen].bounds.size.width-, [UIScreen mainScreen].bounds.size.height-);

    /*為imageView添加邊框和陰影,以突出顯示*/
    //給imageView添加邊框
    CALayer * layer = [photoIV layer];
    layer.borderColor = [[UIColor whiteColor] CGColor];
    layer.borderWidth = f;

    //添加四個邊陰影
    photoIV.layer.shadowColor = [UIColor blackColor].CGColor;
    photoIV.layer.shadowOffset = CGSizeMake(, );
    photoIV.layer.shadowOpacity = ;
    photoIV.layer.shadowRadius = ;
    [self.view addSubview:photoIV];
    //調用顯示分享的頁面
    [self share];
}
           

三、截屏方法實作(網上直接找的比較全面的截屏方法,傳回一個NSData對象)

- (UIImage *)imageWithScreenshot
{
    CGSize imageSize = CGSizeZero;
    UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
    if (UIInterfaceOrientationIsPortrait(orientation))
        imageSize = [UIScreen mainScreen].bounds.size;
    else
        imageSize = CGSizeMake([UIScreen mainScreen].bounds.size.height, [UIScreen mainScreen].bounds.size.width);

    UIGraphicsBeginImageContextWithOptions(imageSize, NO, );
    CGContextRef context = UIGraphicsGetCurrentContext();
    for (UIWindow *window in [[UIApplication sharedApplication] windows])
    {
        CGContextSaveGState(context);
        CGContextTranslateCTM(context, window.center.x, window.center.y);
        CGContextConcatCTM(context, window.transform);
        CGContextTranslateCTM(context, -window.bounds.size.width * window.layer.anchorPoint.x, -window.bounds.size.height * window.layer.anchorPoint.y);
        if (orientation == UIInterfaceOrientationLandscapeLeft)
        {
            CGContextRotateCTM(context, M_PI_2);
            CGContextTranslateCTM(context, , -imageSize.width);
        }
        else if (orientation == UIInterfaceOrientationLandscapeRight)
        {
            CGContextRotateCTM(context, -M_PI_2);
            CGContextTranslateCTM(context, -imageSize.height, );
        } else if (orientation == UIInterfaceOrientationPortraitUpsideDown) {
            CGContextRotateCTM(context, M_PI);
            CGContextTranslateCTM(context, -imageSize.width, -imageSize.height);
        }
        if ([window respondsToSelector:@selector(drawViewHierarchyInRect:afterScreenUpdates:)])
        {
            [window drawViewHierarchyInRect:window.bounds afterScreenUpdates:YES];
        }
        else
        {
            [window.layer renderInContext:context];
        }
        CGContextRestoreGState(context);
    }

    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    NSData *imageData = UIImagePNGRepresentation(image);
    return [UIImage imageWithData:imageData];
}
           

補充:最近無意間發現一個更簡單快捷的擷取螢幕快照的方式:

  • (nullable UIView *)snapshotViewAfterScreenUpdates:(BOOL)afterUpdates

這個方法是蘋果在ios7之後為所有的UIView提供的一個新的API,如果使用這個方法來截屏的話就非常簡單了,簡單一句話搞定

UIView *snapView = [self.someView snapshotViewAfterScreenUpdates:NO];
           

這個方法的厲害之處還在于它可以截取目前視圖中的任意一個view,産生一個view的快照,以此來實作很多效果。

注意到,這個方法有一個參數AfterScreenUpdates,它有什麼用呢?官方文檔中是這麼說的:

當你要快照的時候,’afterUpdates’就确定了你的快照是目前螢幕中正在展示的還是包含那些view最近的改變。

比如下面這個例子:

- (void)layoutSubviews {
         UIView *snapshot = [self snapshotViewAfterScreenUpdates:YES];
         self.alpha = ;
     }
           

我們得到的結果會是一個空白的view,因為ScreenUpdates設定為YES,它會自動捕獲對self的更改,是以我們看到的是 self.alpha = 0.0的view。

但是這種方法截屏後是一個UIView的結果,截屏分享我們自然是分享一張圖檔,這個時候就用到如何将一個view轉成圖檔了,方法如下:

- (UIImage *)createImageWithView:(UIView *)view
{

    CGSize s = view.bounds.size;

//第一個參數表示區域大小。第二個參數表示是否是非透明的。如果需要顯示半透明效果,需要傳NO,否則傳YES。第三個參數就是螢幕密度了,設定為[UIScreen mainScreen].scale可以保證轉成的圖檔不失真。
    UIGraphicsBeginImageContextWithOptions(s, NO,[UIScreen mainScreen].scale);

    [view.layer renderInContext:UIGraphicsGetCurrentContext()];

    UIImage*image = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    return image;

}
           

四、分享的方法:

分享我使用的第三方的友盟分享最新版,導入以下頭檔案

#import <UMSocialCore/UMSocialCore.h>
#import <UShareUI/UShareUI.h>
#import <UMengUShare/WXApi.h>
           
- (void)share
{
    [UMSocialUIManager showShareMenuViewInWindowWithPlatformSelectionBlock:^(UMSocialPlatformType platformType, NSDictionary *userInfo) {
        // 根據platformType調用相關平台進行分享
        [self shareImageToPlatformType:platformType];
        //分享成功之後移除imageView
        [self.photoIV removeFromSuperview];
        self.photoIV = nil;

    }];
    //設定ShareMenuView的代理,實作點選取消分享的時候移除imageView
    [UMSocialUIManager setShareMenuViewDelegate:self];
}

- (void)shareImageToPlatformType:(UMSocialPlatformType)platformType
{
    //建立分享消息對象
    UMSocialMessageObject *messageObject = [UMSocialMessageObject messageObject];    
    UMShareImageObject *shareObject = [[UMShareImageObject alloc] init];
    //設定分享的圖檔
    shareObject.shareImage = self.photoIV.image;
    //分享消息對象設定分享内容對象
    messageObject.shareObject = shareObject;
    //調用分享接口
    [[UMSocialManager defaultManager] shareToPlatform:platformType messageObject:messageObject currentViewController:self completion:^(id data, NSError *error) {
        if (error) {
            NSLog(@"************Share fail with error %@*********",error);
        }else{
            NSLog(@"response data is %@",data);
        }
        [self.photoIV removeFromSuperview];
        self.photoIV = nil;
    }];
}
//ShareMenuViewDelegate
- (void)UMSocialShareMenuViewDidDisappear
{
    [self.photoIV removeFromSuperview];
    self.photoIV = nil;
}
           

這樣就可以實作整個截屏分享的功能。