Custom UIView as navigationItem title - ios

I want to create simple custom view and use it for navigationItem.titleView. My custom view is very simple, has only image view and label: [image]-[label]. I have xib file where I have defined all constraints (both subviews has constraint to superview - I want to height and width of subviews determine height and width of entire custom view). The problem is that when I instantiate view from xib like this:
class func titleViewWithTitle(title: String, icon: UIImage?) -> TitleView {
let titleView = NSBundle.mainBundle().loadNibNamed("TitleView", owner: self, options: nil).first as TitleView
titleView.title.text = title
titleView.icon.image = icon
titleView.layoutSubviews()
return titleView
}
the size of this view is not determined by it's children. It has the size that was manually set in Interface Builder. What can I do to force the view to dynamically calculate size?

In your custom view, override the layoutSubviews method and add this:
CGSize targetSize = [self systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
Create a CGRectFrame from this and set this frame as a new frame for self (which is the custom view).
This will basically find the smallest possible frame that still encompasses its content in a way that all content is shown.
Note: All subviews of this custom view must have autolayout compression resistance set properly. I.e. they must resist shrinking.

Related

inputAccessoryView not getting touch events on iPhone X

I have a view that I assign as the inputAccessoryView of my view controller. I adjusted the constraints so that it's above the home indicator on iPhone X (X, XR, XS, XS Max). I keep that inputAccessoryView pinned to the bottom of the screen when the keyboard is hidden by setting canBecomeFirstResponder to true in my view controller.
It works on all phones except for the X family. On all of the X phones, my view is not getting any touch events - they are hitting the view below it, as if inputAccessoryView wasn't there.
If I constrain the bottom to superview instead of safeArea, it works, but then it's too close to the home indicator, which I don't want:
In this radar ("inputAccessoryViews should respect safe area inset with external keyboard on iPhone X"), Apple engineers say that this is not a bug and that developers should constrain one of the views to its parent's safeAreaLayoutGuide:
Engineering has provided the following feedback regarding this issue: It’s your responsibility to respect the input accessory view’s safeAreaInsets. We designed it this way so developers could provide a background view (i.e., see Safari’s Find on Page input accessory view) and lay out the content view with respect to safeAreaInsets. This is fairly straightforward to accomplish. Have a view hierarchy where you have a container view and a content view. The container view can have a background color or a background view that encompasses its entire bounds, and it lays out it’s content view based on safeAreaInsets. If you’re using autolayout, this is as simple as setting the content view’s bottomAnchor to be equal to it’s superview’s safeAreaLayoutGuide.
I believe that's exactly what I'm doing, but I'm clearly missing something since it breaks on X.
GitHub project is here: https://github.com/nambatee/HorizontallyScrollableToolbarAccessoryView/tree/master/Horizontally%20Scrollable%20Toolbar%20Accessory%20View
Your problem is actually is that you are not setting a height for inputAccessoryView and your scrollView is out of bounds that's why you are not getting the touch events and just to prove that if you go to your top level view and set it to clips to bounds and run your project this is what you get
So why is this happening? it's because you view is not having an intrinsicContentSize you can give it an intrinsicContentSize by subclassing UIView and override intrinsicContentSize and return what ever width and height you want just like this
class CustomView: UIView {
override var intrinsicContentSize: CGSize {
return CGSize.zero
}
}
Don't forget to set your view to be CustomView in code and in the nib file
private lazy var horizontallyScrollableToolbarAccessoryView: CustomView? = {
let nibName = "HorizontallyScrollableToolbarAccessoryView"
let view = Bundle.main.loadNibNamed(nibName, owner: nil, options: nil)?.first as? CustomView
return view
}()
you can also provide the height through a height constraint like this
override func viewDidLoad() {
super.viewDidLoad()
self.horizontallyScrollableToolbarAccessoryView?.heightAnchor.constraint(equalToConstant: 80).isActive = true
}
but you will still need to set your intrinsicContentSize to be CGSize.Zero
class CustomView: UIView {
override var intrinsicContentSize: CGSize {
return CGSize.zero
}
}
and that's what you get at the end a working scrollView

How can I make views height depend on its content in Swift?

I have got a view and some elements in it
let background_img_view: UIView = {
let view = UIView()
return view
}()
background_img_view.addSubview(background_image)
background_img_view.addSubview(border)
background_img_view.addSubview(about_txt)
about_txt size is unknown, it can be 30px or 300px, now I want my background_img_view's height to depend on about_txt's height.
How can I make it happen programmatically?
Have you tried using the sizeThatFits(_:) method for the about_txt view. Use the size that this function returns and set the superview's size to that.
https://developer.apple.com/reference/uikit/uiview/1622625-sizethatfits
If you have the subviews added before the view is on the screen, you could set the height in the viewWillAppear method of your view controller. You can also update the size in viewWillLayoutSubviews.
If you're using auto layouts, have a look at setNeedsLayout vs. setNeedsUpdateConstraints and layoutIfNeeded vs updateConstraintsIfNeeded

How to get height of UILabel, UITextView in Swift after dynamic resize

I have a UILabel and a UITextView created in storyboard that both change height to fit the text that is passed into them. I need to fetch the height of both of them programmatically in order to size my view correctly (view embedded in scroll view), but when I run this code in their view controller, it gives me the height defined in storyboard rather than the resized height. articleText is my text view, and articleLabel my label.
articleText.attributedText = largeTextString
articleLabel.attributedText = labelString
print(articleText.contentSize.height)
print(articleLabel.bounds.size.height)
// Both return storyboard value, not resized value
Thanks in advance!

Auto Layout View Hierarchy

I need to display the layout I have in the picture in my app.
The view hierarchy is:
scroll view (scrollEnabled = true)
image view
label
webview (scrollEnabled = false)
table view (scrollEnabled = false, max amount of rows = 6)
The web view height is dynamically changed by it's delegate webViewDidFinishLoad.
func webViewDidFinishLoad(webView: UIWebView) {
webView.sizeToFit()
}
How can I set up the auto layout to move the table view below the web view?
First of all you need to add containerView in scrollView and then add subViews to containerView.
Below I’ve displayed the hierarchy you need to follow for displaying content in UIScrollView and the constraints you need to set.
scroll View (constraints :- leading,trailing,top,bottom)
Container View (constraints :- leading,trailing,top,bottom,widthsEqually to View,heightsEqually to View or height = 1000)
NOTE : If all subViews has specific height then there is no need to give height to ContainerView.
UIImageView (constraints :- leading,trailing,top,verticalSpacing,height)
UILabel (constraints :- leading,trailing,top,verticalSpacing,height)
UIWebView (constraints :- leading,trailing,top,verticalSpacing,height>=0)
UITableView (constraints :- leading,trailing,top,Bottom)
NOTE: give height to tableView if required. You will need to make changes in height constraint of UIWebView programmatically at run time based on your requirement.
For more reference please refer links below:
http://spin.atomicobject.com/2014/03/05/uiscrollview-autolayout-ios/
http://blog.surecase.eu/working-with-uiscrollview-in-storyboard-using-autolayout/
http://makeapppie.com/2014/12/11/swift-swift-using-uiscrollview-with-autolayout/

Subclassed UIView not visible, however content is visible

I subclassed UIView: http://pastebin.com/MVk1XmPS and when I add it to another view of a UIViewController:
self.myView = MyView.newAutoLayoutView()
self.myView.backgroundColor = UIColor.redColor()
self.view.addSubview(self.myView)
the red background is missing. It seems that myView has no width and height. However the content is visible:
I have to hard code the dimension:
self.myView.autoSetDimensionsToSize(CGSize(width: 100, height: 100))
but shouldn't it grow automatically by the size of the content? I use swift, xcode6.1 and iOS8.1
Views do not automatically grow to fit their content. If you enable clipsToBounds on your view, you will see the content disappear. Alternatively, if you put a button as part of your content, you will see it but be unable to interact with it because it is outside of its superview's bounds.
In your subclass, you could implement the sizeToFit or sizeThatFits: methods, but these are not going to be automatically called by the system. You should consider assigning constraints for your view in your storyboard. If you're not using a storyboard, you will need to assign a frame in your viewWillLayoutSubviews or layoutSubviews method.
Storyboards will also like your custom view better if you implement intrinsicContentSize.

Resources