更新自动布局约束以重新定位文本字段

时间:2015-09-09 12:24:31

标签: ios swift uitextfield nslayoutconstraint ios-autolayout

我目前正在通过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后重新定位textFields。

有人建议我可以使用AVMakeRectWithAspectRatioInside生成CGRectUIImage相同的尺寸后应用Aspect Fit,使用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()
    }
}

2 个答案:

答案 0 :(得分: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()
}

答案 1 :(得分:0)

我能够找到一个非常相似的人的例子。这就是方法。

  1. 在故事板中,只对每个UITextField应用3个约束,保留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()
    }
    
  5. 当UIImageView没有图像时,以及没有图像时,这似乎都能很好地工作。它也适用于旋转设备。

    我抓到的两个方面是认为我需要首先在Storyboard中定义所有约束,并且认为我需要使用CGRect生成的AVMakeRectWithAspectRatioInsideRect添加视图。 1}}