Create a Copy of a Uiview in Swift

Create a copy of a UIView in Swift

You can't arbitrarily copy an object. Only objects that implement the NSCopying protocol can be copied.

However, there is a workaround: Since UIViews can be serialized to disk (e.g. to load from a XIB), you could use NSKeyedArchiver and NSKeyedUnarchiver to create a serialized NSData describing your view, then de-serialize that again to get an independent but identical object.

Duplicate, clone or copy UIView

Sure. The documentation has a good example of how to achieve that; it's for UITableViewCell, but is a good approach to use here as well.

Depending on the complexity of your view, you might want to make it a custom view class, and give it its own IBOutlet properties for whatever subviews it has; in that case, you'd set the “Class Identity” of the view in Interface Builder to that class. Then your view controller could access those views on any given XIB-loaded view via, for instance, myLoadedView.someLabel, rather than having to use, e.g., [myLoadedView viewWithTag:3] as suggested by the aforelinked documentation.

How to make copy UIView and save accessibilityId programmatically?

This appears to be an Apple bug. You should really report this on Apple Bug Reporter.

That said, you can work around the issue as follows:

extension UIView {
func copyView<T: UIView>() -> T {
let copy = NSKeyedUnarchiver.unarchiveObject(with: NSKeyedArchiver.archivedData(withRootObject: self)) as! T
copy.accessibilityIdentifier = accessibilityIdentifier
return copy
}
}

Can UIView be copied?

Your app probably crashes with something like:

 [UIView copyWithZone:]: unrecognized selector sent to instance 0x1c6280

The reason is that UIView does not implement the copying protocol, and therefore there is no copyWithZone selector in UIView.

How to make a copy of UIView with all layer properties?

In fact it was wrong idea to copy view or it's layer. I spent two days solving this problem, but today I just added my buttonsStackView.layer as a sublayer to containerView.layer. Then, in completion closure of the animate method, I removed it from superLayer and added to my rootViewController.view.layer. It works perfectly.

transitionContext.containerView.layer.addSublayer(buttonsStackViewSnapshot)

UIView.animate(withDuration: duration,
animations: {
buttonsStackViewSnapshot.frame = finalButtonsFrame
},
completion: { (finished) in
buttonsStackViewSnapshot.removeFromSuperlayer()
toVC.view.layer.addSublayer(buttonsStackViewSnapshot)
toVC.view.isHidden = false
transitionContext.completeTransition(finished)
})

Copy of UiView and all subviews..Copied UIButton cannot be pressed

Since this is all done in viewDidLoad, I assume that the view you want to copy is the same every time.

Your code does not work likely because NSKeyedArchiver does not archive the button's target and selector pairs.

You can create a method that gives a new UIView instead:

func createPart() -> UIView {
let part = UIView()
part.translatesAutoresizingMaskIntoConstraints = false
part.layer.cornerRadius = 4
part.layer.masksToBounds = true
part.backgroundColor = .random()

// The part below is copied from your viewDidLoad method
// Include only those lines that create the part view.
// I might have put more than you need. Check twice
let button = UIButton(frame: CGRect(x: 270, y: 200, width: 80, height: 40))
let partLabel1 = UILabel(frame: CGRect(x:10, y: 10, width: 300, height: 50))
let partLabel2 = UILabel(frame: CGRect(x:10, y: 50, width: 300, height: 50))
partLabel1.text = "This should sit within part use :)"
partLabel1.textColor = .white
partLabel2.text = "This should also sit within part use :)"
partLabel2.textColor = .white
part.addSubview(button)
part.addSubview(partLabel1)
part.addSubview(partLabel2)
part.bringSubviewToFront(button)
part.bringSubviewToFront(partUse3Label1)
part.layer.zPosition = -1
button.setTitle("Issue", for: .normal)
button.backgroundColor = .orange
button.leadingAnchor.constraint(equalTo: part.leadingAnchor).isActive = true
button.trailingAnchor.constraint(equalTo: part.trailingAnchor).isActive = true
button.bottomAnchor.constraint(equalTo: part.bottomAnchor).isActive = true
button.topAnchor.constraint(equalTo: part.topAnchor).isActive = true
button.heightAnchor.constraint(equalToConstant: 40).isActive = true
button.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
button.isUserInteractionEnabled = true
part.bringSubviewToFront(button)
partLabel1.leadingAnchor.constraint(equalTo: part.leadingAnchor).isActive = true
partLabel1.trailingAnchor.constraint(equalTo: part.trailingAnchor).isActive = true
partLabel2.leadingAnchor.constraint(equalTo: part.leadingAnchor).isActive = true
partLabel2.trailingAnchor.constraint(equalTo: part.trailingAnchor).isActive = true
part.layoutIfNeeded()

return part
}

And then in viewDidLoad, you should remove the lines of code that help create the part view, leaving only the code that creates the stack view and main content view. You should then call createPart twice, and there you have 2 copies!

let part = createPart()
let copyOfPart = createPart()


Related Topics



Leave a reply



Submit