iOS 复制一个UIView对象


项目中要做一个新手引导,也就是给某个页面加个遮罩,然后突出显示出一块视图,在写点提示啥的

我的思路是加一个一模一样的视图到遮罩上,但是问题来了,简单的视图是可以这么搞,复杂一点的难道也要创建一个一模一样的吗,那样岂不是太麻烦了。

能不能直接复制一份出来,然后加到遮罩上呢?

我们都知道复制数组、字典、字符串这些用copymutableCopy,然后我就想当然的用我的自定义View调了一下copy,结果很尴尬,直接给崩了,说是要实现copyWithZone这个方法。

总不能所有的自定义View都是实现一遍一个方法吧!

网友们给出这么一个方法,我欣喜若狂,赶紧拿去试一试

NSData *archiveData = [NSKeyedArchiver archivedDataWithRootObject:view];  
UIView *copyView = [NSKeyedUnarchiver unarchiveObjectWithData:archiveData];

然而这个方法并不完美,在复制的copyView中,虽然所有的子控件都能显示出来,但是地址都是nii,当然这不是问题的关键,最致命的是子控件里面包含圆角的话,复制出来后,子控件的圆角都么得啦。这就不能忍了,于是就有了这篇博客,我想了笨方法,给复制出来的View的子控件,加上本该有的圆角!

一言不合就上代码:

@implementation GuideView

- (instancetype)init
{
    self = [super init];
    if (self) {
        self.backgroundColor = [UIColor colorWithWhite:0 alpha:0.3];
        self.frame = [UIScreen mainScreen].bounds;
        self.alpha = 0;
    }
    return self;
}

+ (instancetype)guideView{
    return [[GuideView alloc] init];
}

- (void)addToView:(UIView *)view{
    [self addToView:view containCorner:NO];
}

/**  加给某个View上*/
- (void)addToView:(UIView *)view containCorner:(BOOL)containCorner{
    // 这样复制后,如果有子控件设置了圆角,复制后圆角会失效,而且所有子控件虽然都能显示正确,但地址都是nil
    NSData *archiveData = [NSKeyedArchiver archivedDataWithRootObject:view];
    UIView *copyView = [NSKeyedUnarchiver unarchiveObjectWithData:archiveData];
    
    // 子控件如果包含圆角
    if (containCorner == YES) {
        
        // 替换子控件 这样复制出来的子控件也丢失了圆角
        NSData * subData = [NSKeyedArchiver archivedDataWithRootObject:view.subviews];
        NSArray* subViews = [NSKeyedUnarchiver unarchiveObjectWithData:subData];
        [copyView removeAllSubviews];
        for (UIView *subview in subViews) {
            [copyView addSubview:subview];
        }
        
        // 在原View中找到设置了圆角的子控件
        for (UIView *subView in view.subviews) {
            
            if (subView.layer.cornerRadius != 0)
            {
                // 在复制好的View的子控件中遍历,找到与之对应的子控件
                for (UIView *copySubView in copyView.subviews) {
                    
                    // 给找到的控件设置上圆角,这里通过frame确定是否是同一个控件
                    if ([NSStringFromCGRect(copySubView.frame) isEqualToString:NSStringFromCGRect(subView.frame)]) {
                        copySubView.layer.cornerRadius = subView.layer.cornerRadius;
                        break;
                    }
                }
            }
        }
    }
    copyView.frame = [view convertRect:view.bounds toView:kAppDelegate.window];
    [self addSubview:copyView];
}

- (void)show{
    [kAppDelegate.window addSubview:self];
    [UIView animateWithDuration:0.3 animations:^{
        self.alpha = 1;
    }];
}

- (void)disMiss{
    [UIView animateWithDuration:0.3 animations:^{
        self.alpha = 0;
    } completion:^(BOOL finished) {
          [self removeFromSuperview];
    }];
}

//- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
//    [super touchesBegan:touches withEvent:event];
//    [self disMiss];
//}
@end

效果图




如果是单纯的实现这个功能,是没有必要这么费劲的去复制UIView的,我想到了另外两种方案:

一种是把要漏出来的部分截图,然后加个图片框在遮罩上,在把截的图设上去,经过测试之后发现,代码截的图不是特别清晰,效果不是很好。(可能是我截图的姿势不对)。

另一种方案是把遮罩中间镂空,也是最简单,最高效的方案了,具体实现看我下一篇博客



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值