Autolayout removes UIBezierPath - ios

I am trying to add shadow around a uiview, trying to use this code https://github.com/benboecker/ShadowView/blob/master/ShadowView/ShadowView.swift
View is added in storyboard and not managing properties programmatically
It works perfectly when frame is same as in storyboard and NO autolayout is applied.
the moment I add any constraint that moves the frame with autolayouts, looks like self.layer.shadowPath is removed and calling layoutSubviews() or setNeedsLayout() or layoutIfNeeded() doesnt help at all.
Add an autolayout constraint
Final version doesnt have the shadow anymore because uiview frame is changed.
I tried calling layout after viewdidappear too, didnt help .
#IBOutlet weak var shadowView: ShadowView!
override func viewDidAppear(_ animated: Bool) {
self.shadowView.layoutIfNeeded()
}
Any idea what is going on?

Related

Make a UIView relayout itself when dependent constraint changes

I have a UIImageView and UIButton, UIButton is aligned to top of UIImageView. Now in code I am changing the top of UIImageView but the UIButton is not updated accordingly. I tried SetNeedsLayout, LayoutIfNeeded on UIButton but nothing works.
override func viewDidLayoutSubviews() {
profileImageView.frame.origin.y = arcView.bounds.height/1.8
editProfileButton.layer.setNeedsDisplay()
}
I have set the constraints in Storyboard. I would really appreciate any help here.
First: Are you sure that all your constraints (for both the UIImageview and UIButton) are added right?
Second: when working the constraints, you should change the origin.y of the UIImageview also by by a constraint, by modifying its constant's value:
Instead of directly changing profileImageView.frame.origin.y, you should change the constant of the constraint that tells what's the imageview origin.y (if the first point is applied, this constraint must be exist...); Add this constraint to the viewController as an IBOutlet and change value of its constant property (take a look at the comments in the code snippet, it's a part of the answer):
class ViewController: UIViewController {
// let's assume that this is the #IBOutlet of the constraint, I called it 'imageViewTopMargin':
#IBOutlet weak var imageViewTopMargin: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
// it's not necessary -for sure- to do this the in the viewDidLoad method
// but I'm doing this for demo purposes:
// let's say that you want to push the imageView to the bottom with extra 40 points:
imageViewTopMargin.constant += 40
}
}
Hope this helped.

Swift / cornerRadius and masksToBounds lets UIImageView disappear

I have a UITableViewController with a UIImageView. The content is loaded with the following simple code.
#IBOutlet weak var avatarImageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
updateUI()
}
func updateUI() {
backendless.userService.currentUser.retrieveProperties()
avatarImageView.layer.cornerRadius = avatarImageView.frame.size.width/2
avatarImageView.layer.masksToBounds = true
let imgURL = NSURL(string: (backendless.userService.currentUser.getProperty("Avatar") as? String)!)
avatarImageView.sd_setImageWithURL(imgURL)
tableView.reloadData()
}
The ImageView does not appear.
But if I delete the following code, the UIImageView will be set and displayed correctly.
avatarImageView.layer.cornerRadius = avatarImageView.frame.size.width/2
avatarImageView.layer.masksToBounds = true
What am I missing? Help is very appreciated.:
PS:
Xcode 8.0
Swift 2.3
Contrains for ImageView are set to 120*120
sd_setImageWithURL = pod 'SDWebImage'
Try this:
override func viewDidLoad() {
super.viewDidLoad()
self.view.layoutIfNeeded() // <- This will update your initial view frames
updateUI()
}
What is happening is that in Xcode 8.0, by the time you hit viewDidLoad, the frame of all subviews of a controller is still x: 0.0, y: 0.0, w: 1000.0, h: 1000.0, so in effect you're making the corner radius of your avatar image view 500.0pt. When you call layout if needed, the correct frames will be calculated, and give you the value you're expecting.
One obvious problem is that you are calling updateUI too soon. In viewDidLoad, there is no UI. The view has loaded but that is all; it is not in the interface and no layout has yet taken place. Your code depends upon avatarImageView.frame, but we do not yet know what that is. You have constraints on the image view, but they have not yet taken effect! Thus you should postpone this call until after the interface is present, e.g. viewDidAppear or at least viewDidLayoutSubviews. But of course then you probably only want to call it once (typed in browser, not tested, but it will be something like this):
var didConfigureUI = false
func viewDidLayoutSubviews() {
if !didConfigureUI {
didConfigureUI = true
updateUI()
}
}
I think your problem with your controller. You have added the image view to a UITableViewController. That means constraint set to image view will not work if you use the frame in view did load. You need to change frame of the UIIMageView before use it or you need to use UIViewController. use the below code before using the frame of image view.
avatarImageView.frame.size.width = 120.0
avatarImageView.frame.size.height = 120.0
I think this will solve the problem. But you should use UIViewController if there is no special purpose of UITableViewController.
“xy.view.layoutIfNeeded()”
needs to be called everytime i’m calling a property before the view has finished loading
for example imageView.view.layoutIfNeeded() to call for the height and widths values

UIView from CGRectMake does not have the right height

I am adding a UIView to a container view programmatically, (the container view however is created in storyboard). Here is the code:
class ViewController: UIViewController{
#IBOutlet weak var dwView: UIView!
private var dwSelector = dwSelectorView()
override func viewDidLoad(){
super.viewDidLoad()
addDWSelector()
}
func addDWSelector(){
dwSelector.setTranslatesAutoresizingMaskIntoConstraints(false)
dwSelector.frame = CGRectMake(self.dwView.bounds.origin.x, self.dwView.bounds.origin.y, self.dwView.bounds.width / 2.0, self.dwView.frame.height)
println("dw height: \(self.dwView.frame.height)")
//prints 568, way too large of a value
self.dwView.addSubview(dwSelector)
}
}
The heigh of dwView is 123 in storyboard but the print state printed 568 and so now this is what it looks like:
You should always not rely on -(void)viewDidLoad since view bounds is incorrect at this point or - (void)viewWillAppear if you are using auto layout to set your view's frame. If you layout view in UIViewController, viewDidLayoutSubviews() is a appropriate place, if you layout subviews in UIView, it is layoutSubviews().
Check this article to get more details:Where to progmatically lay out views in iOS 5 (and handling orientation changes)
have you tried to call addDWSelector() in viewWillAppear()?

"inflating" xib programmatically in swift using Auto-Layout

I've asked a simular question before with no working result yet, but it might have too much "stuff" which is irrelevant to the exact issue I'm experiancing:
I used to be an Android-only developer in my current position and did not do any iOS apps before this so I might be troubling myself with the wrong stuff.
I want to load an view from xib which has a parent class I'd love to be able to do something like this (e.g. in UIViewController):
override func viewDidLoad() {
let view = MyView()
view.unlimitedLabel.text = "bla bla unlimited character string"
self.view.addSubView(view)
}
The MyView would be like this (I'm omitting what I added just to keep it clean):
import UIKit
class MyView : UIView {
#IBOutlet var view: UIView!
#IBOutlet weak var deadlineLabel: UILabel!
}
So what init's are recommended, what should I apply to the view to make it respect the autoLayout? I understand it will be hard to do the AutoLayout when the view doesn't know it's parent and such.
for now I'm usually overriding all init's and call a private func like
private func setup() {
NSBundle.mainBundle().loadNibNamed("MyView", owner: self, options: nil)
view.setTranslatesAutoresizingMaskIntoConstraints(false)
addSubview(view)
}
This barely ever works as expected, I have it working for height sometimes, but then the width is not being respected it just takes the xib's width. In general the view will have the xib's in UIBuilder size.
The xib is set correctly it's working fine for tableViewCell's right now. And the "MyView" class is set to the xib's file owner, outlets linked.
Note: I'm on iOS7 using Swift

Container View Not Moving Off Screen

I have a container view that I want to initially be off the bottom of the screen. It should be easy, but I seem to be missing something fundamental. I have previously done something similar by moving controls off the left side of the screen with:
control.center.x -= view.bounds.width
I have a very simple storyboard setup:
And my view controller looks like this:
class ViewController: UIViewController {
#IBOutlet var containerView: UIView!
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
containerView.center.y += view.bounds.height
}
}
When run, the container view is right where it shows in the storyboard and is not offscreen. Even setting the containerView's center.y to a specific value such as containerView.center.y = 50 will do nothing. The only way I can get it to show off screen is by adding animation in the viewDidAppear:
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
UIView.animateWithDuration(0, animations: {self.containerView.center.y += self.view.bounds.height})
}
But that just seems like a workaround and not the proper way to do it. I have been dealing with this for hours, reading blogs, reading other Stackoverflow questions, but I cannot find the solution. I do not have constraints on the container, although I did test it with constraints and that did not make a difference. Any help is appreciated.
It is possible that the main view's `layoutSubviews is called after you reposition the container view, so it will default to the position specified in the storyboard.
The proper way to do is to have proper layout constraints in storyboard, make an outlet for the bottom edge constraint and set this constraint's constant property.

Resources