将一个UIView的frame设置为来自不同父视图的另一个视图的frame

5
我正在创建位于不同superviews中的UIView,但是我希望将它们的框架设置为相等。

enter image description here

这是我迄今为止尝试过的

let globalPoint = self.view.convert(subViewOfOuterView.frame.origin, to: nil)
let frame = CGRect(x: globalPoint.x, y: globalPoint.y, width: self.subViewOfOuterView.frame.width, height: self.subViewOfOuterView.frame.height)
subViewOfInnerUIView.frame = frame

但是我的视图最终看起来像这样

enter image description here


不要乱搞框架(frame)。使用自动布局(autolayout)。只要OuterUIView和InnerUIView在链条中有共同的Superview,就可以简单地将两个视图的边缘相互约束(constrain)。 - Paulw11
好的,但你可以只使用约束来进行动画。 - Paulw11
@Paulw11,我该如何使用自动布局来解决这个问题? - Sam
@Paulw11,我在尝试将自动布局应用到我的程序中时遇到了更多问题,我想我宁愿使用框架,您知道如何使用框架解决这个问题吗? - Sam
@Sam 我已经更新了我的答案。希望我理解你的意思 :) - Wattholm
显示剩余2条评论
1个回答

1
使用您提供的对象名称,这里是一个示例,创建了第二个视图,也是一个UIButton(subViewOfInnerUIView),它将具有与第一个按钮(drawButton)相同的框架。两个按钮都是主视图中不同父视图的子视图。我使用了UIButton,因此可以为视图添加标签,但任何其他可设置框架的UIView子类也可以工作。
请注意,由于它们具有相同的框架,除了大小相同之外,它们相对于其父视图的位置也相同。
即使所涉及的对象驻留在几层深或浅的子视图中,这也应该有效。这不应该成问题。
该示例可以在最新版本的XCode中的单个视图playground中重新创建。希望这可以帮助!
//: A UIKit based Playground for presenting user interface

import UIKit
import PlaygroundSupport

class MyViewController : UIViewController {
    override func loadView() {
        let view = UIView()
        view.backgroundColor = .white
        self.view = view

        let subView1 = UIView(frame: CGRect(x: 40, y: 250, width: 300, height: 300))
        subView1.backgroundColor = .red
        view.addSubview(subView1)

        let subView2 = UIView(frame: CGRect(x: 20, y: 50, width: 340, height: 100))
        subView2.backgroundColor = .green
        view.addSubview(subView2)

        let drawButton = UIButton(frame: CGRect(x: subView1.frame.width / 2 - 50, y: 25, width: 150, height: 50))
        drawButton.backgroundColor = .blue
        drawButton.setTitle("DRAW BTN", for: .normal)
        subView1.addSubview(drawButton)

        let subViewOfInnerUIView = UIButton()
        subViewOfInnerUIView.setTitle("DRAW BTN2", for: .normal)
        subViewOfInnerUIView.backgroundColor = .brown
        subView2.addSubview(subViewOfInnerUIView)

        let frame = view.convert(drawButton.frame, to: nil)
        subViewOfInnerUIView.frame = frame
    }
}
// Present the view controller in the Live View window
PlaygroundPage.current.liveView = MyViewController()

以下是制作两个视图重叠的更新代码。我对变化进行了动画处理,以便清晰可见,并且注释了特定帧以尝试解释如何完成:
//: A UIKit based Playground for presenting user interface

import UIKit
import PlaygroundSupport

class MyViewController : UIViewController {
    override func loadView() {
        let view = UIView()
        view.backgroundColor = .white
        self.view = view

        let subView1 = UIView(frame: CGRect(x: 40, y: 250, width: 300, height: 300))
        subView1.backgroundColor = .red
        view.addSubview(subView1)

        let subView2 = UIView(frame: CGRect(x: 20, y: 50, width: 340, height: 100))
        subView2.backgroundColor = .green
        view.addSubview(subView2)

        let drawButton = UIButton(frame: CGRect(x: subView1.frame.width / 2 - 50, y: 25, width: 150, height: 50))
        drawButton.backgroundColor = .blue
        drawButton.setTitle("DRAW BTN", for: .normal)
        subView1.addSubview(drawButton)

        let subViewOfInnerUIView = UIButton()
        subViewOfInnerUIView.setTitle("DRAW BTN2", for: .normal)
        subViewOfInnerUIView.backgroundColor = .brown
        subView2.addSubview(subViewOfInnerUIView)

        let frame1 = drawButton.frame
        let frame2 = subView1.convert(drawButton.frame, to: view)
        let frame3 = view.convert(frame2, to: subView2)

        print(frame1) // original drawButton frame in its superview
        print(frame2) // drawButton frame relative to the main view (self.view)
        print(frame3) // drawButton frame relative to subView2 (this is the frame you want)

        subViewOfInnerUIView.frame = view.convert(drawButton.frame, to: nil)

        UIView.animate(withDuration: 5.0, delay: 0.0, options: [.autoreverse, .repeat], animations: {
            subViewOfInnerUIView.frame = frame3
        }, completion: nil)

        subViewOfInnerUIView.frame = frame3


    }
}
// Present the view controller in the Live View window
PlaygroundPage.current.liveView = MyViewController()

最后一行将subViewOfInnerUIView.frame设置为frame3,基本上就是你想要的。你可以创建一个函数来完成这3行代码的工作,以使它更容易(将2个子视图作为参数传递),尽管如果视图层次结构很深,则可能不那么简单:

    let frame2 = subView1.convert(drawButton.frame, to: view)
    let frame3 = view.convert(frame2, to: subView2)
    subViewOfInnerUIView.frame = view.convert(drawButton.frame, to: nil)

希望这能帮到你!

我已经发布了你的解决方案的输出,两个按钮没有重叠。 - Sam
@Sam 我认为输出是你想要的效果。让我看看并使按钮重叠。应该很快就能编辑好。 - Wattholm
@Sam 我已经更新了我的答案。希望这是你想要的行为 :) - Wattholm
所以这个问题的一切都正常,但在我的实际程序中,我遇到了一个问题,即在应用程序启动时使帧相等。这是描述它的图片 https://imgur.com/a/oB20OFI ,这是我在github上的项目 https://github.com/stackoverflowsam93/set 。这仅在应用程序启动时发生,甚至在开始新游戏时也不会发生。我在ViewController的第120行和131行执行此处讨论的操作的代码。 - Sam
严格来说,这个问题与其他事情有关,主要是当应用程序启动时和点击newGame时视图和变量状态不同。我通过将您的代码复制到此方法中解决了您的问题:@IBAction func newGame(_ sender: UIButton),并将其移动到viewDidAppear中,以复制某人点击newGame时应用程序的状态,其中错误不会发生。我还在viewDidLoad中删除了updateViewFromModel调用。我还注意到,一些与视图框架和位置相关的属性在didLoad和didAppear中不同,这就是为什么我将代码放在后者中的原因。 - Wattholm

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接