Adding sublayer to UITextField without storyboard doesnt style the textfields - ios

I have decided to learn to use Swift without storyboards. Before making the switch, I had a function in a file called Utilities.swift that has a function to style the text fields, which worked fine when I had a storyboard.
class Utilities {
static func styleTextField(_ textfield:UITextField) {
let bottomLine = CALayer()
bottomLine.frame = CGRect(x: 0, y: textfield.frame.height - 2, width: textfield.frame.width, height: 2)
bottomLine.backgroundColor = UIColor.init(red: 48/255, green: 173/255, blue: 99/255, alpha: 1).cgColor
textfield.borderStyle = .none
textfield.layer.addSublayer(bottomLine)
}
}
Then in my view controller, I have let firstName = UITextField() and then a function for Utilities.styleTextField(firstName), which when I had storyboards, worked fine. After removing storyboards and adding constraints programmatically, I can see the text field but it is default without styling.

My guess is that, at this point, you didn't set the text field's frame yet, so the CALayer is not being drawn because its size is (width: 0, height: 0).
When you get the component from IB, it comes with a frame, which is the one you set in the tool.
Try setting the frame before calling the function.

Related

How to add shadow to UICollectionViewCell with clear background color?

I am populating the collection view cells. But only for a single cell, I want a different background color with shadow to the cell. So far I am able to give background color but can't find any idea, how to give shadow. Any suggestions...
cell.backgroundColor = UIColor.init(alpha: 1, red: 255, green: 221, blue: 126)
let view = UIView()
view.frame = CGRect(x: 20, y: cell.frame.origin.y + 62, width: cell.frame.size.width, height: 50)
view.layer.shadowColor = UIColor.black.cgColor
view.layer.shadowOffset = CGSize(width: 3, height: 3)
view.layer.shadowOpacity = 0.9
view.backgroundColor = UIColor.clear
self.addSubview(view)
return cell
This is what I did
This is what I want
I can give you a way of doing it.
Give your cell a clear color
Add a child view in it make sure to give proper constrains (make sure to keep the child view inside the cell).
Add all labels or any other views inside the new child view
Give shadows and background color to the child view.
(make sure to toggle the color when needed just as selected color)
I am sure this will definitely look the image you have sown

Height of Navigation Bar in swift 4

In swift 3, I was able to change the height of a custom navigation bar using constraints and simply setting the height. Now I cannot do that anymore. It doesn't actually change the height of the navigation bar in the storyboard. Even when I go to the size inspector, the height field is gray and I am not able to change it. What is the best practice if I am presenting a view modally and want to display a navigation bar? It doesn't display automatically since it is a modally segue.
I had a similar issue, so i started to research and i found a solution that works for me... I'm gonna show how i did it, but i have to say that i don't use storyboards, so it is all in code...
1) You have to create a class of type "UIView", and then put this code in it:
class ExtendedNavBarView: UIView {
override func willMove(toWindow newWindow: UIWindow?) {
super.willMove(toWindow: newWindow)
layer.shadowOffset = CGSize(width: 0, height: CGFloat(1) / UIScreen.main.scale)
layer.shadowRadius = 0
layer.shadowColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1).cgColor
layer.shadowOpacity = 0.25
}
2) Then, go to the class where you have your navigationController. In the viewDidLoad method, put this code:
navBar.shadowImage = #imageLiteral(resourceName: "TransparentPixel")
let extendedBar = ExtendedNavBarView()
extendedBar.frame = CGRect(x: 0, y: 0, width: view.bounds.width, height: 82) //The height value is gonna determinate the total height of the navbar
view.addSubview(extendedBar)
extendedBar.backgroundColor = UIColor(red: 249/255, green: 249/255, blue: 249/255, alpha: 1.0)
Basically is an extension view for the navigationBar, depending of the value you put in the height, the total navbar is gonna be more or less taller.
If you want to learn more about it, you can go here:
Custom NavigationBar
Also, the "TransparentPixel" image is in the page, you just have to download the sample project.

How to clear elements created programmatically from UITableViewCell before it's reuse

I am writing an application in Swift 3 that involves a UITableView. I am creating my table view cells pragmatically. The problem I am experiencing is that the cell's label text is persistent after the .reloadData() function. Is there a function to clear all elements and formatting from a cell before it's use? I am instantiating the UILabel via code and cannot access it across iterations. Unfortunately, I have already put a ton of time into programmatically creating the table, so I'd like to avoid going back and making a cell class if possible.
I am planning to use a function something like this:
var label: UILabel
if reloadCount > 0 {
//clear all formatting from the cell
}
label = UILabel(frame: CGRect(x: 30, y: 0, width: self.screenWidth - 100, height: 50))
label.textAlignment = .center
label.lineBreakMode = NSLineBreakMode.byWordWrapping
label.textColor = UIColor(red: 127.0/255, green: 140.0/255, blue: 142.0/255, alpha: 1.0)
label.font = UIFont(name: "Tahoma", size: CGFloat(22))
label.numberOfLines = 0
label.tag = Int(self.thoughtFeed[indexPath.row].dbId!)!
label.text = thoughtFeed[indexPath.row].thoughtText!.fromBase64()
label.isUserInteractionEnabled = true
label.addGestureRecognizer(labelTap)
cell.addSubview(label)
Thank you very much for the help.
You'll need to somehow "remember" the UILabel and either reuse it or remove it. Since you say you don't want to subclass UITableViewCell you can use tags to get a reference to your label. In your cellForRowAtIndexPath do something like this:
if let label = cell.viewWithTag(42) as? UILabel {
// now you have a reference to the existing label.
// Just update the text (or whatever you need to do)
} else {
label = UILabel(frame: CGRect(x: 30, y: 0, width: self.screenWidth - 100, height: 50))
// add a tag so we can remember it when we dequeue a cell later
label.tag = 42
cell.addSubview(label)
}

Programmatically changing button shadows is working for all but the first row, yet the first row's background is indeed changing?

I have 4 stackViews, each containing a set of buttons for a custom keyboard. I have a function that edits their appearance. I have added a shadow offset:
btn.layer.shadowRadius = 0.5
btn.layer.shadowOpacity = 0.5
btn.layer.shadowOffset = CGSize(width: 0.5, height: 0.5)
I'm setting the button background's to white, and changing the font color. it works for ALL of them. However, the shadow/opacity is only working for the last 3 rows... but I tried changing the "Q" to "F" to make sure that that btn is being iterated over, which it definitely is as you can see in the picture:
here's the full function:
func setButtonUI (containerView: UIStackView) {
for view in containerView.subviews {
if let btn = view as? UIButton {
btn.layer.cornerRadius = 10
btn.setTitleColor(UIColor(red: 0.0/255.0, green: 51.0/255.0, blue: 102.0/255.0, alpha: 1.0), for: .normal)
btn.layer.backgroundColor = UIColor.white.cgColor
//shadows (working for all but first row)
btn.layer.shadowRadius = 0.5
btn.layer.shadowOpacity = 0.5
btn.layer.shadowOffset = CGSize(width: 0.5, height: 0.5)
if btn.currentTitle == "Q" {
btn.setTitle("F", for: .normal)
}
}
}
}
any ideas as to why the first row is not getting the shadow effects?

UIStackView not appearing in Container View

Can someone please explain to me why I cannot see this StackView show up in its container?
This is what it looks like now:
This is what I want it to look like, ignore the cells, I just need to figure out why the Edit button, search bar and Sort button are not showing.
Here is the code I used to setup the views and their contents:
// Container
let barViewFrame = CGRectMake(0, 0, view.frame.width, 44)
let barViewContainer = UIView(frame: barViewFrame)
barViewContainer.backgroundColor = UIColor(red: 231/255, green: 231/255, blue: 231/255, alpha: 1.0)
tableView.tableHeaderView = barViewContainer
// Edit Button
let editButton = UIButton(type: .System)
editButton.bounds = CGRectMake(0, 0, 44, 44)
editButton.setTitle("Edit", forState: .Normal)
// Search Bar
let searchBar = UISearchBar(frame: CGRect(x: 0, y: 0, width: 50, height: 44))
searchBar.placeholder = "Search"
searchBar.searchBarStyle = .Prominent
searchBar.barTintColor = UIColor(red: 231/255, green: 231/255, blue: 231/255, alpha: 1.0)
// Sort Button
let sortButtton = UIButton(type: .Custom)
sortButtton.bounds = CGRectMake(0, 0, 44, 44)
sortButtton.setImage(UIImage(named: "Sort"), forState: .Normal)
// Stackview
let stackViewH = UIStackView(arrangedSubviews: [editButton, searchBar, sortButtton])
stackViewH.axis = .Horizontal
stackViewH.alignment = .Center
stackViewH.spacing = 8
barViewContainer.addSubview(stackViewH)
barViewContainer.addConstraints([
stackViewH.leftAnchor.constraintEqualToAnchor(barViewContainer.leftAnchor),
stackViewH.topAnchor.constraintEqualToAnchor(barViewContainer.topAnchor),
stackViewH.rightAnchor.constraintEqualToAnchor(barViewContainer.rightAnchor),
stackViewH.bottomAnchor.constraintEqualToAnchor(barViewContainer.bottomAnchor)])
When you add views programmatically, iOS assumes that you want to layout those views using frames. To make this work with auto layout, behinds the scenes it adds constraints so the view will appear according to its frame. But, you are adding constraints that you want the auto layout engine to use rather than the ones it would like to create. So to tell auto layout not to generate those constraints you can set the translatesAutoresizingMaskIntoConstraints to false for the views on which you don't want this to occur.
In your case:
stackViewH.translatesAutoresizingMaskIntoConstraints = false

Resources