2015-08-08 87 views
0

我試圖創建一個自定義視圖,顯示完全像鍵盤,但我無法弄清楚如何使用框架操作和/或編程自動佈局解決我的問題。添加子視圖停靠在超級視圖底部(自定義鍵盤)

一些上下文:我有一個消息應用程序樣式視圖控制器的文本視圖和按鈕停靠在屏幕的底部。所有的視圖都被包裝到一個漂亮的單一內容視圖中,並設置了自動佈局,這樣當鍵盤出現時,它會將整個視圖向上推,當視圖消失時,會將整個視圖向下推。這是我試圖重現的行爲。

我搞砸了,試圖手動調整框架類似於我的鍵盤代碼的大小,但最終拋棄了贊成基於自動佈局的解決方案。這是我到目前爲止有:

StickersCollectionViewController *stickerController = [self.storyboard instantiateViewControllerWithIdentifier:@"StickersCollectionViewController"]; 

[self addChildViewController:stickerController]; 
[self.view addSubview:stickerController.view]; 
[stickerController didMoveToParentViewController:self]; 

NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:stickerController.view attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1.0 constant:self.view.bounds.size.height]; 
[self.view addConstraint:constraint]; 

NSLayoutConstraint *width = [NSLayoutConstraint constraintWithItem:stickerController.view attribute:NSLayoutAttributeWidth 
          relatedBy:NSLayoutRelationEqual toItem:self.view 
          attribute:NSLayoutAttributeWidth multiplier:1.0 constant:0.0]; 

NSLayoutConstraint *height = [NSLayoutConstraint constraintWithItem:stickerController.view 
                attribute:NSLayoutAttributeHeight 
                relatedBy:NSLayoutRelationEqual 
                 toItem:nil 
                attribute:NSLayoutAttributeNotAnAttribute 
                multiplier:1.0 
                constant:240.0]; 

[self.view addConstraint:width]; 
[self.view addConstraint:height]; 


double delayInSeconds = 0.0; 
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); 
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ 
    constraint.constant = 240.0; 
    [UIView animateWithDuration:0.3 
        animations:^{ 
         [self.view layoutIfNeeded]; 
        }]; 
}); 

到目前爲止,這看起來不錯:視圖被實例化並添加只是關閉屏幕,然後動畫進入視野。不過,我還想讓我的超級觀點(上面提到)也用這種觀點生動。這是我需要幫助的一塊。

任何人都可以在這個方向提供幫助嗎?或者提供一個關於我可以走的另一條路線的建議?謝謝。

回答

0

試試這個,不同的是使用「[self.view layoutIfNeeded];」在動畫之前和動畫之後,然後放置這個「constraint.constant = 240.0;」在動畫中。

double delayInSeconds = 0.0; 
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); 
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ 
    [self.view layoutIfNeeded]; 
     [UIView animateWithDuration:0.3 
         animations:^{ 
          constraint.constant = 240.0; 
          [self.view layoutIfNeeded]; 
         }]; 
    }); 

所以,試試這個還有:

這樣的:

NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:stickerController.view attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1.0 constant:self.view.bounds.size.height]; 

768,16大概是這樣的:

NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:stickerController.view attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1.0 constant:0]; 

,因爲你是限制到視圖的頂部和不限制在視圖頂部+ self.view.bounds.size.height,不知道這是否有幫助,但這是一個想法。

第二種可能的解決方案是將所有UI元素包裝到一個UIView中,並將此UIView設置爲stickerController.view的視圖,這並不是那麼簡單,因爲從技術上講,您應該將此視圖指定爲stickerController的視圖.view在stickerController impelemntation文件負載視圖方法然後鍵入鑄stickerController.view因爲這例如

Typcasting內部stickerController的實現文件

- (void)loadView 
{ 
    [self setView:[ContainerViewThatHasSubViews new]]; 
} 

- (ContainerViewThatHasSubViews*)contentView 
{ 
    return (id)[self view]; 
} 

然後,創建ContainerViewThatHasSubViews的像這樣的子類

ContainerViewThatHasSubViews.h

@interface ContainerViewThatHasSubViews : UIView 
@property (nonatomic) UIView *subContainerOfContainerViewThatHasSubViews; 
@property (nonatomic) NSLayoutConstraint *tester; 
@end 

ContainerViewThatHasSubViews。米

@interface ContainerViewThatHasSubViews() 
@end 

@implementation ContainerViewThatHasSubViews { 
} 
    self = [super initWithFrame:frame]; 
    if (self) { 

     _subContainerOfContainerViewThatHasSubViews = [UIView new]; 
     [_subContainerOfContainerViewThatHasSubViews setTranslatesAutoresizingMaskIntoConstraints:false]; 
     [self addSubview:subContainerOfContainerViewThatHasSubViews]; 

     /// PSUEDO CODE HERE NOW 
     ALL OTHER UI ELEMENTS ARE ADDED TO THE UIVIEW "subContainerOfContainerViewThatHasSubViews" 

     like this *** [subContainerOfContainerViewThatHasSubViews addSubView:**another ui element***];*** 

     etc. etc. etc. 

     then use layout constraints like this: 

     NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:stickerController.view attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1.0 constant:self.view.bounds.size.height]; 
     [subContainerOfContainerViewThatHasSubViews.view addConstraint:constraint]; 

     etc. etc., so the layout constraints are added to "subContainerOfContainerViewThatHasSubViews" 

     add separate constraints to this UIView for the items inside this view, and you can then animate these cosntraitns as well by declaring the constraints in your header file as propertyies like i did with the _tester constraint, you can animate these when you press a button in your UIViewController impelmentation file by addding a gesture recognizer or whatever you have to show the keyboard 

     then end with this: 

     NSDictionary* views = NSDictionaryOfVariableBindings(subContainerOfContainerViewThatHasSubViews); 
     NSDictionary* metrics = @{@"sp" : @(heightResizer(10)), @"sh" : @40}; //include sizing metrics here 

     [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_subContainerOfContainerViewThatHasSubViews]|" options:0 metrics:metrics views:views]]; 

     and this: 

     _tester =[NSLayoutConstraint constraintWithItem:_subContainerOfContainerViewThatHasSubViews attribute:NSLayoutAttributeCenterTop relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterTop multiplier:1.0f constant:0.0f]; 


     [self addConstraint:_tester]; 
    } 
    return self; 
} 
@end 

要點:

https://gist.github.com/anonymous/c601481d24ad1b98b219

https://gist.github.com/anonymous/b22b68d4bf8d7fa51d66

https://gist.github.com/anonymous/a9aaf922e0f5383256b6

https://gist.github.com/anonymous/fc6655ea8200cda9c0dd

有很多的這一個,但它只是^ h流程圖的意見工作。我從來沒有使用故事板,因爲我覺得我有更多的控制權,以編程方式做所有事情,如果你可以處理你需要編寫多少代碼來實現這一點,那麼你很好去,我知道這是因爲我正在構建一個和你一樣的應用程序,它可以完成與你想要的功能相同的功能,這對我來說很有用,因爲我深入瞭解了這些視圖。這是完全控制,只要確保你將其他NSLayoutContraints作爲子類UIView的合法性,然後你可以在你的子類UIView的頭文件中放置方法,指向UIView子類的實現文件,這些方法可以是動畫方法您可以從您的視圖控制器調用這樣的:

[[self contentView] CALLYOURFUNCTION]; 

訪問其他佈局限制和UI元素從子類的UIView在你的瀏覽器這樣做是爲了給他們打電話:

[[self contentView] tester]; //this is the constraint from9 the header file of tbhe custom UIView 

設置在你的UIViewController中的常量做到這一點:

[[[self contentView] tester] setConstant:A_NUMBER]; 

問題是,您將所有視圖封裝到UIView子類中,而不是訪問視圖控制器本身的視圖並嘗試對視圖進行動畫處理。我從來沒有見過有人嘗試動畫UIViewController本身的「視圖」屬性,我只看到UIView的動畫,它是UIViewController視圖的子視圖。該點也就是你正迫使該UIView的是UIViewControllers視圖的視圖,然後您使用子類的UIView內的另一個UIView的動畫視圖的全部內容,所以它是這樣的:

-UIViewController's view 
    Sub Class of UIView 
     UIView <=== this is the view that contains ALL THE OTHER UIElements of the View controller 

向包含所有其他UI元素的UIView添加一個約束,這個約束是我添加到自定義Sub類UIView頭部的測試器約束。

然後,您可以添加額外的約束的,我已經提到其中包含的UIViewController中

所有其他UI元素當您在這些子項添加約束的UIView的子視圖,您可以製作動畫,以及。這種方法是先進的,所以問問題,如果你有他們,我的答案是有點混亂。

+1

嘿,謝謝你的回答,但我想我需要澄清一點。我的問題是與子視圖上的動畫不一致(它的動畫效果很好),但我也試圖將超視圖移開。所以隨着自定義視圖從屏幕到屏幕上的動畫效果,超視圖應該動起來爲其騰出空間。對不起,如果我不夠清楚,但我很欣賞這個建議。 – FrostRocket

+0

太棒了,讓我多想一想,我會迴應。事實上,我要添加到我的答案,看看這個新東西 – Loxx

+0

我會彈出一個要點,告訴你我的意思是更徹底,一秒 – Loxx

0

爸爸warbucks答案確實讓我接近我正在尋找的解決方案。對於那些用故事板構建了大部分UI骨架的人,我最終在視圖控制器的底部添加了一個容器視圖,並在按鈕按下時修改了主內容視圖和容器視圖的中心值。

  1. 佈局內容視圖,你通常會。將Leading,Trailing和Top約束設置爲內容視圖,將Bottom約束設置爲容器視圖(如步驟2中所述)。

  2. 創建容器視圖並將其停靠在內容視圖下方。將等寬設置爲內容視圖,將頂部約束設置爲內容視圖的底部,並將高度設置爲240(或您希望的任何內容)。注意:視圖將被定位在視圖控制器的關閉位置。如果你像我一樣有點OCD,這會讓你感到困擾,直到你意識到它是k。

  3. 下面是我用來將容器視圖移動到位並使內容視圖跟隨它。請注意,我可能會清理它更多,但這是總體思路:

    if (_isStickersViewOpen) { 
        self.tableView.contentInset = UIEdgeInsetsZero; 
        self.tableView.scrollIndicatorInsets = UIEdgeInsetsZero; 
    
        [UIView animateWithDuration:0.3 
             delay:0.0 
            options:UIViewAnimationOptionCurveEaseOut 
           animations:^{ 
            self.contentView.center = CGPointMake(self.scrollView.center.x, self.scrollView.center.y); 
            self.containerView.center = CGPointMake(self.scrollView.center.x, self.scrollView.bounds.size.height + self.containerView.bounds.size.height/2); 
           } 
           completion:^(BOOL finished){ 
            _isStickersViewOpen = NO; 
           }]; 
    } else { 
        UIEdgeInsets contentInsets = UIEdgeInsetsMake(self.containerView.frame.size.height, 0.0, 0.0, 0.0); 
    
        self.tableView.contentInset = contentInsets; 
        self.tableView.scrollIndicatorInsets = contentInsets; 
    
        [UIView animateWithDuration:0.3 
             delay:0.0 
            options:UIViewAnimationOptionCurveEaseOut 
           animations:^{ 
            self.contentView.center = CGPointMake(self.scrollView.center.x, self.scrollView.bounds.size.height/2 - self.containerView.bounds.size.height); 
            self.containerView.center = CGPointMake(self.scrollView.center.x, self.scrollView.bounds.size.height - self.containerView.bounds.size.height/2); 
           } 
           completion:^(BOOL finished){ 
            _isStickersViewOpen = YES; 
           }]; 
    } 
    

我不是說這是最有效的還是乾淨的解決方案,但它適合我的目的。

+0

這是一個很棒的答案,乾淨而且重要 – Loxx

相關問題