Autoresize subviews when the frame of superview is modified - ios

I have a green rectangle (viewA) with a inner red rectangle (viewB). If I try to modify the dimension of the viewA the viewB is not automatically changed.
I try to:
check the autoresizesSubviews value (is true)
set an autoresizingMask
change the bounds instead the frame of the superview
All these solution don't work.
This is my code:
#IBOutlet weak var viewA: UIView!
#IBOutlet weak var button: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func buttonAction(_ sender: Any) {
viewA.autoresizesSubviews = true
self.viewA.autoresizingMask = [.flexibleWidth, .flexibleHeight,.flexibleTopMargin, .flexibleLeftMargin, .flexibleRightMargin, .flexibleBottomMargin]
viewA.bounds = CGRect(x: 0, y: 0, width: 100, height: 100) // or frame instead of bounds
}
Thanks to everyone.
EDIT:
I add the two views in the storyboard. Here you can see also the constraint of the viewB.

Don't mix up frame and auto layout of a view, both are behaving differently.
You need to do something like as follow.
Constrains for viewA
CenterX and CenterY
(Height or Width) and Aspect Ratio 1:1 (means equal width and equal height)
Constraints for viewB
Leading, Trailing, Top and Bottom to its superview (i.e. viewA)
Now you need to Create an #IBOutlet to the constraint you need to modify(of viewA).
#IBOutlet weak var const_height_viewA: NSLayoutConstraints!
So on button click you need to change only constraint's constant.
#IBAction func buttonAction(_ sender: Any) {
const_height_viewA.constant = 250
//changing height constraint of viewA will automatically updates viewB frame.
}
Note: No need to modify constraints of viewB as it will be automatically adjusted by given constraints.
For pictorial reference

You should not change the frame if you are using AutoLayout. If you are using AutoLayout, it is best to update the constraints to the values you want instead of changing the frame.
Notice the first point in the Rule of Thumb section from the docs.

Related

ScrollView does not scroll in iOS

I want to allow users to scroll left or right but only one screen far.
//
// MainViewController.swift
// Calendar
//
// Created by Andy on 7/22/17.
// Copyright © 2017 Andy. All rights reserved.
//
import UIKit
class MainViewController: UIViewController, UIScrollViewDelegate {
#IBOutlet weak var ScrollView: UIScrollView!{
didSet{
ScrollView.delegate = self
ScrollView.contentSize = CGSize(width: ScrollView.frame.width * 3, height: ScrollView.frame.height)
}
}
#IBOutlet weak var center: UIView!
#IBOutlet weak var left: UIView!
#IBOutlet weak var right: UIView!
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destination = segue.destination as? ReusableViewController {
if let identifier = segue.identifier{
destination.currentYearOffSet = 0
destination.currentMonthOffSet = 0
switch identifier {
case "center":
destination.position = .center
case "left":
destination.position = .left
case "right":
destination.position = .right
default:
fatalError("Unexpected Segue Identifier")
}
}
}
}
}
This Controller does nothing more than getting the scroll work. And inside the scrollview there are three containerViews managed by other controllers. But that simply does not work.
I have done the following to solve the problem but in vain: 1. Check the content size of scrollView. 2. Hook up the controller and the three containerViews. 3. Set the scrollView delegate but I haven't implemented any method.(Maybe that's the cause but I don't know what to implement)
Plus, do I need to hook up those three containerViews when the controller does nothing about them?
EDIT: I removed: 1. contentSize 2. UIScrollViewDelegate 3. outlets of the three containerViews. This does make my code a lot more nicer, but scrollView still cannot scroll.
EDIT2: I add a view which is exactly the size I want scrollView.contentSize to be as the scrollView's immediate subview. And it seem that the content height is solved because it's only saying that the content width is ambiguous. It want to to add leading and trailing constraints to the view I added but I want it to just center horizontally in the scrollView. Now I need to set the leading and trailing constraints to let autoLayout know the contentWidth. How can I set the leading and trailing offSet based on the width of its superview or I'm supposed to do something else to solve this problem?
You do not need to set like this:-
#IBOutlet weak var ScrollView: UIScrollView!{
didSet{
ScrollView.delegate = self
ScrollView.contentSize = CGSize(width: ScrollView.frame.width * 3, height: ScrollView.frame.height)
}
}
Just having outlet #IBOutlet weak var ScrollView: UIScrollView! and pinning proper constraint(leading, trailing, top, bottom, equal Width(should be equal to or greater than to), equal height (should be equal to or greater than to).
For Horizontal scroll
If you wanted to scrolling horizontally then also pinned width constraint, this is required to avoid auto layout error but inside placeholder checked Remove at build time.
For Vertical scroll
If you wanted to scrolling vertically then also pinned height constraint, this is required to avoid auto layout error
but inside placeholder checked Remove at build time.
Note:- You can use either both or any one based on your requirement.

UIStackview fill proportionally in a UITableviewCell takes incorrect frame

Adding proportional fill setting in a UIStackview won't let the view stretch properly. Is this the expected behaviour?
Fill proportionally' distribution type works with intrinsic content size.
So if our vertical stack(height say 600) view has 2 views, ViewA (intrinsic content height 200) and ViewB(intrinsic content height 100), the stack view will size them to ViewA(height 400) and ViewB(height 200).
Here in IB what you see is not what you get.
Dragging to make frames change is useless. Just run the app.
You will see the expected behaviour only when the child views somehow get the intrinsic/constrained height.
How it looks in IB Here the top stack view has views constrained to be of height minimum 10 and 30, i.e. ration 1:4.
What we really get
Top stack view is what we had expected to look like. View with height in ratio 1:4. And bottom one with ratio 1:1, not expected.
You can fix this by creating a custom view
class CustomHeightView: UIView {
var height = 1.0
override public var intrinsicContentSize: CGSize {
return CGSize(width: 0.0, height: height)
}
}
Change the class of your UIView to CustomHeightView
So in the Controller create an outlet for the UIViews
#IBOutlet weak var header_one: CustomHeightView!
#IBOutlet weak var header_two: CustomHeightView!
Then in your viewDidLoad set the proportion the way you want it
override func viewDidLoad() {
super.viewDidLoad()
header_one.height = 1.8
header_two.height = 1.2
}

storyboard dynamic auto layout issue

I have this situation :
When I tap on "add" button I reduce the pink view's(first view) height and I execute this code:
#IBOutlet weak var viewPink: UIView!
#IBAction func add(_ sender: AnyObject) {
viewPink.frame = CGRect(x: viewPink.frame.origin.x, y: viewPink.frame.origin.y, width: viewPink.frame.size.width, height: viewPink.frame.size.height - 50)
}
but I want that the last view remains to the same distance from the pink view , essentially you have to climb on why the pink view reduces its height , instead the second view remains where it was before.
Can you help me about it?
P.S I set the vertical spacing constraint between the two views but It doesn't work
You should add an Height constraint on your pink view, create an IBOutlet to this constraint in your ViewController, and set the "constant" property to change the height.
Example:
heightConstraint.constant = 150
This will change the height with Autolayout, you shouldn't change the height by setting a new frame because it doesn't use Autolayout.

UICollectionView width programatically conflicting with storyboard initialization

I've created a UICollectionView through the storyboard and temporarily positioned it in the view; however, I'd like to overwrite the positions programmatically on launch rather than using the storyboard configuration.
I thought viewDidLoad() was the right location to place make this change?
Swift 2 Code:
override func viewDidLoad() {
super.viewDidLoad()
collectionView.dataSource = self
collectionView.delegate = self
collectionView.registerClass(UICollectionViewCell.self, forCellWithReuseIdentifier: "collectionCell")
collectionView.backgroundColor = UIColor(white:1, alpha:0.0)
// Doesn't stretch the width to the device's width on launch. :-(
collectionView.frame.size = CGSize(width: UIScreen.mainScreen().bounds.width, height: 200)
}
If you are setting constraints and then want to change height or width then you should take outlet of that height or width and increament it's constant value. just ctrl+drag from width constraint to class and make outlate and then increment that outlate's contant property in viewdidload.
for example,
#IBOutlet weak var heightConstraint: NSLayoutConstraint!
self.heightConstraint.constant = 200
And second thing if you want to keep your collectionview's height equal with device then there is no need to set programatically. autolayout manage it if you set proper constraint. so main point is use autolayout at evrywhere or not at all. dont mix both autolayout and then set frame programatically.
hope this will help :)

How can I update a UIView's position and size in reference to it's superview's position and size? [Swift]

I have a superview with another subview inside of it. The subview has constraints set to it to be centered in the superview and half the size of the superview.
The position and size of the superview are being changed when a button is clicked, but the position and size of the subview is not being changed with it. I tried using UIView.updateConstraints(), but it is not repositioning it or resizing it.
So my question is:
What would be the best way to resize and reposition the subview with respect to the superview?
Thank you!
Here is the code:
func updateTimerFormat() {
minutesContainer.frame.size.width *= 0.75
minutesContainer.frame.size.height *= 0.75
minutesContainer.center.x = view.center.x
minutesContainer.center.y = view.center.y * 1.5 - 30
// The minutes label is the subview of the minutesContainer
minutesLabel.updateConstraints()
}
You should not to call updateConstraints(), because I do not think your view's constraints need to be updated.
You just need to change SuperView's size or position. Then your view can automatically set the size and position, because you set their constraints before.
This is a demo.https://github.com/cythb/iOSIssues/tree/master/2_AjustSizeDemo
Constraint subview(yellow) center to superview(green) center. Constraint size is half of the superview(green).
When you click button, you don't do anything else,just change the size of superview.
There are two ways-
Implement the func layoutSubviews(). This method is called when super view frame become change. In this method you can change your subviews frame.
Second option is that use autolayout during configure the subviews
1/ Connect minutesContainer constraints to your ViewController:
#IBOutlet weak var widthConstraint: NSLayoutConstraint!
#IBOutlet weak var heightConstraint: NSLayoutConstraint!
#IBOutlet weak var centerYConstraint: NSLayoutConstraint!
2/ Change your updateTimerFormat method:
func updateTimerFormat() {
widthConstraint.constant *= 0.75
heightConstraint.constant *= 0.75
centerYConstraint.constant = view.center.y * 0.5 - 30
}

Resources