【问题标题】:Updating auto layout constraints to reposition Text Field更新自动布局约束以重新定位文本字段
【发布时间】:2015-09-09 12:24:31
【问题描述】:

我目前正在通过Udacity iOS 开发 Nanaodegree 并遇到了一个我真的很难解决的问题。我是开发新手和 Stackoverflow,所以这是我的第一篇文章.... 就这样;

我正在构建一个用于生成 Memes 的应用程序。它通过允许用户选择图像并输入一些文本来实现。

我有一个UIView。在那个UIView 我有2x UIToolbar、2x UITextFieldUIImageView。工具栏位于视图的顶部和底部,文本字段分别位于其下方和上方。 UIImageView 占满视图的高度和高度,位于工具栏和文本输入下方。

查看这里screenshots of Storyboard and app

用户可以从他们的相册中选择一张图片,或者用他们的相机拍照,以填充UIImageView。然后将UIImageView 设置为Aspect Fit 以保持其正确的纵横比。

我在 Interface Builder 中设置了约束,以便 UITextFields 与顶部和底部工具栏保持恒定距离。

我遇到的问题是用户需要旋转设备来定位文本字段,以便它们位于图像的顶部和底部。我的意思是,如果用户选择横向图像,并且设备是纵向的,则用户需要旋转他们的设备以确保文本字段位于图像顶部。

我想做的是在用户选择或拍摄图像并且图像已应用 Aspect Fit 后重新定位 textFields。

有人建议我可以使用AVMakeRectWithAspectRatioInside 来生成与UIImage 相同尺寸的CGRect 在应用了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()
    }
}

【问题讨论】:

  • [self setNeedsLayout];放在更新框架的行之后。
  • @Kampai 唉,这并没有解决问题:(
  • 做一件事在你的问题中添加换帧代码。

标签: ios swift uitextfield nslayoutconstraint ios-autolayout


【解决方案1】:

我观察到这里的问题是绘图/渲染视图。所以像视图这样的东西是在实际布局发生之前绘制的,这意味着在视图没有渲染之前框架不会改变。

您可以在这里做的是在实际绘图发生之前尽早强制布局。有一种方法可用,可以在视图的框架更新时处理强制布局视图。

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()
}

【讨论】:

    【解决方案2】:

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

    1. 在情节提要中,只对每个 UITextField 应用 3 个约束,留下 topTextField 的顶部约束和底部文本字段的底部约束。

    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()function 中调用辅助方法

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

    这似乎在 UIImageView 没有图像和没有图像时都可以正常工作。当您旋转设备时,它也可以工作。

    我开始关注两个方面,一是认为我需要首先在 Storyboard 中定义所有约束,二是认为我需要使用 AVMakeRectWithAspectRatioInsideRect 生成的 CGRect 将视图添加到层​​次结构中@

    【讨论】:

      猜你喜欢
      • 2021-04-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-09-03
      • 1970-01-01
      • 2014-12-18
      相关资源
      最近更新 更多