从UIView

时间:2015-07-21 20:44:14

标签: ios objective-c iphone uiview uiviewcontroller

我长期以来一直在研究同样的问题,我可能在这里错过了一个简单的解决方案。

我创建了一个小型库来提供一个自定义的UIView,它可以像iMessage那样粘在键盘上(也就是不用键盘隐藏):https://github.com/oseparovic/MessageComposerView

基本上我遇到的问题是,当用户初始化自定义视图时,我想要一个具有以下默认rect初始化视图的视图:

CGFloat defaultHeight = 44.0;
CGRect frame = CGRectMake(0,
                          [self currentScreenSize].height-defaultHeight,
                          [self currentScreenSize].width,
                          defaultHeight)

这要求在UIView中计算currentScreenSize。我尝试了多种实现,所有这些都有其缺点。由于MVC的这一突破性原则,似乎并不是一个好的解决方案。

关于SO有很多重复的问题,但大多数人都认为你可以访问其他代码库(例如app delegate),而这个自定义视图并不是这样,所以我正在寻找一个自包含的解决方案。 / p>

以下是我使用的两个主要实现:

NextResponder

此解决方案似乎在各种场景中都相当成功。它所做的就是获得下一个响应者的帧,它非常方便地不包含导航或状态栏,可以用来将UIView定位在屏幕的底部。

主要问题是UIView中的self.nextResponder在初始化时为nil,这意味着无法使用它(至少不是我所知道的)来设置初始值帧。一旦视图被初始化并添加为子视图,虽然这看起来像是各种重新定位用途的魅力。

- (CGSize)currentScreenSize {
    // return the screen size with respect to the orientation
    return ((UIView*)self.nextResponder).frame.size;
}

ApplicationFrame

这是我长时间使用的解决方案,但它更笨重并且有几个问题。首先,通过使用applicationFrame,您必须处理导航栏高度,否则将偏移视图的位置。这意味着您必须确定它是否可见,获取其高度并从currentSize中减去它。

不幸的是,获取导航栏意味着您需要访问UINavigationController,这不像访问UIViewController那么简单。我到目前为止所获得的最佳解决方案是以下currentNavigationBarHeight。我最近发现了一个问题,但是如果存在UIAlertView,那么这将无法获得导航栏高度[UIApplication sharedApplication].keyWindow.rootViewController将评估为_UIAlertShimPresentingViewController

- (CGSize)currentScreenSize {
    // there are a few problems with this implementation. Namely nav bar height
    // especially was unreliable. For example when UIAlertView height was present
    // we couldn't properly determine the nav bar height. The above method appears to be
    // working more consistently. If it doesn't work for you try this method below instead.
    return [self currentScreenSizeInInterfaceOrientation:[self currentInterfaceOrientation]];
}

- (CGSize)currentScreenSizeInInterfaceOrientation:(UIInterfaceOrientation)orientation {
    // http://stackoverflow.com/a/7905540/740474

    // get the size of the application frame (screensize - status bar height)
    CGSize size = [UIScreen mainScreen].applicationFrame.size;

    // if the orientation at this point is landscape but it hasn't fully rotated yet use landscape size instead.
    // handling differs between iOS 7 && 8 so need to check if size is properly configured or not. On
    // iOS 7 height will still be greater than width in landscape without this call but on iOS 8
    // it won't
    if (UIInterfaceOrientationIsLandscape(orientation) && size.height > size.width) {
        size = CGSizeMake(size.height, size.width);
    }

    // subtract the height of the navigation bar from the screen height
    size.height -= [self currentNavigationBarHeight];

    return size;
}

- (UIInterfaceOrientation)currentInterfaceOrientation {
    // Returns the orientation of the Interface NOT the Device. The two do not happen in exact unison so
    // this point is important.
    return [UIApplication sharedApplication].statusBarOrientation;
}

- (CGFloat)currentNavigationBarHeight {
    // TODO this will fail to get the correct height when a UIAlertView is present
    id nav = [UIApplication sharedApplication].keyWindow.rootViewController;
    if ([nav isKindOfClass:[UINavigationController class]]) {
        UINavigationController *navc = (UINavigationController *) nav;
        if(navc.navigationBarHidden) {
            return 0;
        } else {
            return navc.navigationBar.frame.size.height;
        }
    }
    return 0;
}

有没有人建议如何从这个UIView中最好地计算UIViewController大小。我完全接受有关如何在我可能忽略的初始化时将UIView粘贴到屏幕底部的其他建议。谢谢!

1 个答案:

答案 0 :(得分:0)

+ (id) getCurrentUIViewController : (id)res {
   if([res isKindOfClass:[UIViewController class]]) {
      return res;
   }
   else if ([res isKindOfClass:[UIView class]]) {
      return [Function getCurrentUIViewController:[res nextResponder]];
   }
   else {
      return nil;
   }
}