2015-09-09 34 views
1

我目前正在通過Udacity iOS開發Nanaodegree的方式,並且遇到了一個我非常努力解決的問題。我是開發新手,和Stackoverflow,所以這是我的第一篇文章....在這裏它走了;更新自動佈局約束來重新定位文本字段

我正在構建一個用於生成Memes的應用程序。它通過允許用戶選擇圖像並輸入一些文字來實現。我有一個UIView。在那個UIView我有2x UIToolbar,2x UITextFieldUIImageView。工具欄位於視圖的頂部和底部,文本字段分別位於視圖的下方和上方。 UIImageView空間充滿了視圖的高度,並位於工具欄和textInputs下方。

在這裏看到screenshots of Storyboard and app

用戶能夠從自己的相冊中選擇圖片,或採取與他們的相機拍照,來填充UIImageView。然後將UIImageView設置爲Aspect Fit以保持其正確的寬高比。

我在Interface Builder中設置了約束,以便UITextFields與頂部和底部工具欄保持恆定的距離。

我遇到的問題是用戶需要旋轉設備來定位文本字段,以便它們位於圖像的頂部和底部。我的意思是,如果用戶選擇了橫向圖像,並且設備是縱向的,則用戶需要旋轉他們的設備以確保文本字段位於圖像的頂部。

我想要做的是在用戶選擇或拍攝圖像並且圖像已應用Aspect Fit後重新定位textField。

有人建議,我可以使用AVMakeRectWithAspectRatioInside以產生具有UIImage它具有後的同一尺寸的CGRect已看點飛度施加,可使用的CGRect更新UIImageView的幀,然後更新的約束。

我設法生產了新的CGRect並更新了UIImageView的框架。然後,我改變了對UITextFields的限制,以使它們與UIImageView而不是工具欄對齊,但UITextFields在幀更新時不會自行重新定位。

在幀更新後我會調用以下內容;

view.setNeedUpdateConstraints() 

如果有人有最好的方法來解決這個問題,這將是偉大的。

編輯:

這裏是從的viewController項目我已經創建隔離,並嘗試解決這個問題的代碼..

import UIKit 
import AVFoundation 

class ViewController: UIViewController { 

    @IBOutlet weak var imageViewPic: UIImageView! 
    @IBOutlet weak var topTextToToolberContraint: NSLayoutConstraint! 
    @IBOutlet weak var bottomTextToToolbarConstraint: NSLayoutConstraint! 
    @IBOutlet weak var topText: UILabel! 
    @IBOutlet weak var bottomText: UILabel! 

    override func viewDidLoad() { 
     super.viewDidLoad() 
    } 

    override func viewWillAppear(animated: Bool) { 
     let imageToDisplay = UIImage(named: "Captain-Picard-Facepalm") 
     imageViewPic.image = imageToDisplay 
    } 

    func updateFrame() {   
     let resizedImageSize = imageViewPic.image!.size 
     let imageViewBounds = imageViewPic.bounds 
     let newRect = AVMakeRectWithAspectRatioInsideRect(resizedImageSize, imageViewBounds) 
     imageViewPic.frame = newRect 
    } 

    override func willRotateToInterfaceOrientation(toInterfaceOrientation: UIInterfaceOrientation, duration: NSTimeInterval) { 
     updateFrame() 
     view.setNeedsLayout() 
    } 
} 
+0

付諸視圖添加到使用所產生的CGRect層次結構中的所有約束'[self setNeedsLayout];'在更新幀的行之後。 – Kampai

+0

@Kampai唉這沒有解決問題:( –

+0

做一件事添加改變框架的代碼在你的問題。 – Kampai

回答

0

我能找到一個人做一個非常相似的例子。這是方法。

  1. 在情節串連圖板,只適用3個約束到每個UITextFields,留下topTextField的頂部約束以及bottomTextField的底部約束。

  2. 爲頂部和底部約束添加兩個屬性到ViewController。

    var topConstraint : NSLayoutConstraint! 
    var bottomConstraint : NSLayoutConstraint! 
    
  3. 創建以下輔助方法;

    func layoutTextFields() { 
    
    //Remove any existing constraints 
    if topConstraint != nil { 
        view.removeConstraint(topConstraint) 
    } 
    
    if bottomConstraint != nil { 
        view.removeConstraint(bottomConstraint) 
    } 
    
    //Get the position of the image inside the imageView 
    let size = memeImageView.image != nil ? memeImageView.image!.size : memeImageView.frame.size 
    let frame = AVMakeRectWithAspectRatioInsideRect(size, memeImageView.bounds) 
    
    //A margin for the new constrains; 10% of the frame's height 
    let margin = frame.origin.y + frame.size.height * 0.10 
    
    //Create and add the new constraints 
    topConstraint = NSLayoutConstraint(
        item: topTextField, 
        attribute: .Top, 
        relatedBy: .Equal, 
        toItem: memeImageView, 
        attribute: .Top, 
        multiplier: 1.0, 
        constant: margin) 
    view.addConstraint(topConstraint) 
    
    bottomConstraint = NSLayoutConstraint(
        item: bottomTextField, 
        attribute: .Bottom, 
        relatedBy: .Equal, 
        toItem: memeImageView, 
        attribute: .Bottom, 
        multiplier: 1.0, 
        constant: -margin) 
    view.addConstraint(bottomConstraint) 
    } 
    
  4. 呼叫在viewDidLayoutSubviews()功能輔助方法

    override func viewDidLayoutSubviews() { 
    super.viewDidLayoutSubviews() 
    layoutTextFields() 
    } 
    

這似乎很好地工作時,雙方的UIImageView沒有圖像,也當它沒有。當您旋轉設備時,它也可以工作。

有兩個方面,我被逮住在想我需要在故事板定義第一,以及思考我需要通過AVMakeRectWithAspectRatioInsideRect

0

我觀察到,這裏的問題是繪圖/渲染視圖。因此,在實際佈局發生之前,視圖等事物正在繪製,這意味着在視圖未呈現之前,幀不會更改。

你可以在這裏做的是在實際繪圖發生之前的早期佈局。有一種方法可用,它可以在視圖的幀更新時處理強制佈局視圖。

func setNeedsLayout() 
func layoutIfNeeded() 

以上兩種方法都用於強制佈局視圖。

嘗試下面的代碼,可以照顧更新佈局。

func updateFrame() {   
    let resizedImageSize = imageViewPic.image!.size 
    let imageViewBounds = imageViewPic.bounds 
    let newRect = AVMakeRectWithAspectRatioInsideRect(resizedImageSize, imageViewBounds) 
    imageViewPic.frame = newRect 
    imageViewPic.layoutIfNeeded() 
    self.view.layoutIfNeeded() 
} 

也可以在ViewController中重寫下面的方法。 updateViewConstraints()用於更新自定義約束的方法。

override func updateViewConstraints() { 
    super.updateViewConstraints() 
    self.view.layoutIfNeeded() 
    self.imageViewPic.layoutIfNeeded() 
}