iOS9之后圆角与阴影性能优化

2019-01-10  本文已影响0人  _码奴

圆角和阴影实现代码和各种实现方法对比都在下面,并且做了注释,可以查看注释了解差异和优劣

#import "ViewExtendController.h"
#import "UIImageView+DrawEx.h"

@interface ViewExtendController ()<UITableViewDelegate,UITableViewDataSource>

@property (nonatomic,strong) UIImageView * imageView;
@property (nonatomic,strong) UIButton * button;

@property (nonatomic,strong) UITableView * tableView;

@end

@implementation ViewExtendController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.title = @"View扩展功能";
    [self makeView];
}

- (void)makeView {
    self.imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 64, 100, 100)];
    [self.view addSubview:self.imageView];
    self.imageView.backgroundColor = [UIColor redColor];
    self.imageView.layer.cornerRadius = 50;
//    self.imageView.layer.masksToBounds = YES;
    
    self.imageView.layer.shadowColor = UIColor.greenColor.CGColor;
    self.imageView.layer.shadowOffset = CGSizeMake(3, 5);
    self.imageView.layer.shadowRadius = 10;
    self.imageView.layer.shadowOpacity = 0.7;
    // 上面阴影代码会离屏渲染,加上下面这句不会离屏渲染
    // 创建一个圆形贝塞尔曲线, 加上这句,视图不进行离屏渲染
/*
     * 这个方法会检测出内存泄漏 CGPathCreateWithRoundedRect
     * 但是实际应该没有影响,因为如果释放程序会立刻崩溃,感觉应该只是系统延迟释放了,所以才会检测出泄漏
     */
//UIBezierPath * path = [UIBezierPath bezierPathWithRoundedRect:im.bounds byRoundingCorners:UIRectCornerAllCorners cornerRadii:im.bounds.size];
//    self.imageView.layer.shadowPath = path.CGPath;
// 这个方法会检测出内存泄漏,CGPathCreateWithRoundedRect(self.imageView.bounds, self.imageView.bounds.size.width, self.imageView.bounds.size.height, NULL);  所以保险起见这里改成上面的方式
    
    [self.view addSubview:self.tableView];
    
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return 50;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    ViewExtendCell * cell = [tableView dequeueReusableCellWithIdentifier:@"ViewExtendCell" forIndexPath:indexPath];
    for(UIImageView * im in cell.viewsArray) {
        // masksToBounds iOS9 之后不会离屏渲染,对帧率影响不明显
//        im.layer.cornerRadius = im.bounds.size.width/2;
//        im.layer.masksToBounds = YES; // 这句,不离屏,但是还是会有额外渲染,因为毕竟要裁剪圆角,主要问题是不能显示阴影,因为阴影也会被裁减掉
        
        im.image = [UIImage imageNamed:@"timg"];
        // 这个方法可以对帧率影响不明显,并且能在实现圆角的情况下不影响阴影的显示
        [im drawCornerRadius:im.frame.size.width/2]; //这个方法来自是定义的类别中,下面有给出代码
        
    }
    return cell;
}

- (UITableView *)tableView {
    if(!_tableView) {
        self.tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 164, self.view.frame.size.width, self.view.frame.size.height - 164) style:UITableViewStylePlain];
        self.tableView.delegate = self;
        self.tableView.dataSource = self;
        self.tableView.rowHeight = 60;
        [self.tableView registerClass:[ViewExtendCell class] forCellReuseIdentifier:@"ViewExtendCell"];
    }
    return _tableView;
}

@end


@implementation ViewExtendCell

- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if(self) {
        [self makeCell];
    }
    return self;
}

- (void)makeCell {
    
    NSMutableArray * viewArray = [[NSMutableArray alloc] init];
    
    self.iconImage = [[UIImageView alloc] initWithFrame:CGRectMake(20, 5, 50, 50)];
    [self.contentView addSubview:self.iconImage];
    
    
    self.iconImage_1 = [[UIImageView alloc] initWithFrame:CGRectMake(75, 5, 50, 50)];
    [self.contentView addSubview:self.iconImage_1];
    
    self.iconImage_2 = [[UIImageView alloc] initWithFrame:CGRectMake(130, 5, 50, 50)];
    [self.contentView addSubview:self.iconImage_2];
    
    self.iconImage_3 = [[UIImageView alloc] initWithFrame:CGRectMake(185, 5, 50, 50)];
    [self.contentView addSubview:self.iconImage_3];
//    self.iconImage_3.layer.cornerRadius = 10;
//    self.iconImage_3.layer.masksToBounds = YES;
    
    self.iconImage_4 = [[UIImageView alloc] initWithFrame:CGRectMake(240, 5, 50, 50)];
    [self.contentView addSubview:self.iconImage_4];
//    self.iconImage_4.layer.cornerRadius = 10;
//    self.iconImage_4.layer.masksToBounds = YES;
    
    self.iconImage.image = [UIImage imageNamed:@"timg"];
    self.iconImage_1.image = [UIImage imageNamed:@"timg"];
    self.iconImage_2.image = [UIImage imageNamed:@"timg"];
    self.iconImage_3.image = [UIImage imageNamed:@"timg"];
    self.iconImage_4.image = [UIImage imageNamed:@"timg"];
    
    [viewArray addObject:self.iconImage];
    [viewArray addObject:self.iconImage_1];
    [viewArray addObject:self.iconImage_2];
    [viewArray addObject:self.iconImage_3];
    [viewArray addObject:self.iconImage_4];
    for(UIImageView * im in viewArray) {
        // masksToBounds iOS9 之后不会离屏渲染,对帧率影响不明显
//        im.layer.cornerRadius = im.bounds.size.width/2;
//        im.layer.masksToBounds = YES; // 这句,不离屏,但是还是会有额外渲染,因为毕竟要裁剪圆角,主要问题在于会影响阴影的显示
        
        // iOS9之后还是会造成离屏渲染了,下面使用 layer.mask 会离屏渲染,并且太多会影响帧率
//        UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:im.bounds byRoundingCorners:UIRectCornerAllCorners cornerRadii:im.bounds.size];
//        CAShapeLayer *maskLayer = [[CAShapeLayer alloc]init];
//        //设置大小
//        maskLayer.frame = im.bounds;
//        //设置图形样子
//        maskLayer.path = maskPath.CGPath;
//        im.layer.mask = maskLayer;  // iOS9之后还是会造成离屏渲染了,
        
        // 因为上面有圆形测试代码m,设置了masksToBounds,所以下面阴影其实看不到
        // 直接使用这种阴影会离屏渲染,但是帧率影响不明显,
        im.layer.shadowColor = UIColor.greenColor.CGColor;
        im.layer.shadowOffset = CGSizeMake(3, 5);
        im.layer.shadowRadius = 10;
        im.layer.shadowOpacity = 0.7;
        //上面代码,阴影离屏渲染不太影响帧率,但是会对GUP消耗很大,这可能是阴影过多卡顿的主要原因
        // 创建一个圆形贝塞尔曲线, 加上这句,阴影不再进行离屏渲染,并且降低GPU的资源占用率
        UIBezierPath * path = [UIBezierPath bezierPathWithRoundedRect:im.bounds byRoundingCorners:UIRectCornerAllCorners cornerRadii:im.bounds.size];
        im.layer.shadowPath = path.CGPath;
        //这个方法会内存泄漏,使用上面方法 CGPathCreateWithRoundedRect(im.bounds, im.bounds.size.width, im.bounds.size.height, NULL);,但实际应该没有影响,只是被延迟释放了而已,为了保险还是使用上面方法
        
    }
    
    self.viewsArray = viewArray;
    
}

@end

下面是 "UIImageView+DrawEx.h" 类的代码,这个里面没写什么,依托于UIImage+Corner.h这个类

#import "UIImageView+DrawEx.h"
#import "UIImage+Corner.h"

@implementation UIImageView (DrawEx)

- (UIImage *)drawCornerRadius:(CGFloat)cornerRadius {
    // 获取裁减成圆角的图片,并重新赋值给imageview的image
    UIImage * image = [self.image drawCornerInRect:self.bounds cornerRadius:cornerRadius];
    self.image = image;
    return image;
}

@end

下面是 UIImage+Corner类代码实现,

#import "UIImage+Corner.h"

@implementation UIImage (Corner)


- (UIImage *)drawCornerInRect:(CGRect)rect cornerRadius:(CGFloat)cornerRadius {
    UIImage * image = nil;
    // 创建贝塞尔曲线对象
    UIBezierPath * bezierPath = [UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:cornerRadius];
    // 开始设置绘图
    UIGraphicsBeginImageContextWithOptions(rect.size, false, [UIScreen mainScreen].scale);
    CGContextAddPath(UIGraphicsGetCurrentContext(), bezierPath.CGPath);
    CGContextClip(UIGraphicsGetCurrentContext());
    // 调用绘制方法
    [self drawInRect:rect];
    
    // 绘制图片
    CGContextDrawPath(UIGraphicsGetCurrentContext(), kCGPathFillStroke);
    // 获取绘制完成的image
    image = UIGraphicsGetImageFromCurrentImageContext();
    // 结束绘制
    UIGraphicsEndImageContext();
    
    return image;
}

@end
上一篇下一篇

猜你喜欢

热点阅读