CustomIOS7AlertView 适配 iOS 8

原来项目中用到一个很好用的自定义对话框 CustomIOS7AlertVIew

这个对话框在iOS 7下完全没有问题。

self.alertView = [[CustomIOS7AlertView alloc] init];
        self.alertView.delegate = self;
        self.dvController = [[ZYAlertDirectionalVersionViewController alloc] initWithNibName:@"ZYAlertDirectionalVersion" bundle:[NSBundle mainBundle]];
        self.dvController.delegate = self;
        self.dvController.view.layer.cornerRadius = 8;
        
        [self.alertView setButtonTitles:[NSMutableArray arrayWithObjects: nil]];
        [self.alertView setContainerView:self.dvController.view];
        [self.alertView show];

使用方法很简单。视图是在xib里面的,使用setContainerView放入CustomIOS7AlertView里面就可以了。横竖屏也可以适应。

但是在iOS 8中,横屏的时候,弹出的框确实竖屏的样子。


查了资料后,才知道,原来是iOS 8 中UIScreen的方向与实际方向同步了,而不是iOS7中一直竖屏。所以iOS7中做了交换width、height的动作,而iOS 8中就多余了。

摘录一段:

Yes, it's orientation-dependent in iOS8, not a bug. You could review session 214 from WWDC 2014 for more info: "View Controller Advancements in iOS 8"

Quote from the presentation:

UIScreen is now interface oriented:

  • [UIScreen bounds] now interface-oriented
  • [UIScreen applicationFrame] now interface-oriented
  • Status bar frame notifications are interface-oriented
  • Keyboard frame notifications are interface-oriented

CustomIOS7AlertView中有四个地方需要修改:

1. 创建containerView的时候,计算屏幕大小。 8.0以上不需要交换高宽。

// Helper function: count and return the screen's size
- (CGSize)countScreenSize
{
    if (buttonTitles!=NULL && [buttonTitles count] > 0) {
        buttonHeight       = kCustomIOS7AlertViewDefaultButtonHeight;
        buttonSpacerHeight = kCustomIOS7AlertViewDefaultButtonSpacerHeight;
    } else {
        buttonHeight = 0;
        buttonSpacerHeight = 0;
    }

    CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width;
    CGFloat screenHeight = [UIScreen mainScreen].bounds.size.height;

    //2015-1-27 dinghongyan 8.0以上适配。不转,屏幕大小对应屏幕方向。
    if ([[[UIDevice currentDevice] systemVersion] floatValue] < 8.0) {
        UIInterfaceOrientation interfaceOrientation = [[UIApplication sharedApplication] statusBarOrientation];
        if (UIInterfaceOrientationIsLandscape(interfaceOrientation)) {
            CGFloat tmp = screenWidth;
            screenWidth = screenHeight;
            screenHeight = tmp;
        }
    }

    return CGSizeMake(screenWidth, screenHeight);
}


2. show的时候,添加到window上,不需要根据方向,在代码中转换。

// Create the dialog view, and animate opening the dialog
- (void)show
{
    dialogView = [self createContainerView];
  
    dialogView.layer.shouldRasterize = YES;
    dialogView.layer.rasterizationScale = [[UIScreen mainScreen] scale];
  
    self.layer.shouldRasterize = YES;
    self.layer.rasterizationScale = [[UIScreen mainScreen] scale];

#if (defined(__IPHONE_7_0))
    if (useMotionEffects) {
        [self applyMotionEffects];
    }
#endif

    dialogView.layer.opacity = 0.5f;
    dialogView.layer.transform = CATransform3DMakeScale(1.3f, 1.3f, 1.0);

    self.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0];

    [self addSubview:dialogView];

    // Can be attached to a view or to the top most window
    // Attached to a view:
    if (parentView != NULL) {
        [parentView addSubview:self];

    // Attached to the top most window (make sure we are using the right orientation):
    } else {
        //2015-1-27 dinghongyan 8.0以上适配。不转。会自适应当前方向。
        if ([[[UIDevice currentDevice] systemVersion] floatValue] < 8.0) {
            UIInterfaceOrientation interfaceOrientation = [[UIApplication sharedApplication] statusBarOrientation];
            switch (interfaceOrientation) {
                case UIInterfaceOrientationLandscapeLeft:
                    self.transform = CGAffineTransformMakeRotation(M_PI * 270.0 / 180.0);
                    break;
                    
                case UIInterfaceOrientationLandscapeRight:
                    self.transform = CGAffineTransformMakeRotation(M_PI * 90.0 / 180.0);
                    break;
                    
                case UIInterfaceOrientationPortraitUpsideDown:
                    self.transform = CGAffineTransformMakeRotation(M_PI * 180.0 / 180.0);
                    break;
                    
                default:
                    break;
            }
        }

        [self setFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
        [[[[UIApplication sharedApplication] windows] firstObject] addSubview:self];
    }

    [UIView animateWithDuration:0.2f delay:0.0 options:UIViewAnimationOptionCurveEaseInOut
					 animations:^{
						 self.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.4f];
                         dialogView.layer.opacity = 1.0f;
                         dialogView.layer.transform = CATransform3DMakeScale(1, 1, 1);
					 }
					 completion:NULL
     ];
}


3. 键盘弹出事件中,横屏不需要交换高宽

// Handle keyboard show/hide changes
- (void)keyboardWillShow: (NSNotification *)notification
{
    CGSize screenSize = [self countScreenSize];
    CGSize dialogSize = [self countDialogSize];
    CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;

    UIInterfaceOrientation interfaceOrientation = [[UIApplication sharedApplication] statusBarOrientation];
    
    //2015-1-29 dinghongyan iOS8适配。
    if ([[[UIDevice currentDevice] systemVersion] floatValue] < 8.0) {
        if (UIInterfaceOrientationIsLandscape(interfaceOrientation)) {
            CGFloat tmp = keyboardSize.height;
            keyboardSize.height = keyboardSize.width;
            keyboardSize.width = tmp;
        }
    }
    

    [UIView animateWithDuration:0.2f delay:0.0 options:UIViewAnimationOptionTransitionNone
					 animations:^{
                         dialogView.frame = CGRectMake((screenSize.width - dialogSize.width) / 2, (screenSize.height - keyboardSize.height - dialogSize.height) / 2, dialogSize.width, dialogSize.height);
					 }
					 completion:nil
	 ];
}



4. 转屏的时候,不要代码中强制转。因为转屏的时候,原来的代码是整个dialogView旋转的,所以底层的View旋转了,上层的containerView和我自定义的view都转了。

实际上,底层的View转不转都无所谓的,不转的话,frame要调整。而上层的containerView和自定义的view是不需要转的。

所以,索性不使用旋转,而是改变底层view的frame。

// Handle device orientation changes
- (void)deviceOrientationDidChange: (NSNotification *)notification
{
    // If dialog is attached to the parent view, it probably wants to handle the orientation change itself
    if (parentView != NULL) {
        return;
    }
    
    if ([[[UIDevice currentDevice] systemVersion] floatValue] < 8.0) {
        UIInterfaceOrientation interfaceOrientation = [[UIApplication sharedApplication] statusBarOrientation];
        CGAffineTransform rotation = [self changeOrientation];
        [UIView animateWithDuration:0.2f delay:0.0 options:UIViewAnimationOptionTransitionNone
                         animations:^{
                             dialogView.transform = rotation;
                         }
                         completion:^(BOOL finished){
                             // fix errors caused by being rotated one too many times
                             dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5f * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
                                 UIInterfaceOrientation endInterfaceOrientation = [[UIApplication sharedApplication] statusBarOrientation];
                                 if (interfaceOrientation != endInterfaceOrientation) {
                                     dialogView.transform = [self changeOrientation];
                                 }
                             });
                         }
         ];
    }else{
        //2015-1-27 dinghongyan 8.0以上适配。不转,改frame
        [UIView animateWithDuration:0.2f delay:0.0 options:UIViewAnimationOptionTransitionNone
                         animations:^{
                             self.frame = CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height);
                             
                             dialogView.center = self.center;
                         }
                         completion:^(BOOL finished){
                             UIInterfaceOrientation interfaceOrientation = [[UIApplication sharedApplication] statusBarOrientation];
                             // fix errors caused by being rotated one too many times
                             dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5f * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
                                 UIInterfaceOrientation endInterfaceOrientation = [[UIApplication sharedApplication] statusBarOrientation];
                                 if (interfaceOrientation != endInterfaceOrientation) {
                                     //如果转屏失败,再转回去
                                     self.frame = CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height);
                                     
                                     dialogView.center = self.center;
                                 }
                             });
                         }
         ];
    }
}

//iOS7中转屏处理
-(CGAffineTransform)changeOrientation{
    UIInterfaceOrientation interfaceOrientation = [[UIApplication sharedApplication] statusBarOrientation];
    
    CGFloat startRotation = [[self valueForKeyPath:@"layer.transform.rotation.z"] floatValue];
    CGAffineTransform rotation;
    
    switch (interfaceOrientation) {
        case UIInterfaceOrientationLandscapeLeft:
            rotation = CGAffineTransformMakeRotation(-startRotation + M_PI * 270.0 / 180.0);
            break;
            
        case UIInterfaceOrientationLandscapeRight:
            rotation = CGAffineTransformMakeRotation(-startRotation + M_PI * 90.0 / 180.0);
            break;
            
        case UIInterfaceOrientationPortraitUpsideDown:
            rotation = CGAffineTransformMakeRotation(-startRotation + M_PI * 180.0 / 180.0);
            break;
            
        default:
            rotation = CGAffineTransformMakeRotation(-startRotation + 0.0);
            break;
    }
    return rotation;
}


5. 这个应该是ps了。跟适配没有关系,但是是CustomIOS7AlertView提醒我要注意的一个地方。

就是转屏失败怎么办?

原来的代码,在转屏失败的时候,很萌的来了一句TODO

UIInterfaceOrientation endInterfaceOrientation = [[UIApplication sharedApplication] statusBarOrientation];
                             if (interfaceOrientation != endInterfaceOrientation) {
                                 // TODO user moved phone again before than animation ended: rotation animation can introduce errors here
                             }

如果按照旋转角度的话,其实我拎不清的。左转右转、多少度神马的,转不过弯儿来。但是改frame的话,就好做多了。只要失败的时候,再根据当前的屏幕重新调整一次就好了。于是:

//2015-1-27 dinghongyan 8.0以上适配。不转,改frame
        [UIView animateWithDuration:0.2f delay:0.0 options:UIViewAnimationOptionTransitionNone
                         animations:^{
                             self.frame = CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height);
                             
                             dialogView.center = self.center;
                         }
                         completion:^(BOOL finished){
                             UIInterfaceOrientation interfaceOrientation = [[UIApplication sharedApplication] statusBarOrientation];
                             // fix errors caused by being rotated one too many times
                             dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5f * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
                                 UIInterfaceOrientation endInterfaceOrientation = [[UIApplication sharedApplication] statusBarOrientation];
                                 if (interfaceOrientation != endInterfaceOrientation) {
                                     //如果转屏失败,再转回去
                                     self.frame = CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height);
                                     
                                     dialogView.center = self.center;
                                 }
                             });
                         }
         ];

至此,大功告成!



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值