【问题标题】:iOS Swift - Position subview based on button frame (button is inside Vertical Stack View)iOS Swift - 基于按钮框架的位置子视图(按钮位于垂直堆栈视图内)
【发布时间】:2020-06-27 18:31:24
【问题描述】:

更新

在rect和主View之间添加convert方法后,Y位置没问题,但是X坐标在主视图之外向右移动了: Dropdown view(subview) is off main view 下面是转换方法前后的按钮框架。主视图为 414 x 896。下拉菜单以某种方式向右移动,如附加图像所示。 stackView btnRect 中的按钮框架:(120.66666666666666, 0.0, 293.3333333333333, 30.0) 主视图中的按钮框架:cvtRect (241.33333333333331, 190.0, 293.3333333333333, 30.0) 视图:可选(>)

目标。我想通过在按钮下方显示带有下拉选项的 UIView 来制作下拉列表。按钮位于垂直堆栈视图内。我向此下拉 UIView 添加了一个带有下拉选项的 TableView。我想单击一个按钮并让这个带有 TableView 的 UIView 显示在按钮下方。基本上遵循本教程https://www.youtube.com/watch?v=D3DCPaEE4hQ,但我的按钮位于垂直堆栈视图内。

问题。 UIView 内的 UIView 和 TableView 在单击按钮时显示正常。问题是下拉 UIView 的位置始终是同一个原点 X=120,Y=0。

我就是这样做的:

  1. 我有 4 行的垂直堆栈
  2. 在第 4 行,我有标签(宽度=120 与上面的 X 坐标几乎相同)和一个触发 UIView 显示的按钮
  3. 我正在使用按钮显示下拉列表(基本上是 UIView),当点击按钮时,应该出现在按钮下方,但它总是出现在原点 x=120 Y=0 ,基本上固定到垂直堆栈视图中右列的顶部。垂直堆栈视图的第一列带有标签,第二列带有不同的控件,如按钮等。
func addTransparentView(frames: CGRect)
   {
      let window = UIApplication.shared.windows.filter {$0.isKeyWindow}.first
      transparentView.frame = window?.frame ?? self.view.frame

      //some of the stuff I tried to at least centre dropdownUIView 
      //transparentView.center.x = window?.center.x ?? self.view.center.x
      //transparentView.center.y = window?.center.y ?? self.view.center.y

      self.view.addSubview(transparentView)

      tvPriority.frame = CGRect(x: frames.origin.x, y: frames.origin.y + frames.width, width: frames.width, height: 0)

      //some of the stuff I tried to at least centre UIView
      //tvPriority.center = verticalStackView.convert(verticalStackView.center, from:tvPriority)     
      //tvPriority.center.x = view.center.x
      //tvPriority.center.y = view.center.y

      self.view.addSubview(tvPriority)
      tvPriority.layer.cornerRadius = 5

      transparentView.backgroundColor = UIColor.black.withAlphaComponent(0.9)
      let tapGesture = UITapGestureRecognizer(target: self, action: #selector(removeTransparentView))
      transparentView.addGestureRecognizer(tapGesture)
      transparentView.alpha = 0
      UIView.animate(withDuration: 0.4, delay: 0, usingSpringWithDamping: 1.0, initialSpringVelocity: 1.0, options: UIView.AnimationOptions.curveEaseInOut, animations: {self.transparentView.alpha = 0.5
         self.tvPriority.frame = CGRect(x: frames.origin.x, y: frames.origin.y + frames.height, width: frames.width, height: 193)
      }, completion: nil)
   }
  1. 要成功制作下拉列表,我需要 UIView 显示在按钮框架(X、Y、宽度、高度)下方。但是,虽然按钮位于第 4 行,应该是 Y 值更高的位置,但按钮框架始终位于 X=120,Y=0,所以我的 UIView 总是固定在应该模拟下拉的按钮上方的这个位置。

问题 1. 下拉 UIView 的定位缺少什么?当按钮位于垂直堆栈视图的第 4 行时,为什么按钮位置 Y=0,Y 位置明显更高?我还尝试简单地将这个下拉菜单放在屏幕中心,但这也不起作用。

2. 我从 Web 开发领域过渡到 iOS 开发,并且在我的职业生涯中经常使用下拉菜单。我应该只使用 Picker View 吗?还是警觉?在 Swift 应用中向用户提供互斥选项列表的最常见和最标准的方式是什么?

非常感谢

【问题讨论】:

    标签: swift uiview frame uistackview addsubview


    【解决方案1】:

    你的按钮是stackView的一个子视图,所以它的frame是相对于stackView的frame而言的。

    要在视图的坐标空间中获取其框架(矩形),您需要使用.convert。将此操作分配给 stackView 中的一个按钮:

    EDIT修正了代码示例...我在发布之前没有检查它。

    class ConvertViewController: UIViewController {
    
        @IBOutlet var dropDownView: UIView!
    
        @IBAction func didTap(_ sender: Any) {
            guard let btn = sender as? UIButton else {
                fatalError("Sender is not a button!")
            }
            guard let sv = btn.superview as? UIStackView else {
                fatalError("Sender is not in a stackView!")
            }
    
            let btnRect = btn.frame
            let cvtRect = sv.convert(btn.frame, to: view)
            print("button frame in stackView:", btnRect)
            print("button frame in main view:", cvtRect)
    
            let dropDownRect = dropDownView.bounds
            let cvtCenterX = cvtRect.origin.x + (cvtRect.size.width / 2.0)
            let viewX = cvtCenterX - (dropDownRect.width / 2.0)
            let newOrigin = CGPoint(x: viewX, y: cvtRect.minY + cvtRect.height)
            dropDownView.frame.origin = newOrigin
    
        }
    
    }
    

    如果您查看调试控制台中的输出,您应该会看到如下内容:

    button frame in stackView: (0.0, 114.0, 46.0, 30.0)
    button frame in main view: (164.5, 489.5, 46.0, 30.0)
    

    如您所见,我的 stackView 中第 4 个按钮的矩形(框架)的原点为0.0, 114.0,但在将其转换为我的view 坐标空间后,矩形的原点为164.5, 489.5

    您现在可以相对于转换后的矩形定位“下拉列表”。

    作为旁注,您可能需要查看UIPopoverPresentationController

    【讨论】:

    • 非常感谢,这有帮助,我现在非常接近。我添加了 let btnRect = btn.frame 和 let cvtRect = btn.convert(btn.frame, to: view)。现在我在正确的 Y 位置,只是 X 坐标现在关闭。 btnRect: (120.66666666666666, 0.0, and after .convert cvtRect (241.33333333333331, 190.0, 所以这个 X=241 使得下拉菜单位于视图之外:view: Optional(
    • 也感谢您的建议,PopoverPresentationController 看起来很棒,我以后会使用它。我仍然对上面的视图、子视图和框架坐标很感兴趣 :-) 以及是什么让它们移动
    • x = 241 将是按钮的左边缘。您可以对x 位置进行任何计算...例如,如果您希望“下拉列表”视图位于按钮下方的中心,您可能会得到转换后矩形的中心:@987654330 @ 然后用let viewX = cvtCenterX - (dropDownView.size.width / 2.0)定位您的视图
    • @Bosniak - 抱歉......我没有测试就输入了该代码。我更新了我的答案——现在应该是准确的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-12
    • 2020-07-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多