Hiding element space without height constraint - ios

This is a reuseable tableview cell. I want to hide 3. UILabel from the top, both the element and its space when it has no data.
I can't create a height constraint of it because I need to use it multiline depends on the text.
if release.post.isEmpty {
cell.label3.isHidden = true
} else {
cell.label3.isHidden = false
}
So how can I hide its space without a height constraint?

You can use the stack view and then hide the required objects i.e label or image. Remember to give the proper constraints to the stack view and select the required properties.

I fixed this by dynamically adding the constraint
cell.match.translatesAutoresizingMaskIntoConstraints = false
cell.match.constraints.forEach { (constraint) in
if constraint.firstAttribute == .height
{
constraint.constant = release.post.height(withConstrainedWidth: cell.match.frame.width, font: UIFont.preferredFont(forTextStyle: UIFont.TextStyle.subheadline)) + 15
}
}

Related

How do I limit the size of a UIView in a storyboard designer and the runtime view overall?

I have a custom UIView that's my little component lets call it PlaceholderView.
My UITableViewCell prototype has a Label and a PlaceholderView that sits inside a UIStackView that's vertically axis.
The PlaceholderView, is supposed to call some custom code that goes to a cache to retrieve a specific view then it adds it to the SubView of the PlaceholderView.
I want this subview to take up the whole surface of the entire PlaceholderView. How do I go about doing that? I tried this but not sure if it does the job
if (view != null)
{
AddSubview(view);
view.SizeToFit();
}
Second question. These view's that I am adding, when I create them during design time, I make a new storyboard, drag and drop a ViewController then proceed to place other controls like Labels and Button's on it.
How do I restrict this ViewController's overall height so it's completely fixed size? I know I can set the simulated metrics, and I am also setting the View. Frame's size to restrict the height.
Are there better ways to make these views constrained easier?
Currently, when I am setting these fixed height values, it does cause some weird issues with overlaps if I set UITableView.RowHeigh to AutomaticDimension.
// attaches all sides of the child to its parent view
extension UIView {
func layoutToSuperview() {
guard let view = self.superview else {return}
self.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
self.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
self.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
self.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
}
}
Usage:
Instead of view.SizeToFit() use view.layoutToSuperview()
I want this subview to take up the whole surface of the entire
PlaceholderView
You can try autolayout:
if (view != null)
{
view.TranslatesAutoresizingMaskIntoConstraints = false;
AddSubview(view);
view.LeadingAnchor.ConstraintEqualTo(this.LeadingAnchor).Active = true;
view.TopAnchor.ConstraintEqualTo(this.TopAnchor).Active = true;
view.TrailingAnchor.ConstraintEqualTo(this.TrailingAnchor).Active = true;
view.BottomAnchor.ConstraintEqualTo(this.BottomAnchor).Active = true;
}
Are there better ways to make these views constrained easier?
The answer is also auto layout. Set a control's height constraint to claim how much space it wants to take. See this thread for more details: Using Auto Layout in UITableView for dynamic cell layouts & variable row heights.
Though it is native oc, you can see its concept.

UIStackView unsatisfiable autolayout constraints

I have a UIStackView defined in storyboard with the first button's height set to 70 and other one set to 45. I get this autolayout error:
[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.
(
"<NSLayoutConstraint:0x280f614f0 UIButton:0x10641a120.height == 45 (active)>",
"<NSLayoutConstraint:0x280f60e60 UIButton:0x106418f80.height == 70 (active)>",
"<NSLayoutConstraint:0x280f604b0 'UISV-alignment' UIButton:0x10641a120.bottom == UIButton:0x106418f80.bottom (active)>",
"<NSLayoutConstraint:0x280f63cf0 'UISV-alignment' UIButton:0x10641a120.top == UIButton:0x106418f80.top (active)>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x280f60e60 UIButton:0x106418f80.height == 70 (active)>
I understand the UIStackView is unable to accept different heights of UIButtons, is that correct and what is the way to have UIStackView accept different heights or widths of it's elements?
Something in your Stack View constraints is causing the problem.
Here is a valid layout:
With the Stack View properties:
The result before adding a third button via code:
And the result after adding a third button (height constraint of 60) via code:
No auto-layout warnings or errors.
The code (connected to Button 1), adds / removes Button 3 as an arranged subview of the stack view:
class TestViewController: UIViewController {
#IBOutlet var theStackView: UIStackView!
var thirdButton: UIButton = {
let b = UIButton()
b.translatesAutoresizingMaskIntoConstraints = false
b.setTitle("Button 3", for: .normal)
b.backgroundColor = .red
return b
}()
#IBAction func doAddThird(_ sender: Any) {
if theStackView.arrangedSubviews.count == 2 {
theStackView.addArrangedSubview(thirdButton)
} else {
if let v = theStackView.arrangedSubviews.last {
v.removeFromSuperview()
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
// finish initializing the third button
if let v = theStackView.arrangedSubviews.first as? UIButton {
thirdButton.titleLabel?.font = v.titleLabel?.font
}
NSLayoutConstraint.activate([
thirdButton.heightAnchor.constraint(equalToConstant: 60),
])
}
}
A Stackview will take on the dimensions of its components, if you don't give it height and width constraints. It looks like you are telling your stackView to be a particular height (either because you have a height constraint or two Y position constraints which imply a height). You cannot both tell the stackView to have a height and tell all of its arrangedSubviews to have a height unless those two values are exactly the same. So for instance if you tell the stack to be 150 high, and your buttons are 45 and 70 high then the one with the lowest content hugging priority loses and gets expanded to take up the extra 35 points of space that the stack view needs to be 150 points high.
Quick solutions:
Remove the hieght constraint on the stack view; it will now be as high as the sum of the high of its elements.
Add a blank UIView to the stack and give it content hugging of 1 and it will take up any extra space (this only works if your stack is bigger than its elements; if its too small you need to reduce the size of the arrangedSubviews instead).

UILabel breaks early inside UIStackView

Given the view hierarchy:
UIStackView
--UILabel
--UISwitch
The label breaks too early, even if it can be fit to a single line.
Setting numberOfLines = 1 forces the label to be laid out correctly.
How to make UILabel perform line break only when needed?
Code:
private lazy var title: UILabel = {
let v = UILabel()
v.numberOfLines = 0
return v
}()
private lazy var toggle = UISwitch()
private lazy var stack = UIStackView(axis: .horizontal,
distribution: .equalSpacing,
alignment: .center,
views: [title,
toggle])
func setupConstraints() {
stack.snp.makeConstraints { (make) in
make.edges.equalTo(contentView.layoutMarginsGuide)
}
}
Result:
Setting numberOfLines = 1 gets me what I'd like to achieve, but the label looses its multi-line functionality:
How to force the desired behavior without losing support for multi-line labels?
When there is a lot of horizontal space, the label gets laid out correctly no matter of the numberOfLines property:
Set your UISwitch's content hugging and resistance priority to 1000.
And stack view distribution and alignment to fill.
Extra Note - If you want label and switch to be top aligned, then set alignment to top.
In your stack view you can give a constraint to your label and switch...
1) give your label leading, top , trailing and bottom constraint. Don't give Width constraint. In trailing constraint take second item Switch.
2) give your switch trailing, top, bottom and Fix width.
Hope it Will work.
Add label inside another stack view.
UIStackView
--UIStackView
--UILabel
--UISwitch

Whats wrong with changing the tableview height with bottom constraint

I have a parent view which has a tableview and tableviews leading,trailing,top,bottom is zero.
and I have a label to show if there are no records ... to show a message and I have vertically and horizontally centered it.
Based on content size of tableview I have to change the parentview's height and i can't directly do because there is no height property defined for parent view .. only leading,trailing,top and bottom property.
Now I have to change the bottom property value with respect to tables content size
if there are no records have to set the bottom constraint to higher value so that parent view height reduces
(Xamarin c# but constraints are same as iOS objective c or swift no change though)
if(vuParent.Frame.Height - tblMine.ContentSize.Height > 0 && !tblMine.Hidden && tblMine.ContentSize.Height!=0)
{
constraintBottomvuParent.Constant = 10 + vuParent.Frame.Height - tblMine.ContentSize.Height;
}
else if(vuParent.Frame.Height - tblMine.ContentSize.Height < 0)
{
constraintBottomvuParent.Constant = 10;
}else
{
constraintBottomvuParent.Constant = 200;
}
if there is any better way kindly let me know
Thanks

How to modify view controller after pressing a button?

Let's say that if you press the button from the bottom of the screen after typing something in the account text field, you would be required to also enter the password like in the second image.
How should I do this? I don't think that creating a new view controller would be good. So, should I somehow modify the same view controller?
How could I add the new password text field under the account text field?
Keep in mind that they are still centered. Hiding and unhiding wouldn't work in this case and I also need to modify more things than only adding that text field.
First, create a UIView with everything you need on them. in this example I will have only two text fields and they are all color coded.
The view needs to be centered both horizontally and vertically, with width and height. Set identifiler for the height constraint to be updated later. Set the clip to board to true so that when we redeuce the height of the view, text fields below will hide. The settings for the view will be like this
For your text fields, they must have a constant padding to top. In my example, they are set to be in center horizontally, having a constant height, width and padding to opp.
Now, all you need to do is to get the height of the view from code and set the height to show or hide the text fields.
var flag = true
#IBAction func click(_ sender: Any) {
if flag {
flag = false
let filteredConstraints = theView.constraints.filter { $0.identifier == "viewHeight" }
if let heightConstraint = filteredConstraints.first {
heightConstraint.constant = 60
}
} else {
flag = true
let filteredConstraints = theView.constraints.filter { $0.identifier == "viewHeight" }
if let heightConstraint = filteredConstraints.first {
heightConstraint.constant = 128
}
}
}
Here is the code running in simulater.
another option is you can make tableView at Center, you need to create tableview height constraint outlet,
then you can maintain a counter how many time you want to add View, the counter should be return in tableView numberOfRowsInSection,
and you can make this view in Prototype Cell or using NIB, then just adjust header label text, textField placeholder and text on specific cell index,
when you increase or decrease counter update tableView Constraint, example you have a cell height as 50, in first case when you have on cell in tableView, you can set your tableView height constraint's constant as 50, when cells are two the 100 and so on.....
I think it's a simple logic

Resources