UIView frame auto reset - ios

I have this simple code, initializing an UILabel
At first print, frame width/height are correct, but at second, all values of frame are 0.
let messageBoxFrame = CGRect(x: 0, y: 0, width: 1024, height: BAND_HEIGHT)
print(messageBoxFrame)
let messageBox = UILabel(frame: messageBoxFrame)
messageBox.textAlignment = .center
messageBox.textColor = UIColor.white
messageBox.backgroundColor = UIColor.blue
messageBox.sizeToFit()
print(messageBox.frame)

messageBox.sizeToFit() this line of code is adjusting your UILabel frame
As per this sizeToFit()
Call this method when you want to resize the current view so that it
uses the most appropriate amount of space. Specific UIKit views resize
themselves according to their own internal needs. In some cases, if a
view does not have a superview, it may size itself to the screen
bounds. Thus, if you want a given view to size itself to its parent
view, you should add it to the parent view before calling this method.

Related

Swift - setting UIView's size based on size screen

I went through many threads here and tried two most recommended solutions.
Inside ViewDidLoad() method:
self.darkBackgroundWithButtons.frame = CGRectMake(0, 0, UIScreen.mainScreen().bounds.width, UIScreen.mainScreen().bounds.height * 0.254)
or
self.darkBackgroundWithButtons.frame = CGRectMake(0, 0, self.view.frame.width, self.view.frame.height * 0.254)
Also, in my storyboard I set low priority of the view's height constraint
(If I don't set height in storyboard, xcode would complain about ambiguous layout)
But none of these lines of code above does anything to darkBackgroundWithButtons, it remains the same height for each device size
This probably is the problem:
In interface builder you set constrains to your button, and therefore it doesn't change its height when you try to update the frame. Do this instead:
First connect your constrain from interface builder to your viewcontroller, just how you would normally do it with a button.
Then use this code to change the constrain:
var index = self.darkBackgroundWihButtons.constraints.indexOf("your constrain name")!
self.darkBackgroundWithButtons.constraints[index].constant = 0.2 // or whatever number you want

Contain items with dynamic height in VC with scrollable functionality

Here is an image of what I'm envisioning.
Two bottoms at the bottom will always stay there. And height of textview and container view is dynamic. I will container another viewcontroller in container view. When sum of height of textview and container view is bigger than current viewcontroller's height, I want them to be scrollable.
I've been looking into 2 things: UICollectionView, UIScrollView.
However, I could not figure out how to make what I'm envisioning with those two components.
I also tried with stackview but that was not suitable for my purposes.
My gut tells me that UIScrollView is way to go but I cannot figure out. My current attempt was putting a scroll view and set the constraints to Nav bar and 2 buttons. Then, put textview and container view inside scroll view using storyboard.
If somebody can guide me a bit, that would be super helpful to me. Sorry for not containing any code, btw. I just couldn't even start :/
let margin = CGFloat(10)
let scrollView = UIScrollView(frame: view.frame)
let textView = UITextView(frame: CGRectMake())//Set textViewFrame
let containerView = UIView(frame: CGRectMake(x:margin, y: textView.height + margin, width: view.frame.width - 2 * margin, height: view.frame.height)
let button1 = UIButton(frame: CGRectMake(x:margin, y: textView.height + contentView.height + 2 * margin, width: (view.frame.width - 2 * margin) /2, height: 30)
scrollView.contentSize = CGSize(width: view.frame.width, height: button1.frame.origin.y + button1.frame.height + margin)
That should be enough to get you started. The important thing is adjusting the scrollView's content size to extend past the frame of the view. To test where this would get you you still need to add as subviews and you could also set backround colors different colors and adjust as necessary.

Swift + UIView: How to change y coordinates?

I have a UIView called descriptionView and I want to hide it initially when the screen first loads by offsetting the y coordinate to be the screen size + the height of descriptionView itself:
However, in my controller, none of my frame changes do anything:
override func viewDidLoad() {
super.viewDidLoad()
...
// descriptionView.frame.origin.y = self.view.frame.height
// UIView.animateWithDuration(1, animations: {
// self.descriptionView.frame.origin.y = self.view.frame.height
// self.view.layoutIfNeeded()
// })
//
print("xxx")
descriptionView.frame = CGRectMake(0, self.view.frame.height, self.view.frame.width, 66)
// descriptionView.frame = CGRectOffset(descriptionView.frame, 0, descriptionView.frame.height)
}
No matter what I do it seems fixed at that visible position like in my storyboard. Can someone help?
In IB you are using NSAutoLayout, so you either need to manipulate the constraints, or tell the view to translate the mask to constraints.
If you want to set the frame directly then you will want to do this:
descriptionView.translatesAutoresizingMaskIntoConstraints = true
descriptionView.frame = CGRectMake(...)
Otherwise you can create IBOutlets to the height and width constraint from IB and update those:
self.descriptionViewHeight.constant = self.view.frame.width
Additionally, I would recommend doing frame manipulations inside of viewWillAppear: rather than viewDidLoad. viewDidLoad does not strictly guarantee final position.
Instead of editing the frame or descriptionView, edit its height constraint.
First, create an NSLayoutConstraint from this constraint by cmd-dragging the height constraint from the Interface Builder to your class (like you do for any UI object).
Then you can set the constant property of this constraint to 0.
(Yes, constant is declared as a varproperty...)
If you are using constraints, chaging the frame view myView.frame property will not affect on view actual position and size. Instead of this make constraint outlet and change it in your code, it will look like this:
descriptionView.heightConstraint.constant = 100
Also, if you want to hide something, you can use property myView.hidden = true, or myView.alpha = 0;

UIView appears with wrong center position

In the following function I define all the necessary characteristics of a UIView:
func OpenController() {
var gameOverView: UIView = UIView()
gameOverView.center = super.view.center
gameOverView.frame.size = CGSize(width: 200, height: 300)
gameOverView.backgroundColor = UIColor.grayColor()
self.view.addSubview(gameOverView)
}
Even though I define the center of the UIView "gameOverView" as that of the the viewcontroller it resides in, it appears with a corner in the center of the viewcontroller and not centered in the viewcontroller. I have tried various other ways of defining the position (NSLayoutConstraints, frame.x, frame.y etc.) but all have this result.
If anyone can tell me why this happens and how to center the UIView within its parent view controller I would greatly appreciate it!
Your issue here is that your center is being set before the frame. Since you are creating the view without the frame argument your frame is {0, 0}.
So you are currently centering the subview then resizing it, so this is happening:
What you need to do is resize the subview then center it, like this:
So you can just swap your centering and framing logic:
gameOverView.frame.size = CGSize(width: 200, height: 300)
gameOverView.center = super.view.center
Otherwise even easier just pass the frame when creating the view (you could even pass in the proper x, y coordinates to center it here too):
var gameOverView: UIView = UIView(frame: CGRectMake(0, 0, 200, 300))
You have to set the center of the view after setting its size. This is because before setting the size or frame of a view its frame rect is (x:0,y:0,width:0,height:0). If you then immediately set its center, then a view of size zero will get centered so its new frame rect could be (x:20,y:20,width:0,height:0) (if the parent view is 40x40). If you now change the view's size, the origin point of the view will not actually move so the new frame could be (x:20,y:20,with:5,height:5) which means the view is no longer centered.
So to center a view you have to first set its size and the its center.

Vertical center on UITableViewCell accessoryView's element

How can I vertically center the content that I have inside a accessoryView from a UITableViewCell? The content is represented by a dynamically added UISwitch that is resized to 50% both width and height using:
switchView.transform = CGAffineTransformMakeScale(0.5, 0.5);
A picture with the problem is:
You cannot change the position of a accessoryView. Please refer to the following question:
Can a standard accessory view be in a different position within a UITableViewCell?
It is okay for you to apply transformation such as scale, and rotation to the accessory view. However, you are not able to apply translate transformation to the accessory view. For example,
switchView.transform = CGAffineTransformTranslate(CGAffineTransformMakeScale(0.5, 0.5),10,10);
Only the scale part of the transformation is applied to the switchView. Looking through the apple documentation, I also found this following line of note:
... The accessory view appears in the right side of the cell.
I don't think apple do want you to customized the location of the accessory view. Based on your question, I also tried changing the centre and the frame of the accessoryView, I do notice that the position of the accessoryView is not moving at all.
In short, If you really want to change the size of the UISwitch and move it to the vertical align it in the table view cell, I think you have only one option: You will have to add UISwitch as a subview of the cell and then you will have to freedom to do whatever you want.
Set the appropriate constraint in interface builder: "Vertical Center in Container".
I would not recommend reducing the size of standard UI elements.
The best way I could do this is by subclassing UITableViewCell, and overriding layoutSubviews and positioning the accessoryView there:
- (void)layoutSubviews {
[super layoutSubviews];
self.accessoryView.frame = CGRectMake(self.accessoryView.frame.origin.x + (self.accessoryView.frame.size.width / 2), (self.frame.size.height - (self.accessoryView.frame.size.height / 2)) / 2, self.accessoryView.frame.size.width, f.size.height);
}
I would probably advise you not to resize Apple's prebuilt UI components, especially because Apple's Human Interface Guidelines suggest:
Give tappable controls a hit target of about 44 x 44 points.
The resized switches are smaller.
Nonetheless, I hope this helps!
iOS 15.5 / Swift 13.4.1
It's a little bit weird when I set a UIImageView to cell.accessoryView
let iconView = UIImageView(image: .sfSymbol(of: "lock.fill", size: 17, weight: .semibold))
iconView.bounds = .init(x: 0, y: 0, width: 32, height: 32)
iconView.contentMode = .scaleAspectFit
iconView.debugBorder() // Show 1pt border
self.accessoryView = iconView
But when I use an UIView as image view's container, add top/bottom/leading/trailing auto layout, then set container to cell.accessoryView, the image is vertically centered in cell:
let imageContainerView = UIView(frame: .init(x: 0, y: 0, width: 32, height: 32))
let imageView = UIImageView(image: .sfSymbol(of: "lock.fill", size: 17, weight: .semibold))
imageView.contentMode = .scaleAspectFit
imageContainerView.addSubview(imageView)
imageView.debugBorder() // Show 1pt border
imageView.labr.box(imageContainerView, padding: 0).done() // Auto Layout: fill container
self.accessoryView = imageContainerView

Resources