Dynamically Sized UITextView in Storyboard - ios

I would like to add a paragraph of text to a UIView in my storyboard in the form of a non-editable, non-scrolling and non-selectable UITextView. I would like the UITextView to take up a variable number of lines based on how many it needs. It should have a fixed width and y position. How do I accomplish this in the storyboard in such a way that I can link other UI elements' constraints to the bottom of the UITextView?

Make a constraint pinning the text view’s height to some constant, and make an IBOutlet to that constraint so you can access it in code. Whenever the text changes, set the constraint’s constant to the text view’s contentSize.height:
textView.sizeToFit()
textView.layoutIfNeeded()
textViewHeightConstraint.constant = textView.sizeThatFits(CGSize(textView.frame.size.width, CGFloat.max)).height

Editing Zev Eisenberg answer for Swift 3. CGFloat.max doesn't work anymore. There is now CGFloat.greatestFiniteMagnitude
So updated version for Swift 3 is:
#IBOutlet var textViewHeight: NSLayoutConstraint!
textView.sizeToFit()
textView.layoutIfNeeded()
textViewHeight.constant = textView.sizeThatFits(CGSize(width: textView.frame.size.width,
height: CGFloat.greatestFiniteMagnitude)).height

Selected answer is not work for me. Then i found my solution;
1- Uncheck Scrolling Enabled property. Then, make an IBOutlet that constraint and write that code;
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
textViewConstraint.constant = textView.intrinsicContentSize().height
}

Related

How to set scrollview height programmatically

How can I set the scrollview height programmatically in Xcode 9 with Swift 4? I've set a constraint for the scrollview height and added that as an outlet. But when I change the outlet constant value programmatically it doesn't change the height.
Example:
#IBOutlet weak var scrollview_height: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
self.scrollview_height.constant = 245
}
The height of the ScrollView should be given by it's content and not for you to change manually. At best if you want to do something like that, you have a view inside the scrollView and change the size of that view instead.
Step-by-step:
Add a ScrollView to your view. Set it's constraints (no height or width)
Add a View inside the ScrollView and set it's constraints. Additionally for a vertical scroll you might want to set it's width equal to the SuperView and ensure it has a height.
Create an IBOutlet for the height of the view
update the constant value of the constraint in code
If it does not update as expected, run a layoutIfNeeded on your superview after updates
You have to increase the content Size of your scrollView instead of increasing the frame of scrollView.
self.scrollview.contentSize = CGSize(width: screenWidth, height: yourDesiredHeight)
the scrollable contentSize of scrollView will change According to it.

UITextView auto layout height when using exclusion path

I have a UITableViewCell containing a UITextView and a UIImageView. The text view has scrolling disabled. The UITableViewCell does use auto layout to calculate its height to fit the content.
If there is more text than in the screenshot I want the text to flow around the image and use the space below it too. Therefore I use exclusion path on the text view. The exclusion Path gets set correctly and the text flows around the image.
Exclusion paths must be set after auto layout has calculated the frames. As the exclusion path blocks some view space on the text view the containing text does not fit any more in the height auto layout calculated for the text view.
How can I make this work together with auto layout?
I tried to set a height constraint on the text view after setting exclusion paths:
let size = textView.sizeThatFits(CGSize(width: textView.frame.size.width, height: CGFloat(MAXFLOAT)))
textView.heightAnchor.constraint(equalToConstant: size.height).isActive = true
This does not help. I need to call layoutSubviews() on the UITableViewCell to force it to recalculate its height. However this will create an endless loop as I set my exclusion paths in viewDidLayoutSubviews().
I found that UITextView does NOT recalculate intrinsicContentSize when isScrollEnabled is false and textContainer.exclusionPaths changes.
The solution was simple:
class FixedTextView : UITextView {
func setExclusionPaths(_ paths: [UIBezierPath]) {
textContainer.exclusionPaths = paths
if !isScrollEnabled {
invalidateIntrinsicContentSize()
}
}
}
I had a similar issue where I couldn't feasibly access viewDidLayoutSubviews() without a lot of excessive coupling, so I feel your pain.
Suppose you have view A and the subviews include a UITextView.
In view A, override layoutSubviews()
override public func layoutSubviews() {
super.layoutSubviews()
// At this point, UITextView is laid out and has a valid frame.
// Set exclusion paths here, now that you have enough info to set coordinates.
super.layoutSubviews() // do it again.
}
This is similar to the approach taken with UILabel and maxPreferredWidth on prior iOS versions.
iOS: Multi-line UILabel in Auto Layout
One caveat: I don't know that setting a constraint in here will help you, as the layout cycles don't really work that way, but according to this Update Constraints of Cell Subview , you might be able to get away with doing layoutIfNeeded().

How to lock designable size of custom UView

I am making a custom activityIndicator. I wanted it to behave like UIActivityIndicatorView but with different animations.
When you place UIActivityIndicatorView to Storyboard the width and height of this view are locked for modification (grayed out).
There is no problem to make fixed width for the view in code but
is it possible to make custom view the same way UIActivityIndicatorView is made: with width and height grayed out in storyboard?
Thorax, good day!
Well, i found an answer for your question here!
Though it was 1.5 year ago, i don't think that something had changed
I don't know how to grayed out width and height, but there is a way to avoid setting width and height constrains all the time in IB: you should just override intrinsicContentSize() in your UIView subclass.
In Swift for example:
override func intrinsicContentSize() -> CGSize {
return CGSizeMake(50, 50)
}

Moving UILabel dynamically based on UITextView contents - Using Storyboard

Using storyboard, I am trying to put a UILabel below UITextView. Content of UITextView can grow based on user input. I want my UILabel to reposition its Y value based on UITextView contents. I've tried fixing vertical spacing between UITextView and UILabel but that is not helping.
What else I shall be doing to crack this?
You should use constraints explicitly. The label in particular must have the constraint "top space to Textview" set to N points. Then set an outlet in your view controller from the constraint "top space to Textview" and change that constraint to resize uilabel Y position.
#IBOutlet weak var labelYConstraint: NSLayoutConstraint!
func changeLabelPosition(sender: AnyObject) {
labelYConstraint.constant = newY
}
Let me know if you need more details

How to make UITableView's height dynamic with autolayout feature?

I am using autolayout in Xcode 5.
I set the table view's height to Greater than or equal to 200px. I want that it has dynamic size. Because sometimes it will have many rows, sometimes it will have a few rows.
But the size is always 200px. And if the content is larger than that, I should scroll down to see the lower rows.
What should I do to give the tableview dynamic size?
This is tested with the latest version of Xcode.
1) In Xcode go to the storyboard and click on you table view to select it.
2) In the Utilities pane (see picture 1) make sure the constraint for the table view height is defined.
3) In the view controller that displays the table view create an outlet to this constraint:
In Swift 3
#IBOutlet weak var dynamicTVHeight: NSLayoutConstraint!
In Objective C
#property (strong, nonatomic) IBOutlet NSLayoutConstraint *dynamicTVHeight;
4) In the storyboard go back to the height constraint for the UITableView and verify that the icon in the right has changed the color from purple to blue (see picture 2)
4) Also put this code in the same view controller:
Swift
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
tableView.reloadData()
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
let height = min(self.view.bounds.size.height, tableView.contentSize.height)
dynamicTVHeight.constant = height
self.view.layoutIfNeeded()
}
Objective C
- (void)viewWillAppear:(BOOL)animated
{
// just add this line to the end of this method or create it if it does not exist
[self.tableView reloadData];
}
-(void)viewDidLayoutSubviews
{
CGFloat height = MIN(self.view.bounds.size.height, self.tableView.contentSize.height);
self.dynamicTVHeight.constant = height;
[self.view layoutIfNeeded];
}
This should solve your problem.
These are the links to two versions of the sample project that does what you want, one for Objective C and the other one for Swift 3. Download it and test it with Xcode. Both projects work with the latest version of Xcode, Xcode 8.3.2.
https://github.com/jcatalan007/TestTableviewAutolayout
https://github.com/jcatalan007/TestTableviewAutolayoutSwift
create your cell by xib or storyboard. give it's outlet's contents. now call it in CellForRowAtIndexPath. eg. if you want to set cell height according to Comment's label text.
so set you commentsLbl.numberOfLine=0;
then in ViewDidLoad
self.table.estimatedRowHeight = 44.0 ;
self.table.rowHeight = UITableViewAutomaticDimension;
and now
-(float)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
return UITableViewAutomaticDimension;}
voila ............ you did it....
It can be done programmatically. The concept (and code itself) is actually very simple:
In the updateConstraints method of myTableView's superview, add a constraint so that myTableView's height is equal to myTableView.contentSize.height.
Tested on Xcode 6 targeting iOS 7.
You can Ctrl+Drag the height constraint of your UITableView into your view controller source code and give it a name. Then in updateViewConstraints of your ViewController you can set the constant of that constraint to tableView.contentSize.height
....
#IBOutlet weak var tableViewHeightConstraint: NSLayoutConstraint?
....
override func updateViewConstraints() {
super.updateViewConstraints()
tableViewHeightConstraint?.constant = tableView.contentSize.height
}
Or you can satisfy height constraint from storyboard and check:
[x]Remove at build time
Then, in your controller, update tableview's height which contains all your cells stuff. (*I use PureLayout as framework over AutoLayout)

Resources