Autolayout with xib and storyboard won’t use my constraints - ios

I am trying to create a reusable view (xib) and use it in my storyboard with autolayout. The problem is that it does not seem to use the constraints that I have set up on the storyboard for it.
So my realy basic IOS-project contains:
MyView.swift
MyView.xib
Main.storyboard
ViewController.swift
The MyView class is connected to the xib file in the proper manner:
import UIKit
class MyView: UIView {
#IBOutlet var View: UIView!
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
NSBundle.mainBundle().loadNibNamed("MyView", owner: self, options: nil)
self.addSubview(self.View);
}
}
In my storyboard i added a UIView (CustomClass=MyView) with 2 simple height/width constraints. When I run the app the view is not sized according to those constraints. It is rendered with the height/width properties in the xib.
Does anyone have a clue on how to make my custom view conform to my constraints that I set up in my storyboard?

Are you saying that your UIView is rendered with the height and width of the xib when you load it's view with the xib? Meaning like, the xib is the only thing you see when you run the simulator? If so, I think the simple solution is to create an additional UIView that loads the xib. Make the NewView a subview of MyView That way you have MyView -> NewView(loaded with xib).
Sorry if that is way off. It is just a little difficult to get what you mean without seeing it. Maybe throw up a screenshot or two. Would have posted this as a comment and not an answer but I don't have the reputation yet.

this should help
var contentView = NSBundle.mainBundle().loadNibNamed("MyView", owner: self, options: nil)
contentView.setTranslatesAutoresizingMaskIntoConstraints(false)
self.addSubview(contentView)
var constTop:NSLayoutConstraint = NSLayoutConstraint(item: contentView, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: self, attribute: NSLayoutAttribute.Top, multiplier: 1, constant: 0);
self.view.addConstraint(constTop);
var constBottom:NSLayoutConstraint = NSLayoutConstraint(item: contentView, attribute: NSLayoutAttribute.Bottom, relatedBy: NSLayoutRelation.Equal, toItem: self, attribute: NSLayoutAttribute.Bottom, multiplier: 1, constant: 0);
self.view.addConstraint(constBottom);
var constLeft:NSLayoutConstraint = NSLayoutConstraint(item: contentView, attribute: NSLayoutAttribute.Left, relatedBy: NSLayoutRelation.Equal, toItem: self, attribute: NSLayoutAttribute.Left, multiplier: 1, constant: 0);
self.view.addConstraint(constLeft);
var constRight:NSLayoutConstraint = NSLayoutConstraint(item: contentView, attribute: NSLayoutAttribute.Right, relatedBy: NSLayoutRelation.Equal, toItem: self, attribute: NSLayoutAttribute.Right, multiplier: 1, constant: 0);
self.view.addConstraint(constRight);

Related

Adding view from xib in front of other views

I'm trying to add a custom view from a xib in front of other views. However, for some reason it's never placed as the front view when theres a UITableView on screen. Here's my code:
noInternetView = NSBundle.mainBundle().loadNibNamed("NoInternetView", owner: self, options: nil)[0] as! NoInternetView
noInternetView.translatesAutoresizingMaskIntoConstraints = false
noInternetView.delegate = self
self.view.addSubview(noInternetView)
self.view.addConstraint(NSLayoutConstraint(item: noInternetView, attribute: .CenterX, relatedBy: .Equal, toItem: self.view, attribute: .CenterX, multiplier: 1, constant: 0))
self.view.addConstraint(NSLayoutConstraint(item: noInternetView, attribute: .CenterY, relatedBy: .Equal, toItem: self.view, attribute: .CenterY, multiplier: 1, constant: 0))
I place this at the bottom of my viewDidLoad() code. Why could this be?
noInternetView.hidden = true
your view is hidden, do it visible
noInternetView.hidden = false
self.view.bringSubviewToFront(noInternetView)
Try this it may help you.
First
Check is there a noInternetView have width and height constraints
Second
Add self.view.layoutIfNeeded() after self.view.addConstraint
this help to adjust autolayout you added
If you want your view to be on the top, add it to the window instead.

UIScrollView dynamic height content (autolayout) not filling whole space

I am creating a small chat app in which I use a custom subclass of UIScrollView to present the messages. This app is just for practicing so I don't want to use a third party library. I am implementing this UIScrollView via autolayout, after reading the technical note 2154 by Apple and several tutorials explaining this, and my implementation is almost working but the content view of my UIScrollView doesn't seem to fill all the space available.
The code which presents the ScrollView is:
public class ChatView: UIScrollView {
private var contentView: UIView
...
// This get called by all the init methods. contentView is already created ( contentView = UIView() )
private func setupViews() {
self.translatesAutoresizingMaskIntoConstraints = false
contentView.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(contentView)
let constraint1 = NSLayoutConstraint(item: self, attribute: .Top, relatedBy: .Equal, toItem: contentView, attribute: .Top, multiplier: 1.0, constant: 0.0)
let constraint2 = NSLayoutConstraint(item: self, attribute: .Bottom, relatedBy: .Equal, toItem: contentView, attribute: .Bottom, multiplier: 1.0, constant: 0.0)
let constraint3 = NSLayoutConstraint(item: self, attribute: .Width, relatedBy: .Equal, toItem: contentView, attribute: .Width, multiplier: 1.0, constant: 0.0)
let constraint4 = NSLayoutConstraint(item: self, attribute: .CenterX, relatedBy: .Equal, toItem: contentView, attribute: .CenterX, multiplier: 1.0, constant: 0.0)
self.addConstraints([constraint1, constraint2, constraint3, constraint4])
self.layoutIfNeeded()
// Later, the messages are added to the contentView. I don't think is relevant to see the exact code (but I can post it if needed)
// Each message is added using autolayout and the constraints only reference the messages themselves and contentView
}
}
When I add a ChatView to my view controller (using storyboards), with its four sides pinned to views which are not in his hierarchy, the following problem happens:
In the image, the scrollView cannot be scrolled upwards any more. There seem to be a space which should be filled and isn't. If I scroll down, I have the exact same problem but the empty space is below the content. In the following images you can see that the contentView is smallest than the ChatView itself:
And the same view hierarchy but with the constraints shown:
In both images the view in the background is the ChatView and the selected one is the contentView. I haven't been able to figure why the content view doesn't cover the full ChatView space.
Thanks in advance!
I finally stumbled upon the answer while searching a different problem, in another stackoverflow question. The key is to open the storyboard and set in the container view controller "AdjustsScrollViewInsets" to "NO".
In code it's simply (inside the view controller):
self.automaticallyAdjustsScrollViewInsets = NO;

How to create a custom UIView which has just a button and then can be used throughout the app placing it in different positions?

I have already created a circular button which is a custom UIView.Here's the code:
class HelpTips: UIView {
weak var hotSpot: UIButton!
override init(frame: CGRect) {
super.init(frame: frame)
let strongHotSpot = UIButton()
hotSpot = strongHotSpot
self.addSubview(strongHotSpot)
hotSpotOne.translatesAutoresizingMaskIntoConstraints = false
hotSpotOne.backgroundColor = UIColor.TRLMHelpTipYellowColor()
hotSpotOne.layer.borderColor = UIColor.TRLMHelpTipStrokeColor().CGColor
hotSpotOne.layer.borderWidth = 1
let horizontalConstraint = NSLayoutConstraint(item: hotSpot, attribute: .Leading, relatedBy: .Equal, toItem: self, attribute: .Leading, multiplier: 1.0, constant: -1)
let verticalConstraint = NSLayoutConstraint(item: hotSpot, attribute: .Top, relatedBy: .Equal, toItem: self, attribute: .Top, multiplier: 1.0, constant: 16)
let widthConstraint = NSLayoutConstraint(item: hotSpot, attribute: .Width, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant: 40)
let heightConstraint = NSLayoutConstraint(item: hotSpot, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant: 40)
self.addConstraints([verticalConstraint, horizontalConstraint, widthConstraint, heightConstraint])
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
Now this same button is used throughout the app at several places but it's placed at different positions. So each View Controller will make use of that UIView.
So technically the look of the button remains the same but the constraints for that button keep on changing depending on it's position. I want to follow DRY(Don't repeat yourself) technique here.
I have done this kind of thing before but the code was being repeated several times and was not efficient. How to go about this?
Any help is appreciated. Thanks!
You could create a custom navigation controller and store the view as a property in it. Every view controller will have access to the navigation controller, so they can just reference that property and time you need to use the view. Should keep it DRY.
Create a custom view using an xib. Add your UIButton as subview.
This tutorial will be helpful.

in my viewcontroller, I add a subview which has a xib, I set the autolayout in the xib, but when i add the view to the view controller it doesn't work

first I have my custom view named FindFriendHeadPublish.h,which contains a xib file as follows,I have set the autolayout,and the view is OC
and my view controller which named PreviewViewController.swift also has a xib
and I add the FindFriendHeadPublish view to the view controller, but the autolayout in the FindFriendHeadPublish doesn't work
override func viewDidLoad() {
super.viewDidLoad()
self.title = "我的卡片预览"
var addpreviewView = NSBundle.mainBundle().loadNibNamed("FindFriendHeadPublish", owner: nil, options: nil)
var previewView = addpreviewView.last as! FindFriendHeadPublish
previewView.setTranslatesAutoresizingMaskIntoConstraints(false);
GetUserInfoInterface.getUserInfoWithFUid(UserInfoSaveUtil.getUserInfo().userid, withBlock: { (userInfo:GetUserInfoVo! , error:NSError! ) -> Void in
})
self.scrollView.contentSize = CGSizeMake(320, 640)
self.scrollView.addSubview(previewView)
}
I have check some other problems , but I haven't find a solution, any one can help, thank you
further more, the custom view works well in another viewcontroller which write in OC
and the code above works as follows
First of all add Hieght Constraint to previewView in the nib
then add the following code after previewView.setTranslatesAutoresizingMaskIntoConstraints(false);
var constraints: NSMutableArray = NSMutableArray()
constraints.addObject(NSLayoutConstraint(item: previewView, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: self.scrollView, attribute: NSLayoutAttribute.Top, multiplier: 1.0, constant: 0.0))
constraints.addObject(NSLayoutConstraint(item: previewView, attribute: NSLayoutAttribute.Left, relatedBy: NSLayoutRelation.Equal, toItem: self.scrollView, attribute: NSLayoutAttribute.Left, multiplier: 1.0, constant: 0.0))
constraints.addObject(NSLayoutConstraint(item: previewView, attribute: NSLayoutAttribute.Right, relatedBy: NSLayoutRelation.Equal, toItem: self.scrollView, attribute: NSLayoutAttribute.Right, multiplier: 1.0, constant: 0.0))
self.scrollView.addConstraints(constraints as [AnyObject])
Hope that helps.
You did not set the constraints for previewView and its superview, which you cant do in IB if the views are not in one file.
previewView.setTranslatesAutoresizingMaskIntoConstraints(false);
let viewBindingsDict = ["previewView":previewView, "view":self.view]
self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[previewView(==view)]", options: nil, metrics: nil, views: viewBindingsDict))
self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[previewView]", options: nil, metrics: nil, views: viewBindingsDict))
this example sets the previewView top left with the width of the controllers view.
a nice tutorial: http://www.thinkandbuild.it/learn-to-love-auto-layout-programmatically/
it is recommended to use only one view in a scrollview and use it as container for the others.
if you load a nib and set the owner to self

Swift change class at runtime

So I have 3 views set up in interface builder (XCode 6). They are linked to the ViewController that owns them. Also I have 3 subclasses of UIVIew in my project. At runtime I would need to change the class of one of the views from UIView to my custom view subclass.
How do I do this in swift? (I need all the autolayout set up in IB to work the same after the change).
To achieve what you need you can create a view in IB and later in the code add required view as a subview.
To make added view occupy all container view space you need either update child view's frame or setup auto-layout constraints. Variant with frames needs to be repeated each time container view changes it size. Code bellow:
Auto-Layout Contraints
override func viewDidLoad() {
super.viewDidLoad()
self.myView = UIView(frame: CGRect())
self.myView.setTranslatesAutoresizingMaskIntoConstraints(false)
self.myViewContainer.addSubview(self.myView)
self.myViewContainer.addConstraint(NSLayoutConstraint(item: self.myView, attribute: .Top, relatedBy: .Equal, toItem: self.myViewContainer, attribute: .Top, multiplier: 1.0, constant: 0))
self.myViewContainer.addConstraint(NSLayoutConstraint(item: self.myView, attribute: .Right, relatedBy: .Equal, toItem: self.myViewContainer, attribute: .Right, multiplier: 1.0, constant: 0))
self.myViewContainer.addConstraint(NSLayoutConstraint(item: self.myView, attribute: .Bottom, relatedBy: .Equal, toItem: self.myViewContainer, attribute: .Bottom, multiplier: 1.0, constant: 0))
self.myViewContainer.addConstraint(NSLayoutConstraint(item: self.myView, attribute: .Left, relatedBy: .Equal, toItem: self.myViewContainer, attribute: .Left, multiplier: 1.0, constant: 0))
}
Manual Frame Updates
#IBOutlet var myViewContainer: UIView
var myView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
self.myView = UIView(frame: CGRect())
self.myViewContainer.addSubview(self.myView)
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
self.myView.frame = self.myViewContainer.bounds
}
Frame updates can be done even if container view has auto-layout constraints.

Resources