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 UIView
s 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
Is a Date in Same Week, Month, Year of Another Date in Swift
Launch Image Not Showing Up in iOS Application (Using Images.Xcassets)
How to Set Kerning in iPhone Uilabel
iOS Enterprise Ota Distribution Unable to Download Application
Nsdateformatter and Current Language in iOS11
iOS Gps Tracking App That Runs All the Time
How to Set Device (Ui) Orientation Programmatically
How to Prevent Keyboard Push Up Webview at iOS App Using Phonegap
Swift - Download a Video from Distant Url and Save It in an Photo Album
Xcode 4/iOS - Send an Email Using Smtp from Inside My App
How to Change the Uinavigationcontroller Back Button Name
Button in Uitableviewcell Not Responding Under iOS 7
When to Use Takeunretainedvalue() or Takeretainedvalue() to Retrieve Unmanaged Objects in Swift
How to Show Uialertcontroller from Appdelegate
Changed Project Name in Xcode Causing Naming Error