button position change when screen rotate in tableviewcell - ios

I have to manage my UIButton position at the right side of a UITableViewCell like an image below.
in this cell I gave all my constraints from storyboard except of button..because I created button at runtime like below
In tableview:cellForRowAtIndexPath method
let mybutton = UIButton.buttonWithType(UIButtonType.Custom) as! UIButton
var width:CGFloat = UIScreen.mainScreen().bounds.width
mybutton.frame = CGRectMake(width - 108, 8, 100, 31)
mybutton.tag = indexPath.row
cell?.contentView.addSubview(mybutton)
So the problem is when we launch the app in portrait its ok but when we rotate it, button displays at portrait position...for e.g. if the button position at portrait 220 then in landscape it displays at 220 and after scrolls it looks ok because of cell reusability...
To solve this I'll trying to manually add few constraints to button.I don't know much about how to add constraints programatically but i'll add constraints like below one for top position..and similar with trailing
cell?.contentView.addConstraint(
NSLayoutConstraint(item:imageview ,
attribute: NSLayoutAttribute.Top,
relatedBy: NSLayoutRelation.Equal,
toItem:mybutton ,
attribute:NSLayoutAttribute.Top,
multiplier: 1, constant: 8))
but it displays breaking constraints...
So my questions are...
How to deal with storyboard + manually constraints
How to position button at the right side of a cell

I normally use the Auto-layout Visual Format
//Horizontal constraints
let horizontalConstraints = NSLayoutConstraint.constraintsWithVisualFormat("H:|-20-[button]", options: nil, metrics: metrics, views: views)
self.view.addConstraints(horizontalConstraints)
//Vertical constraints
let verticalConstraints = NSLayoutConstraint.constraintsWithVisualFormat("V:|-20-[button]", options: nil, metrics: metrics, views: views)
self.view.addConstraints(verticalConstraints)
Basically you set V or H for vertical and horizontal fallow by the UI item "|" for the board of the screen, than the -value in pixels- and finally the next [UIComponent]
You can find a nice tutorial here

I have not enough reputation for comment that's why i am answering the question
You can reload Data after orientation changed.
It will solve the problem
override func didRotateFromInterfaceOrientation(fromInterfaceOrientation: UIInterfaceOrientation) {
tableVIew.reloadData()
}

Related

How to create a slide animation inside a view controller?

I'd like to animate a view to slide in and out from the left.
What I did so far:
When the user clicks on the upper left icon, an action (show/hide menu-view) is triggered.
The "menu-view" includes the dark mask view, the semi-transparent white view and all three views (label + image).
Now this menu view shall slide in and out.
I tried to add a constraint to the menu view:
func viewDidLoad() {
super.viewDidLoad()
menuView.translatesAutoresizingMaskIntoConstraints = false
menuViewLeftConstraint = NSLayoutConstraint(item: menuView, attribute: .left, relatedBy: .equal, toItem: view, attribute: .left, multiplier: 1, constant: -1000)
menuViewLeftConstraint.isActive = true
}
and I toggled the constant on every click the user performs (-1000 or 0).
But the animation does not look like I thought it would.
Why do this programmatically with a fixed constant? Set the right of your uiview (trailing) equal to the leading (left) of your superciew (uiviewcontroller). Create an outlet of that constraint and animate it by adding a constant which is equal to the uiview’s width and maybe some offset.
Alternative you can make your subview equal to your superviews width - someoffset, equal height -someoffset, centerX and centerY to the superview and animate the centerX constraint.

Placing UiView as a subview programmatically

I have ViewController that looks like this. There is parent ScrollView that holds UIView (wrapperView) and this wrapper view has TextView and ImageView inside.
This simple structure is created form interface builder with all constraints needed so it works fine.
In some cases I need to programmatically add one more UIView inside my wrapperView right under ImageView (green arrow points there).
So I created xib file for my new UIView and separate class for it
class MyView : UIView {
class func instanceFromNib() -> UIView {
return UINib(nibName: "MyView", bundle: nil).instantiate(withOwner: nil, options: nil)[0] as! UIView
}
}
And I code of my ViewController I added
let myView = MyView.instanceFromNib()
myView = CGRect(x: 0, y: 0, width: 300, height: 80)
wrapperView.addSubview(myView)
now i see myView on the screen in top of wrapperView but when i try to apply constraints like
NSLayoutConstraint(item: myView, attribute: .top, relatedBy: .equal, toItem: myImageView, attribute: .bottom, multiplier: 1.0, constant: 8).isActive = true
I got
Unable to simultaneously satisfy constraints
What am I doing wrong?
First you need to set this:
myView.translatesAutoresizingMaskIntoConstraints = false
And then you have to make sure that there are no your own constraints that are in conflict. In storyboard you have probably added a constraint that binds imageView.bottomAnchor to wrapperView.bottomAnchor. Now if you put between these two anchors another view, you need to deactivate that constraint.
Otherwise if you try to squeeze myView there, it may result in constraint conflicts - imagine there is a constraint saying that
imageView.bottomAnchor should be 10 points from wrapperView.bottomAnchor,
but there are also two more constraints saying that
imageView.bottomAnchor should be 10 points from myView.topAnchor and myView.bottomAnchor should be 10 points from wrapperView.bottomAnchor.
Obviously both these scenarios cannot be satisfied.
I think, that the easiest solution would be add an UIStackView to the wrapperView in the interface builder with no height, just add needed constraints (top, left, bottom, right). Then drag an IBOutlet of the UIStackView to your ViewController and when you will need to add a subview:
#IBOutlet weak var stackView: UIStackView!
func someFunc() {
let myView = MyView.instanceFromNib()
myView = CGRect(x: 0, y: 0, width: 300, height: 80)
stackView.addArrangedSubview(myView)
}
UIStackView will change its size based on its subviews.
You may use the Debug View Hierarchy to debug your UI issues including the constraints which are failing to be satisfied. Most probably your .top constraint which is added at runtime is conflicting with .top constraint which you have set in your storyboard.

Attaching an UIimage behind a UItexView in tableview

I have attached a UItextView in tableview cell. Now I want to insert an UIimage behind it like a chat bubble.But everytime I scroll the tableview , the Uitextview becomes smaller in width and longer in height. The text also gets resized from single to multi line. Also ,the same thing happens when I scroll back to an earlier cell ( for example the first row).
I can't figure out why this is happening.
My code is:
(SampleTableViewCell is my custom UItableViewCell class and lblTitle is my UitextView outlet.)
func tableView(tableView: UITableView, willDisplayCell cell: SampleTableViewCell, forRowAtIndexPath indexPath: NSIndexPath)
{
cell.lblTitle.removeConstraints(cell.lblTitle.constraints)
let stringTitle = carName[indexPath.row] as String //carName is an array
cell.lblTitle.text=stringTitle
cell.lblTitle.sizeToFit()
let h = cell.lblTitle.frame.size.height
let w = cell.lblTitle.frame.size.width
let constraints = NSLayoutConstraint(item: cell.lblTitle, attribute: .Width, relatedBy: .Equal, toItem: cell.lblTitle, attribute: .Height, multiplier: 0, constant: w)
cell.lblTitle.addConstraint(constraints)
let kl = UIImage(imageLiteral: "bubble")
let imageView = UIImageView(frame:CGRectMake(0, 0, w, h))
imageView.image = kl
imageView.alpha = 0.4
cell.lblTitle.addSubview(imageView)
cell.lblTitle.sendSubviewToBack(imageView)
}
It is the problem of autolayout.
You are just giving height and width constraint to textView. what about x and y position?
And you haven't set constraints for your imageview!!
If you are giving constraint to one object then you required to give every object related to it.
So set proper constraints and your problem will be solved.
Instead of adding bubble imageview and constraints programmatically,using storyboard you can add imageview in the tableview cell first and then UITextView of same size as imageview and add constraints.Then you can add your logic at cellForRowAtIndexPath delegate for lblTitle's text and bubble image. Make sure to set lblTitle's background to ClearColor.

How to make a UITextView full width and height of containing UIViewController

I have UITextView that I would like to make the same height and width of it's container. It is in a simple UIViewContainer.
I tried doing the following:
override public func viewDidLoad() {
self.edgesForExtendedLayout = .None
resultText.text = result
resultText.frame = view.frame
}
This seems to work for portrait but not landscape.
All I am trying to do is make the UITextView take up all the space of it's container.
If I could find the answer in Objective-C I could easily translate it to Swift. I am just looking for the answer for iOS.
I suggest you to use auto layout
Then click add 4 constraints.
If any warning,
Click Update Frames
Autolayout is your friend - It can be done easily using Interface Builder, or in code:
override public func viewDidLoad() {
super.viewDidLoad()
self.edgesForExtendedLayout = .None
resultText.text = result
// add vertical constraints to pin the view to the superview edge
self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-0.0-[resultText]-0.0-|", options: nil, metrics: nil, views: ["resultText": resultText]))
// add horizontal constrains to pin the view to the superview edge
self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-0.0-[resultText]-0.0-|", options: nil, metrics: nil, views: ["resultText": resultText]))
}

Controls positioning under the navigation bar issue

I have a question on Auto layout. I'm using xib files and I have a view controller like this.
Its embedded inside a UINavigationController so I have the button positioned with a Top Space to Superview constraint.
The problem is when I rotate the device, it looks like this.
As you can see that constraint still keeps its original value so there's a big gap between the navigation bar edge and the button in landscape mode.
How can I make the button position close to the navigation bar like when its in the portrait and have it that way in both portrait and landscape modes? I'm using Xcode 6 by the way.
Thank you.
If you want to define your auto layout top margin constraints in your Xib file, you can add the following code in the ViewController's class file relative to your Xib:
override func viewDidLoad() {
super.viewDidLoad()
if self.respondsToSelector("edgesForExtendedLayout") {
edgesForExtendedLayout = UIRectEdge.None
}
}
Simple. But the problem there is that you won't be able to have a translucent navigation bar.
Fortunately, there are several alternatives to this. You can define your auto layout top margin as relative to your Top Layout Guide (not to your view) with Storyboard or with code.
If you move to Storyboard, click on the Pin button, select your top margin constraint and choose The Top Layout Guide (see image below).
If you decide to define all your UIButton's constraints with code, you can use Visual Format Language as indicated in the following code:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
var button = UIButton()
button.backgroundColor = UIColor.blueColor()
button.setTranslatesAutoresizingMaskIntoConstraints(false)
view.addSubview(button)
var viewsDict = ["button" : button, "topLayoutGuide" : topLayoutGuide]
view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:[topLayoutGuide]-20-[button]", options: NSLayoutFormatOptions(0), metrics: nil, views: viewsDict))
view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-20-[button]-20-|", options: NSLayoutFormatOptions(0), metrics: nil, views: viewsDict))
}
}
Finally, there is a fourth (kind of mixed) way to perform what you want to do. Set your constraints in your Xib, drag your top margin constraint and your UIButton to your view controller class (name them topConstraint and button) and set your code as the following:
import UIKit
class ViewControllerTwo: UIViewController {
#IBOutlet weak var topConstraint: NSLayoutConstraint!
#IBOutlet weak var button: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
view.addConstraint(NSLayoutConstraint(item: button, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: self.topLayoutGuide, attribute: NSLayoutAttribute.Bottom, multiplier: 1, constant: 10))
view.removeConstraint(topConstraint)
}
}

Resources