Where to get frame size of custom UIView in its subclass
func viewWillAppear(_ animated: Bool)
This is called on the viewController after the view hierarchy is in place and the geometry is set up.
It is usually the best place to arrange geometry-dependent viewController code, and is called just before transition animations are run.
It is followed by a call to viewDidAppear
which is called after transition animations have completed.
update
as you want to set this directly in a custom view (rather than in the viewController) the appropriate UIView function to override is layoutSubviews
. Be sure to call super.layoutSubviews()
in the override.
override func layoutSubviews() {
super.layoutSubviews()
//self.frame will be correct here
}
This will be called after the viewController's viewWillAppear
and before viewDidAppear
update 2: collectionView cells
Collection view cells get their frame data from the collectionview's layout. When a cell needs to know it's geometry, you can override applyLayoutAttributes
func applyLayoutAttributes(_ layoutAttributes: UICollectionViewLayoutAttributes!)
One of the default layoutAttributes is the frame property. See also my comment below on how to extract the frame directly from collectionView.layout.
How to get frame from UIView subclass with AutoLayout
After battling around with it I've figured out what was happening.
layoutSubviews()
is indeed the way to go;
It will calculate the frames of the view and it's direct subviews.
The problem here is that the UILabels are not subviews of the main UIView subclass, but rather are subviews of the main UIView's subview (effect view).
Your view hierarchy example:
--> TestView
--> EffectView
--> UILabel
--> UILabel
--> UILabel
As you can see, layoutSubviews()
will give you the correct frames for TestView
and EffectView
since it's its direct subview, but won't give you the calculated frames from UILabels
because they aren't direct subviews of TestView
.
Getting size of UIView in init
The initializer is called too early in the lifecycle of the view to accurately do layout unless you know the exact dimensions in advance. Even so, it is idiomatically the wrong place to do it.
Try using the layoutSubviews
method as such:
class SubView: UIImageView {
var mySubView: UIImageView
required init?(coder aDecoder: NSCoder) {
mySubView = UIImageView()
mySubView.backgroundColor = UIColor.cyan
super.init(coder: aDecoder)
self.addSubview(mySubView)
}
override func layoutSubviews() {
mySubView.frame = self.bounds
super.layoutSubviews()
}
}
Now the subview bounds will be set properly at the start of each layout pass. It’s a cheap operation.
Also, the bounds
property of a UIView
is the frame
translated to the view’s internal coordinate space. This means that normally this is true: bounds = CGRect(x: 0, y: 0, width: frame.size.width, height: frame.size.height)
. I suggest reading the documentation on view layout.
Alternatively, you can ditch manual layout entirely and use AutoLayout to do this for you.
class SubView: UIImageView {
var mySubView: UIImageView
required init?(coder aDecoder: NSCoder) {
mySubView = UIImageView()
mySubView.backgroundColor = UIColor.cyan
super.init(coder: aDecoder)
self.addSubview(mySubView)
mySubView.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
mySubView.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
mySubView.widthAnchor.constraint(equalTo: widthAnchor).isActive = true
mySubView.heightAnchor.constraint(equalTo: heightAnchor).isActive = true
}
}
How to get dimensions of a custom UIView added via storyboard in initWithCoder:?
Rather than set the subviews dimensions in the init function, set it relative to the custom view in the layoutSubviews method of the custom view. Doing it here will mean that the width of the subview will also always change to match the width of the custom view even if you change the dimensions of the custom view at any point after initialisation.
how do I set the size/position of a custom UIView for its placing within a custom UITableViewCell?
any views added as part of the tableViewCell subclass are positioned relative to the cells frame, ie x:0,y:0 for the subview origin, would be the top left corner of the tableCell.
Something like this should be enough to get you started.
CGRect frame =[self frame];
frame.size.height=20.0f;
frame.origin.x=(self.frame.size.height/2)-frame.size.height;
frame.origin.y=0.0f;
[subview setFrame:frame];
Related Topics
Why Does a Public Class/Struct in Swift Require an Explicit Public Initializer
Storyboard Entry Point Missing
Difference Between Swift's Hash and Hashvalue
Coredata Crash Error Xcode 11 Beta, iOS 13 Beta
Present Actionsheet in Swiftui on iPad
What Does the Swift 'Mutating' Keyword Mean
Presenting a View Controller Programmatically in Swift
Cannot Assign to Property: 'Xxxx' Is a Get-Only Property
How to Pass Protocol with Associated Type (Generic Protocol) as Parameter in Swift
Swiftui - Remove Space Between Cells
How to Call Initializer for Subclass of Generic Type
How to Save Cgimage to Data in Swift
Difference Between Dispatchqueue Types in Swift
Uiimage Created from Mtkview Results in Color/Opacity Differences
Creating a Future Date in Swift with Nsdate()
Do Local Notifications Need User Permission on iOS
Swift3:How to Handle Precedencegroup Now Operator Should Be Declare with a Body