移动子视图 - 偏移量错误,但视觉上正确?

Posted

技术标签:

【中文标题】移动子视图 - 偏移量错误,但视觉上正确?【英文标题】:moving subview - offset amount wrong, but visually correct? 【发布时间】:2015-06-04 04:54:03 【问题描述】:

我编写了这个示例程序来尝试弄清楚发生了什么。我有一个文本字段,单击时会显示子视图而不是显示键盘。在子视图中,有一个关闭按钮,它可以移动子视图,使顶部与屏幕底部对齐。

这样我就可以在故事板中构建子视图,子视图在启动时与屏幕的底部边缘和hidden 对齐。 viewDidLoad 然后调用hideSubView 在开始之前将其移出屏幕。

每次轮班前后我都有println告诉我子视图的位置。

我遇到的问题是数字不加起来。我特别告诉 swift 将 Y 偏移 210,但不知何故,它只将它移动了 68.5,这是屏幕底部的 NOT(请注意,这不是通过将子视图设置为文本字段的输入视图来完成的)。然而,当我单击文本字段时,子视图从下往上动画,而不是中间点。谁能解释为什么会发生这两件事?另一件事是 - 初始 minY 的 457.0 来自哪里?我检查了子视图的初始高度,奇怪的是 143(不是 141.5)。

控制台输出(// - 我为澄清而添加的行)

//hideSubview called from viewDidLoad
Before. minY:457.0 screenheight:667.0 offset:210.0
After. minY:525.5 screenheight:667.0 offset:210.0  //NOTE:457+210 is 667, not 525.5
//1st showSubView called by clicking on myTextField
Before. minY:525.5 screenheight:667.0 subview Height:141.5
After. minY:525.5 subView height:141.5
//hideSubView called by clicking on dismiss button
Before. minY:525.5 screenheight:667.0 offset:141.5
After. minY:667.0 screenheight:667.0 offset:141.5 
//2nd showSubView called by clicking on myTextField
Before. minY:667.0 screenheight:667.0 subview Height:141.5
After. minY:525.5 subView height:141.5
//hideSubView called by clicking on dismiss button
Before. minY:525.5 screenheight:667.0 offset:141.5
After. minY:667.0 screenheight:667.0 offset:141.5

Main.storyboard ViewController.swift

import UIKit

class ViewController: UIViewController, UITextFieldDelegate 

  @IBOutlet weak var myTextField: UITextField!
  @IBOutlet weak var mySubView: UIView!

  var screenSize = UIScreen.mainScreen().bounds
  var subViewIsVisible = false


  override func viewDidLoad() 
    super.viewDidLoad()
    myTextField.delegate = self
    hideSubView()
  

  override func didReceiveMemoryWarning() 
    super.didReceiveMemoryWarning()
  

  @IBAction func dismissButtonClicked(sender: AnyObject) 
    if subViewIsVisible 
      hideSubView()
    
  

  func textFieldDidBeginEditing(textField: UITextField) 
    myTextField.endEditing(true)
    if !subViewIsVisible 
      showSubView()
    
  

  func hideSubView () 
    var offsetAmount = screenSize.height - mySubView.frame.minY
    println("Before. minY:\(mySubView.frame.minY) screenheight:\(screenSize.height) offset:\(offsetAmount)")
    UIView.animateWithDuration(0.25, delay: 0.0, options: UIViewAnimationOptions.CurveEaseOut , animations:
      
        self.mySubView.frame.offset(dx: 0, dy: offsetAmount)
      , completion: _ in
        self.subViewIsVisible = false
        self.mySubView.hidden = true
        println("After. minY:\(self.mySubView.frame.minY) screenheight:\(self.screenSize.height) offset:\(offsetAmount)")
      
    )
  

  func showSubView () 
    mySubView.hidden = false
    println("Before. minY:\(mySubView.frame.minY) screenheight:\(screenSize.height) subview Height:\(mySubView.frame.height)")
    UIView.animateWithDuration(0.25, delay: 0.0, options: UIViewAnimationOptions.CurveEaseOut , animations:
      
        self.mySubView.frame.offset(dx: 0, dy: -self.mySubView.frame.height)
      , completion: _ in
        self.subViewIsVisible = true
        println("After. minY:\(self.mySubView.frame.minY) subView height:\(self.mySubView.frame.height)")
      
    )
  

编辑:

mySubView 的约束:(比我对 Bannings 的评论更容易看到)

【问题讨论】:

为什么不将mySubView 分配给myTextFieldinputAccessoryView @Bannings 这是我遇到问题的程序的简化版本。在那一个中​​,我有一个TextField 和一个Searchbar,它们都可以拉起mySubView。我有限的知识是,一个视图不能有超过 1 个父视图。在这个例子中,如果我按照你说的设置它,那么mySubView 将有 2 个父视图 - 我在故事板上绘制它的主视图和 TextField。这是正确的吗? 您是否在mySubView 中添加了任何约束? @Bannings 外部约束 for mySubView: 1. 将中心 X 与超级视图对齐。 2. 前导空间到 superview = 50。 3. 底部空间 = 底部布局指南。 Internal Constraints(在子视图内):所有 4 个标签(将 Center X 与 Superview 对齐)。所有 4 个标签的顶部和底部 = 10。因此对子视图没有明确的约束来定义它的精确高度。高度由内部组件上设置的约束定义,即关闭按钮的高度 + L1+L2+L3 和 5x10 个空格。 我猜 457 和 143 来自推断的大小,如 mySubView 的约束屏幕截图所示。但是,我已将 ios 模拟器设置为 iPhone6,因此当 viewDidLoad 运行时,它应该具有所有正确的数字。假设起始大小为 143,我希望自动布局将 mySubView 放置在 667-143 = 524... 【参考方案1】:

457 和 143 来自您的故事板,如下所示:

出现这种行为是因为 viewDidLoad 方法中视图的来源不正确。虽然Bottom Layout Guide 有底部约束,但是框架还没有调整。

因此,如果您将视图的 y 设置为 500,那么您将获得如下日志:

Before. minY:500.0 screenheight:667.0 offset:167.0
After. minY:524.5 screenheight:667.0 offset:167.0

在 AutoLayout 调用 viewDidLoad 后,您的 mySubView 的框架将正确。

【讨论】:

感谢您试用。但你确实看到了问题吗?有多个问题,但我遇到的最明显、未解决的问题是:在这两个 println 之间,有一个 self.mySubView.frame.offset(dx: 0, dy: offsetAmount)(来自 hideSubView)。在您的情况下,偏移量是 167。500 + 167 是 NOT 524.5。另请注意 - 524.5 不是屏幕底部,但是当您单击文本字段时,视图将从底部出现,根据控制台输出,它不在! 这是因为您有一个bottom constraint,这将导致它始终在屏幕上。您可以尝试将行设置为self.mySubView.hidden = true 无论这个offset的值是多少都不会影响它在屏幕上的位置 我取消了mySubView(在情节提要中)的“隐藏”选项并注释掉了self.mySubView.hidden = true。运行时,如您所说,它位于底部边缘(基本上忽略了我放置在 viewDidLoad 中的 hideSubView 函数)。但是,当您单击文本字段时 - 它应该将子视图从当前位置动画到当前位置减去子视图的高度,它来自自下而上而不是静止不动,因为它已经在该位置。 您确实可以更新其frame,但这是不安全的,自动布局将在下一次绘图更新(例如旋转屏幕)中再次更新其frame,因此无法保证结果。如果你真的想改变它,你应该做一个 IBOutlet,像这样:***.com/questions/23655096/…

以上是关于移动子视图 - 偏移量错误,但视觉上正确?的主要内容,如果未能解决你的问题,请参考以下文章

网格视图(UICollectionView)的偏移量随着分页滚动而逐渐移动

ios自动布局视觉格式设置子视图与父视图大小相同,但垂直偏移

计算给定球体上扭曲椭圆的偏移量

未定义的偏移量错误,但偏移量不是未定义的

UIScrollView 内容偏移量会阻塞用户交互

vue-scrollto 不在移动设备上排队 - 仅移动设备的偏移量?