Modify height of a container view - ios

Here is my app with the profile on the left (ProfileViewController) and a containerView on the right (ContainerViewController). What I am trying to achieve is once the containerViewController has done its job, it will update the height of the UIView.
// ContainerViewController.swift
let heightConstraint = self.view.constraints.filter { $0.identifier == "Height" }.first
heightConstraint?.constant = height
When browsing the list of constraints, they're all emtpy, and I did set up some constraints in the storyboard. So Why ? Is there any way to access the UIView within the ContainerViewController ?
Ps:
DispatchQueue.main.async {
self.view.frame = CGRect(x: 0, y: 0, width: width, height: height)
}
Sounds to work, but I think that modify constraint is proper ? Nope ?

What I would do, is to set IBOutlet for the constraint, and store it inside ContainerView.
This way, you don't depend on order number or anything else, to get this constraint, even if code (or storyboard) will changed in the future.
And Yes, the right way is to set the constraint constant, and not changing frame.
But be aware, that even constraint constant change need to be put on the main (UI) thread - (by the look of your code, I assume, you are dealing with the threads).

Related

Increasing height of UIView.frame programmatically works till iPhone 8 plus but doesn't works beyond model iphone x

I am increasing the height for UIView programmatically in runtime on click of button, it works fine on iPhone 6,7,8 and plus models but doesn't works on iPhone X and beyond models. i have initially set constraints programmatically as i views are autoLayout based. I also tried to set constraints at runtime which didn't helped too.
//Tried this and working till iPhone 8+
self.view.frame.size.height += CGFloat(280)
//or
self.view.frame = CGRect(x: 0, y: 0, width: self.view.frame.width,
height: self.view.frame.height + 20.0)
//Tried setting height constraint
self.view.autoSetDimension(.height, toSize: 270)
Debug view hierarchy and look for conflicting constraints that might interfere with your height constraint. Also make sure you set translatesAutoresizingMaskIntoConstraints to false if you set constraints in code.
Also: if you set your constraint like this in code (apparently you are using PureLayout), that method returns the reference to that height constraint. So if you want to modify it, you need to update the constant value of your constraint, instead of setting a new one.
For any further help you certainly need to share more information.

SnapKit and Dynamic UITableViewCell not being laid out correctly

I'm currently building a reusable view that takes advantage of the dynamic resizing that UITableView has on offer with its cells.
What I'm trying to achieve is to give a view within the cell a width and a height depending on the size it has been given within the size property that is defined within a struct, I pass this through using a configure function, after setting the size of the view.
I then center it on the xAxis and apply any margins around the view using a property within the struct which is just a UIEdgeInset property. Using the SnapKit library this looks like this.
if let formImageItem = formImageItem,
let size = formImageItem.size {
formItemImgVw = UIImageView(frame: CGRect(x: 0, y: 0, width: size.width, height: size.height))
formItemImgVw?.image = formImageItem.image
formItemImgVw?.contentMode = formImageItem.aspectFit
contentView.addSubview(formItemImgVw!)
formItemImgVw?.snp.makeConstraints({ (make) in
make.size.equalTo(CGSize(width: size.width, height: size.height))
make.top.equalTo(formImageItem.margin.top)
make.bottom.equalTo(formImageItem.margin.bottom)
make.centerX.equalToSuperview()
})
}
The issue I seem to be having is i'm getting the following warning.
2018-10-12 14:57:34.101532+0100 xxxx Dev[6104:2160548] [LayoutConstraints] Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.
Try this:
(1) look at each constraint and try to figure out which you don't expect;
(2) find the code that added the unwanted constraint or constraints and fix it.
(
"<SnapKit.LayoutConstraint:0x2830ec720#FormImageViewTableViewCell.swift#61 UIImageView:0x10530a940.height == 114.0>",
"<SnapKit.LayoutConstraint:0x2830ec780#FormImageViewTableViewCell.swift#62 UIImageView:0x10530a940.top == UITableViewCellContentView:0x105503500.top>",
"<SnapKit.LayoutConstraint:0x2830ec7e0#FormImageViewTableViewCell.swift#63 UIImageView:0x10530a940.bottom == UITableViewCellContentView:0x105503500.bottom>",
"<NSLayoutConstraint:0x2837e2580 'UIView-Encapsulated-Layout-Height' UITableViewCellContentView:0x105503500.height == 44 (active)>"
)
Will attempt to recover by breaking constraint
<SnapKit.LayoutConstraint:0x2830ec720#FormImageViewTableViewCell.swift#61 UIImageView:0x10530a940.height == 114.0>
I understand what this is telling me basically that it's choosing to use the height 44 that is set by default for a table view cell. But I can't seem to get my head around why it's using this default height rather than the one that I have defined within my constraints and applying the height to the view whilst also adding the spacing to the top and bottom.
Also when using the debugger to inspect the UI it seems like a height isn't being set at all and as you can see the height of 44 is just clipping the entire imageview.
So ultimately what I'm trying to achieve is the ability to give a view a defined height and width, and use values to apply top and bottom spacing(margins) in order to resize the cell that it's currently within.
You need to lower the priority of the bottom constraints so replace this
make.bottom.equalTo(formImageItem.margin.bottom)
with
make.bottom.equalTo(formImageItem.margin.bottom).priority(999)
plus in viewDidLoad
tableView.estimatedRowHeight = 120
tableView.rowHeight = UITableViewAutomaticDimension
abd don't implement heightForRowAt

Update widthAnchor on Device orientation

I have this constraint in my controller for a view like this:
someView.widthAnchor.constraint(equalToConstant: view.bounds.width).isActive = true
Now I've added this constraint in willLayoutSubviews to update it on device rotation.
But it doesn't seem to update, even more like it adds another width constraint, which of course conflicts with the old width constraint.
Now I don't really know a proper solution to update this width constraint, but it seems to me like I need to remove the constraint first and then set it again.
Which if I test this like this:
someView.constraints.forEach {
someView.removeContraint($0)
}
This works like expected, only it deletes of course some constraints I don't want to delete... so also not a solution.
Sol1
hook the width constraint as IBOutlet and change it's constant in code like this
self.widthCon.constant = //value
self.view.layoutIfNeeded()
Sol2
delete the constraint with identifier
someView.constraints.forEach {
if $0.identifier == "set_id" {
someView.removeConstraint($0)
someView.widthAnchor.constraint(equalToConstant: view.bounds.width).isActive = true
}
}
Alternate Solution:
If you have a reference to the superview of someView then you can simply assign equal width constraints like so:
someView.widthAnchor.constraint(equalTo: superView.widthAnchor)
This way you can let the Autolayout engine update the width automatically when the device orientation changes.

How do I update a constraint from the Storyboard without an IBOutlet or Identifier?

I have a lot of views that are created in the storyboard, but I want them to be able to update their constraints dynamically without having to use an IBOutlet each time.
I started by making a custom class for the superview of the view I want to update, and change its subview's bottom constraint like this:
myView.constraints.filter{ $0.firstAnchor is NSLayoutAttribute.bottom }.constant -= 200
'NSLayoutAttribute.bottom' doesn't seem to be the correct way to check the type of the Anchor.
How do I check the type of the constraints I want to change?
Am I correct in updating the constraints in the superview of the view I want to change, not the view itself?
NSLayoutConstraint from iOS7 have a property called identifier, from code or from IB you can set this property.
After that to get the constraint you are looking for is just a matter of searching it in a particular view.
Consider this UIView extension:
func constraint(withIdentifier:String) -> NSLayoutConstraint? {
return constraints.filter{ $0.identifier == withIdentifier }.first
}
As per dahlia_boy's suggestion, I used UIView.animate to achieve this functionality, however it doesn't seem to be permanent:
translatesAutoresizingMaskIntoConstraints = true
UIView.animate(withDuration: 1, animations: {
self.frame.size.height -= 200
})

iOS Swift Setting View Frame Position Programmatically

I having two sub views inside scrollview. I need to position that both subviews programmatically. I did it correctly by writing code inside DispatchQueue.main.async. Here is the code:
DispatchQueue.main.async {
self.SelectClientDetailView.frame = CGRect(x: 0, y: 637, width: self.SelectClientDetailView.frame.size.width, height: self.SelectClientDetailView.frame.size.height)
self.SelectClientDetailView2.frame = CGRect(x: 0, y: 837, width: self.SelectClientDetailView2.frame.size.width, height: self.SelectClientDetailView2.frame.size.height)
}
Its working good but when I scrolling my scrollview this both views set back to old positions. How to fix it. Its Default y position will be SelectClientDetailView:400 and SelectClientDetailView2: 600
If you are using Auto Layout then setting frame will cause some weird effects. Auto Layout and Frames doesn't go together. You'll need to rearrange the constrains, not the frames. While using Auto Layout changing the frames will cause some weird effects and will eventually revert back to the constraints you've created in the original UIView.
Some solutions:
If you want to use Autolayout approach then, You need to create an outlet to each constrain just like you would to a view and change its constant when needed.
disable Auto Layout in that specific xib and start playing with frames.
If you only want to change the frame Y position, try this instead:
self.SelectClientDetailView.frame.origin.y = 637
self.SelectClientDetailView.frame.origin.y = 837
As already mentioned, you might need to check your view hierarchy to be sure you are actually adding them to the UIScrollView (and not elsewhere).

Resources