简体   繁体   中英

Load view from Xib get resize frame subviews after auto layout

I have been researching for 2 days but I haven't found any solution to this problem:

I am loading a view from a Xib, and applying auto layout to it. The view is showing right and the auto layout is working fine. But when I try to get the frame of the subviews after the auto layout it is not working. I need the frame of the subview to make the redView circular.

I am loading the view from the Xib when it is initialized and add it as subview with auto layout (I have already tried many different things and check that the prints that I am doing is in the layoutSubviews .

class ReusableView: UIView {

    @IBOutlet weak var redView: UIView!

    var mainView: UIView?
    // MARK: - Initializers.
    override init(frame: CGRect) {
        super.init(frame: frame)
        loadXIB()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        loadXIB()
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        print ("Self subviews \(self.subviews)")
        print ("MainView frame \(mainView?.frame)")
        print ("Red View frame \(redView?.frame)")
    }

    func loadXIB() {
        guard let view = loadView(String(describing: type(of: self))) else { return }
        print ("View loaded from nib \(view.frame)")
        view.translatesAutoresizingMaskIntoConstraints = false
        view.subviews.forEach {
            $0.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        }
        addSubview(view)
        NSLayoutConstraint.activate([
            view.topAnchor.constraint(equalTo: self.topAnchor),
            view.leadingAnchor.constraint(equalTo: self.leadingAnchor),
            view.trailingAnchor.constraint(equalTo: self.trailingAnchor),
            view.bottomAnchor.constraint(equalTo: self.bottomAnchor),
            ])
        mainView = view
    }

    func loadView(_ nibName: String) -> UIView? {
        if nibName.isEmpty {
            return nil
        }
        let bundle = Bundle(for: type(of: self) as AnyClass)
        let nib = UINib(nibName: nibName, bundle: bundle)
        if let view = nib.instantiate(withOwner: self, options: nil).first as? UIView {
            return view
        }
        return nil
    }
}

The result of the prints:

View loaded from nib (0.0, 0.0, 375.0, 667.0)
Self subviews [<UIView: 0x7ff232216880; frame = (0 0; 150 150); autoresize = W+H; layer = <CALayer: 0x60800022f4e0>>]
MainView frame Optional((0.0, 0.0, 150.0, 150.0))
Red View frame Optional((0.0, 20.0, 375.0, 647.0))
MainView subviews Optional([<UIView: 0x7ff232216690; frame = (0 20; 375 647); autoresize = W+H; layer = <CALayer: 0x60800022f520>>])

As we see the mainView has been resized but not his subview. (Then when the view is printed it works completely fine, I have been doing it with more complex views but I have never faced the problem of getting the frame inside de UIView before.)

I have discovered this workaround, but I still want to know if there is a more elegant way.

After loading the view I store the original size of the xib in a variable called XibSize

    guard let view = loadView(String(describing: type(of: self))) else { return }
    xibSize = view.frame.size

And then I have created a method, that takes as a parameter the size that you want to be recalculated after applying the after layout: (As we have the original size ( XibSize ), and the recalculated size of the mainView ), we can calculate the size after applying auto layout of the subviews.)

func getSizeAfterAutoLayout(sizeToRecalculate: CGSize) -> CGSize? {
    guard let mainView = mainView, let xibFrame = xibFrame else { return nil }
    let width = sizeToRecalculate.width * mainView.frame.size.width / xibSize.width
    let height = sizeToRecalculate.height * mainView.frame.size.height / xibSize.height
    return CGSize(width: width, height: height)
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM