2014-09-21 14 views
5

我有一個UINavigationController內的UIViewController,在iOS8上以模態方式呈現。我正在使用當iOS8上的鍵盤出現鍵盤時,移動一個模態提供的UIViewController

self.myNavController.modalPresentationStyle = UIModalPresentationFormSheet; 

在我的視圖控制器中,我有一個文本字段。由於視圖控制器的用戶界面設計,當用戶在文本框中點擊並出現鍵盤時,我需要將視圖控制器向上移動到屏幕上。在iOS7上,我一直在動畫更改爲

self.myNavController.view.superview.frame.origin 

爲了將視圖控制器向上和向下移動。這很好。

但是,在iOS8上,這不再有效。事實上,奇怪的是,行爲是視圖控制器略微移動下來然後備份(所有當我指定self.myNavController.view.superview.frame.origin一個CGPoint與較小的值Y座標)。

本來,我是從在此給出一個建議工作,所以質疑Resize ModalViewController and position it at center in iOS 7

而且我最近嘗試在 Moving dialog up when keyboard present works except when ipad is turned around但效果不佳給出的建議。實際上,隨着變換想法在那裏的回答,我至少可以讓視圖控制器向正確的方向移動(即向上),但它不會停留在那裏。它很快就會回落。

想法?

回答

2

我們現在很興奮。我已經明白了這一點。這可以使用新的iOS8 UIPresentationController解決。我將在下面給出一些示例代碼。並嘗試在稍後鏈接到工作項目zip文件中。

第一個視圖控制器是示例應用程序的根視圖控制器。下面是ChangeFrameTransitioningDelegate的代碼。 「對話框」只是一個空視圖控制器類。

// 
// ViewController.m 
// TestPresentationController 
// 
// Created by Christopher Prince on 9/21/14. 
// Copyright (c) 2014 Spastic Muffin, LLC. Use at your own discretion. 
// 

#import "ViewController.h" 
#import "ChangeFrameTransitioningDelegate.h" 
#import "Dialog.h" 

@interface ViewController() 

@end 

@implementation ViewController 

- (void)viewDidLoad { 
    [super viewDidLoad]; 
    // Do any additional setup after loading the view, typically from a nib. 
} 

- (void) viewDidAppear:(BOOL)animated; 
{ 
    [super viewDidAppear:animated]; 

    ChangeFrameTransitioningDelegate *td = [ChangeFrameTransitioningDelegate new]; 
    td.viewControllerFrame = CGRectMake(100, 0, 100, 100); 

    Dialog *d = [Dialog new]; 
    // Just to make the VC stand out. 
    d.view.backgroundColor = [UIColor greenColor]; 

    // Need to make this custom in order to have the presentationControllerForPresentedViewController method of the transitioning delegate called. 
    d.modalPresentationStyle = UIModalPresentationCustom; 

    d.modalTransitionStyle = UIModalTransitionStyleCoverVertical; 
    d.transitioningDelegate = td; 

    [self presentViewController:d animated:YES completion:^{ 

     // Any time after the view controller is presented you can change the 
     // viewControllerFrame property to change the size and/or position of the 
     // presented view controller. 
     [UIView animateWithDuration:0.5 animations:^{ 
      td.viewControllerFrame = CGRectMake(100, 800, 100, 100); 
     }]; 
    }]; 
} 

- (void)didReceiveMemoryWarning { 
    [super didReceiveMemoryWarning]; 
    // Dispose of any resources that can be recreated. 
} 

@end 
// 
// ChangeFrameTransitioningDelegate.h 
// TestPresentationController 
// 
// Created by Christopher Prince on 9/21/14. 
// Copyright (c) 2014 Spastic Muffin, LLC. Use at your own discretion. 
// 

// For iOS8 and later, use this to change the size/position of a view controller after it has been presented. See TextPresentationController example. 
#import <Foundation/Foundation.h> 
#import <UIKit/UIKit.h> 

@interface ChangeFrameTransitioningDelegate : NSObject<UIViewControllerTransitioningDelegate> 

// This is the size and position that the PresentationController used by this class will use when its frameOfPresentedViewInContainerView method is called. So, this is the size and position that your view controller will have. 
@property (nonatomic) CGRect viewControllerFrame; 

@end 
// 
// ChangeFrameTransitioningDelegate.m 
// TestPresentationController 
// 
// Created by Christopher Prince on 9/21/14. 
// Copyright (c) 2014 Spastic Muffin, LLC. Use at your own discretion. 
// 

// Some help from http://stackoverflow.com/questions/25903412/editing-bounds-of-uiview-when-presenting-hides-keyboard-in-ios-8 
// http://stackoverflow.com/questions/25811199/ios-8-change-the-size-of-presented-modal-view-controller 
// Some code from https://developer.apple.com/devcenter/download.action?path=/wwdc_2014/wwdc_2014_sample_code/lookinsidepresentationcontrollersadaptivityandcustomanimatorobjects.zip (though, beware, this example doesn't work straight out of the box). 
// And see http://stackoverflow.com/questions/25957343/moving-a-modally-presented-uiviewcontroller-up-when-keyboard-appears-on-ipad-wit 

#ifndef SPASLogDetail 
#define SPASLogDetail NSLog 
#endif 

#import "ChangeFrameTransitioningDelegate.h" 

@interface PresentationController : UIPresentationController 
{ 
    UIView *_dimmingView; 
} 
// This is the size and position that the PresentationController will use when its frameOfPresentedViewInContainerView method is called. 
@property (nonatomic) CGRect currentFrame; 
@end 

@implementation PresentationController 

- (instancetype)initWithPresentedViewController:(UIViewController *)presentedViewController presentingViewController:(UIViewController *)presentingViewController; 
{ 
    self = [super initWithPresentedViewController:presentedViewController presentingViewController:presentingViewController]; 
    // Some random default size. 
    self.currentFrame = CGRectMake(0, 0, 100, 100); 
    [self prepareDimmingView]; 
    return self; 
} 

// 4/22/15; Added, for rotation. 
- (void) viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator; 
{ 
    CGSize increasedSize = size; 
    // 4/22/15; I'm getting some odd effects: In a rotation transition from landscape to portrait, the RHS goes white momentarily, and from portrait to landscape, the bottom goes white momentarily. A hack, but increase the size of the dimming view to get around this. 
    increasedSize.width *= 1.5; 
    increasedSize.height *= 1.5; 
    _dimmingView.frameSize = increasedSize; 

    // There appears to be no transitionCoordinator available for this "transition". Therefore using the regular UIView animation, below. 
    /* 
    if([self.presentedViewController transitionCoordinator]) 
    { 
     [[self.presentedViewController transitionCoordinator] animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) { 
      recenterViewController(); 
     } completion:nil]; 
    } 
    else 
    { 
     recenterViewController(); 
    }*/ 

    // 4/23/15; See [1]. Given that I've turned off resizing with the autoresizingMask, this has messed up the repositioning of the (x, y) coordinate of the presentedViewController. Make up for that here. 
    [UIView animateWithDuration: coordinator.transitionDuration animations:^{ 
     // I'm assuming the size here refers to the entire window. 
     CGPoint center = CGPointMake(size.width/2.0, size.height/2.0); 
     self.presentedViewController.view.center = center; 
    } completion:nil]; 
} 

- (void)presentationTransitionWillBegin 
{ 
    UIView* containerView = [self containerView]; 

    // 4/23/15; So, this seems to be related to my modal view resizing problem. When I disable autoresizesSubviews, I stop the resizing during the rotation. HOWEVER, this is at the price of two additional problems: (a) the (x, y) coordinate of the modal stops being changed during the rotation, and (b) the animation of the background (_dimmingView?) starts looking funky during the rotation. WHICH makes sense. The containerView size is the full window. 
    //containerView.autoresizesSubviews = NO; 

    UIViewController* presentedViewController = [self presentedViewController]; 

    // [1] 4/23/15; This is better. The _dimmingView animation is preserved. The (x, y) position of the presentedViewController, however isn't right after the rotation. 
    presentedViewController.view.autoresizingMask = UIViewAutoresizingNone; 

    [_dimmingView setFrame:[containerView bounds]]; 
    [_dimmingView setAlpha:0.0]; 

    [containerView insertSubview:_dimmingView atIndex:0]; 

    void (^setAlpha)() = ^{ 
     [_dimmingView setAlpha:1.0]; 
    }; 

    if([presentedViewController transitionCoordinator]) 
    { 
     [[presentedViewController transitionCoordinator] animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) { 
      setAlpha(); 
     } completion:nil]; 
    } 
    else 
    { 
     setAlpha(); 
    } 
} 

- (void)dismissalTransitionWillBegin 
{ 
    void (^resetAlpha)() = ^{ 
     [_dimmingView setAlpha:0.0]; 
    }; 

    if([[self presentedViewController] transitionCoordinator]) 
    { 
     [[[self presentedViewController] transitionCoordinator] animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) { 
      resetAlpha(); 
     } completion:nil]; 
    } 
    else 
    { 
     resetAlpha(); 
    } 
} 

- (CGRect)frameOfPresentedViewInContainerView 
{ 
    SPASLogDetail(@"frameOfPresentedViewInContainerView: %@", NSStringFromCGRect(self.currentFrame)); 
    return self.currentFrame; 
} 

- (void) setCurrentFrame:(CGRect)currentFrame 
{ 
    _currentFrame = currentFrame; 
    // This is the important part for changing the frame of the presented view controller *after* the view is presented. For some odd reason, its not right to change the frame of the containerView. 
    self.presentedView.frame = currentFrame; 
} 

- (void) containerViewWillLayoutSubviews; 
{ 
    SPASLogDetail(@"containerViewWillLayoutSubviews"); 
} 

- (void)prepareDimmingView 
{ 
    _dimmingView = [[UIView alloc] init]; 
    [_dimmingView setBackgroundColor:[UIColor colorWithWhite:0.0 alpha:0.4]]; 
    [_dimmingView setAlpha:0.0]; 

    //UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(dimmingViewTapped:)]; 
    //[_dimmingView addGestureRecognizer:tap]; 
} 

/* 
- (void)dimmingViewTapped:(UIGestureRecognizer *)gesture 
{ 
    if([gesture state] == UIGestureRecognizerStateRecognized) 
    { 
     [[self presentingViewController] dismissViewControllerAnimated:YES completion:NULL]; 
    } 
}*/ 

@end 

@interface ChangeFrameTransitioningDelegate() 
@property (nonatomic, strong) PresentationController *presentationController; 
@end 

@implementation ChangeFrameTransitioningDelegate 

- (instancetype) init; 
{ 
    self = [super init]; 
    return self; 
} 

- (UIPresentationController *)presentationControllerForPresentedViewController:(UIViewController *)presented presentingViewController:(UIViewController *)presenting sourceViewController:(UIViewController *)source 
{ 
    self.presentationController = [[PresentationController alloc] initWithPresentedViewController:presented presentingViewController:presenting]; 
    self.presentationController.currentFrame = self.viewControllerFrame; 

    return self.presentationController; 
} 

- (void) setViewControllerFrame:(CGRect)viewControllerFrame 
{ 
    _viewControllerFrame = viewControllerFrame; 
    self.presentationController.currentFrame = viewControllerFrame; 
} 

@end 
+0

Hmmmm。我現在看到這個問題。它隨着旋轉設備而來。顯示模式並旋轉設備時,模態對話框尺寸不會保留。 – 2015-04-23 07:09:58

+0

我剛添加了一些更改。在代碼中查看我近期的註釋日期。我想我已經修好了。 – 2015-04-23 08:31:51