Why the custom separator view in the cell changes height? - ios

I have custom tableViewCell. And in it cell i have custom separator. The logic of work should be like this:
if select textField in cell - separator change color and
height(from 1 to 2)
if type text - separator color and height not
change
Now it's work like:
if not added constrain for height for separator in .xib - added constrain for height when create cell, but in screen it equal 0
override func awakeFromNib() {
customSeparator.backgroundColor = .lightGray
customSeparator.frame.size.height = 1.0
}
if added constrain for height for separator in .xib - when select cell height of separator change(like expected). But when type text height change to value specified in .xib
func textFieldDidBeginEditing(_ textField: UITextField) {
customSeparator.backgroundColor = .black
customSeparator.frame.size.height = 2.0
}
So, why is this happening, tell me, plz

You need to create an height IBOutlet constraint and change it as follows:
#IBOutlet weak var customSeparatorHeight: NSLayoutConstraint!
override func awakeFromNib() {
customSeparator.backgroundColor = .lightGray
customSeparatorHeight.constant = 1
self.contentView.layoutIfNeeded()
}

Related

iOS TextField view glides out of layout

I'm using TextField in my app. I made it to wrap the content.
The problem is when the user types a long text the TextField edges glides out of the layout and make some of the view invisible.
is there a way to disable it to expend when it reaches to the layout edges?
The best thing to do is to change your UITextField to a UITextView. Here's a function that I like to use quite a lot for this autoresize technique that you'll see in the likes of Apples iMessage:
func containerViewHeight() {
let size = textView.sizeThatFits(CGSize(width: textView.frame.size.width, height: CGFloat.greatestFiniteMagnitude))
containerView.heightAnchor.constraint(equalToConstant: size.height + 24)
self.textView.setContentOffset(.zero, animated: false)
}
You'll want to call this function initially inside of your viewDidLoad:
override func viewDidLoad() {
self.containerViewHeight()
}
As well as that, you'll want to conform to the UITextViewDelegate methods by subclassing it at the top of your file like so:
class YourViewController: UIViewController, UITextViewDelegate
Once you add this AND you have used self.textView.delegate = self inside of your viewDidLoad:
override func viewDidLoad() {
self.textView.delegate = self
}
you'll then be able to use the textViewDidChange method for that textView, so the final thing you'll want to add in your class is this:
func textViewDidChange(_ textView: UITextView) {
self.containerViewHeight()
}
Your textField probably doesn't have a fixed width.
Just put a width constraint to your textField in your storyboard so it will always have the same width, no matter if the text is too long.
Edit : if you want a maximum width, you can add 2 width constraints to your textField. One for minimum width and one for maximum width. This way the width of your textField will vary between 100 and 200, depending on the text it contains.
Minimum width constraint :
Maximum width constraint :

UIlabel Sizetofit unexpected behavious

I am facing an unexpected behavior with my UIlabel sizeToFit() method. Now I have tried making the numberOfLines = 0, I event called LayoutIfNeed(). But None of them works.
I even tried methods given in this question : Vertically align text to top within a UILabel
But Again None helped. I don't have to many constraints, I am just using Auto resizing pins. I even tried it with no constraints or no auto resize.
I have this label set up in TableViewCell and CollectionReusableView. Calling it in awakeFromNib() just doesnt affect.
UIcollectionReusableView code :
override func awakeFromNib() {
super.awakeFromNib()
label.sizeToFit()
label.numberOfLines = 0
label.layer.shadowOffset = CGSize(width: 0, height: 0)
label.layer.shadowOpacity = 3
label.layer.shadowRadius = 8
}
constrains :
TableViewCell Code:
override func layoutSubviews() {
super.layoutSubviews()
// this is the UIview on which the label is put on.
contentView.layoutIfNeeded()
}
override func awakeFromNib() {
super.awakeFromNib()
// This is the label has the issue
caption.sizeToFit()
}
Constraints :
Also, Label in the text view is stacked with Another Label and stackview constrainst are :
here is the example:
It Just doesn't seem to work. I am totally out of idea.
Any help is greatly appreciated.
You need to call sizeToFit() after the text is added to the label, not before.

Dynamic UITextView mislocation behavior

I am trying to have a textview similar to iPhone messages, where the textview initially has a constraint (height <= 100) and the scrollEnabled = false
This is a link to the project:
https://github.com/akawther/TextView
The text view increases in height based on the content size as in the image on the left until it reaches the height of 100, then the scrollEnabled is set to true. It works perfectly until I click the "send" button on the lower right where the textView should become empty and go back to the original height and scrollEnabled becomes false. The middle image shows what happens when I click the button. When I start typing the textview moves down as you see in the last image on the right.
I want to be able to click the button and eliminate the behavior shown on the middle image, how can I fix this?
import UIKit
class ViewController: UIViewController, UITextViewDelegate {
#IBOutlet weak var bottomConstraint: NSLayoutConstraint!
#IBOutlet weak var messageTextView: UITextView!
#IBOutlet weak var parent: UIView!
let messageTextViewMaxHeight: CGFloat = 100
override func viewDidLoad() {
super.viewDidLoad()
self.messageTextView.delegate = self
}
#IBAction func Reset(sender: AnyObject) {
messageTextView.text = ""
messageTextView.frame.size.height = messageTextView.contentSize.height
messageTextView.scrollEnabled = false
self.parent.layoutIfNeeded()
}
func textViewDidChange(textView: UITextView) {
if textView.frame.size.height >= self.messageTextViewMaxHeight {
textView.scrollEnabled = true
} else {
textView.scrollEnabled = false
textView.frame.size.height = textView.contentSize.height
}
}
}
You can replicate my issue by following these steps in the github project:
1. keep typing words and pressing enters until you start seeing the scroll
2. Click the button you will see that the textview goes up in the blue
container. This is the issue I want to eliminate!
Try bellow code :-
#IBAction func Reset(sender: AnyObject) {
messageTextView.scrollEnabled = false
messageTextView.text = ""
messageTextView.frame.size.height = messageTextView.contentSize.height
parent.frame.size.height = 20
self.view.layoutIfNeeded()
}
func textViewDidChange(textView: UITextView) {
if textView.contentSize.height >= self.messageTextViewMaxHeight {
textView.scrollEnabled = true
} else {
textView.frame.size.height = textView.contentSize.height
textView.scrollEnabled = false
}
}
Your issue is that the UITextView has conflicting properties:
Place on the screen
Size
The size being constrained will cause an issue when you need a resizable TextView. Also, when the TextView is resized, its location is being changed in this case.
Alternate method to approach the issue:
Try setting constraints to its location in relation to the bottom of the screen. When the Keyboard appears, you should move the TextView up with it. Also setting constraints on the height of a resizable TextView is bad practice unless you are planning on forcing the user to scroll.
Hope this helps.
If you are using auto layout, you should be updating to constraint instead of updating the textView.frame.Try create a IBOutlet for your textView heightConstraint then set the updated height to it.
IBOutlet weak var textViewHeightConstraint: NSLayoutConstraint!
//calculate the height and update the constant
textViewHeightConstraint.constant = textView.contentSize.height

How to automatically adapt height of UITableViewCell containing a multiline UIButton?

A subclass of UITableViewCell contains a UIButton with multi-line text, i.e. property numberOfLines = 0.
The table view cells vary in height, so the cell height is set to UITableViewAutomaticDimension.
The cell height adapts when adding a UILabel with multiple text lines. However it does not adapt with a UIButton, in fact also the frame of the button does not adapt to the frame of its titleLabel.
What can I do to make the table view cell and its content view adapt to the button height?
class MyButtonCell: UITableViewCell {
var button: UIButton!
var buttonText: String?
convenience init(buttonText: String?) {
self.init()
self.buttonText = buttonText
button = UIButton(type: UIButtonType.System)
button.titleLabel?.numberOfLines = 0
button.titleLabel?.lineBreakMode = .ByWordWrapping
button.contentHorizontalAlignment = .Center
button.titleLabel?.textAlignment = .Center
button.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubView(button)
NSLayoutConstraint.activateConstraints([
button.topAnchor.constraintEqualToAnchor(self.contentView.topAnchor),
button.bottomAnchor.constraintEqualToAnchor(self.contentView.bottomAnchor),
button.rightAnchor.constraintEqualToAnchor(self.contentView.rightAnchor),
button.leftAnchor.constraintEqualToAnchor(self.contentView.leftAnchor)
])
button.setTitle(buttonText, forState: .Normal)
button.setTitleColor(buttonTextColor, forState: UIControlState.Normal)
button.titleLabel?.font = buttonFont
}
}
The cell height is calculated automatically with:
tableView.estimatedRowHeight = 100
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
UPDATE:
Example project on https://github.com/mtrezza/ButtonCellHeightBug
Filed Apple Bug Report #26170971.
The bug results in this:
Fully dynamic height for table view cell is achievable by 1) using estimated row height, 2) setting rowHeight to AutoDimension, 3) and most importantly using constraints in your xib/storyboard. The cell can contain buttons/labels or whatever UI components you'd like to have, as long as you constrain them properly, particularly to make sure things are constrained vertically so table view can figure out the cell height. And in this way you don't have to calculate height for dynamic text, no need for sizeToFit/sizeThatFit, and it works for different screen sizes.
You should use estimatedHeightForRowAtIndexPath. On your button, you can call sizeToFit(), which will resize it to contain the text.
Also, if you set the estimated size on the tableView (as you did), you usually don't need to call the heightForRowAtIndexPath, or estimatedHeightForRowAtIndexPath, and the tableView will set it for you.
EDIT:
I created a test project, and you seem to be correct. Using a UIButton setTitle does not resize the cell.
A workaround, is to do the calculation using a label in heightForRowAtIndexPath, and return that value + any padding. Then in cellForRowAtIndexPath, you can still set the title on the button and it will appear.
//paragraphs is just a string array.
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
let label = UILabel(frame: CGRectMake(0,0,tableView.frame.width, <your prototype height>))
label.numberOfLines = 0
label.text = paragraphs[indexPath.row]
label.sizeToFit()
print(label.frame.height)
return label.frame.height
}
Bug in iOS?
The problem is that the internal UIButtonLabel resizes correctly, but the actual UIButton does not.
I've worked around this by extending UIButton and overriding a couple of things:
override func layoutSubviews() {
super.layoutSubviews()
self.titleLabel?.preferredMaxLayoutWidth = self.titleLabel?.frame.size.width ?? 0
}
override var intrinsicContentSize: CGSize {
return self.titleLabel?.intrinsicContentSize ?? CGSize.zero
}
You'll also need to make sure that titleLabel?.numberOfLines = 0 and titleLabel?.lineBreakMode = .byWordWrapping.

Set max lines to 3 and adjust height according to label content

I've created a label in a tableViewCell which contain a string of text. The size of the string can vary however it should maximum be 3 lines. However i can't seem to do this? What is the easiest way to create such a functionality in this label so far i've just created this label in my tableViewCell Subclass.
#IBOutlet weak var dummyLabel: UILabel!
In your custom UITableViewCell class add this:
override func layoutSubviews() {
super.layoutSubviews()
dummyLabel.sizeToFit()
}
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
dummyLabel.numberOfLines = 3
}
Similar post here about label resize in UITableViewCell: Swift : align UILabel text in the top rather in the middle

Resources