something wrong with UIButton setImage - ios

I am attempting to make my own custom Facebook login button. I am close, but for some reason when I setImage on the UIButton it still has a really large frame that is pushing the text to the right and the icon to the right as well.
What am I missing? I tried setting the frame and that did not help.
(The actual image is large, but .scaleAspetFit makes it look perfect, but I think the frame persists?)
let customFacebookButton: UIButton = {
let view = UIButton()
view.setImage(UIImage(named: "fb-logo"), for: .normal)
view.imageEdgeInsets = UIEdgeInsetsMake(8, 8, 8, 4)
view.imageView?.contentMode = .scaleAspectFit
view.backgroundColor = UIColor.init(hex: "3B5998")
view.layer.cornerRadius = 6
let mutableAttributedString = NSMutableAttributedString()
let attributes: [NSAttributedStringKey: Any] = [
NSAttributedStringKey.font : UIFont.systemFont(ofSize: 14),
NSAttributedStringKey.foregroundColor : UIColor.init(hex: "#EFEFEF") ]
let string = NSMutableAttributedString(string: "Continue with Facebook", attributes: attributes)
mutableAttributedString.append(string)
view.setAttributedTitle(mutableAttributedString, for: .normal)
return view
}()

It is because of the size of image. Reduce the size of image. It will work perfectly.
I have tested you code with two image sizes 512*512 and 80*80.
512*512
https://i.stack.imgur.com/zuRWo.png
80*80
https://i.stack.imgur.com/YvID9.png
for left align the image:
view.contentHorizontalAlignment = .left
There is no way to centre the title with left align image. Temporally you can change titleEdgeInsets to do that:
view.titleEdgeInsets = UIEdgeInsetsMake(8, 16, 8, 4)
OR
You can take a imageView to the left of button. And remove the image as part of button. then centre align the contentHorizontalAlignment.
Code:
let customFacebookButton: UIButton = {
let view = UIButton()
// view.setImage(UIImage(named: "logo"), for: .normal)
// view.imageEdgeInsets = UIEdgeInsetsMake(8, 8, 8, 4)
view.backgroundColor = UIColor.blue
view.layer.cornerRadius = 6
view.contentHorizontalAlignment = .center
let mutableAttributedString = NSMutableAttributedString()
let attributes: [NSAttributedStringKey: Any] = [
NSAttributedStringKey.font : UIFont.systemFont(ofSize: 14),
NSAttributedStringKey.foregroundColor : UIColor.white ]
let string = NSMutableAttributedString(string: "Continue with Facebook", attributes: attributes)
mutableAttributedString.append(string)
view.setAttributedTitle(mutableAttributedString, for: .normal)
return view
}()
customFacebookButton.frame = CGRect.init(x: 10, y: 20, width: 300, height: 40)
self.view.addSubview(customFacebookButton)
let imageView = UIImageView.init(frame: CGRect.init(x: 12, y: 22, width: 38, height: 38))
imageView.image = #imageLiteral(resourceName: "logo")
self.view.addSubview(imageView)
Output:

Related

Round UIBarButtonItems in Swift

I am trying to make round (sort of notification counter which you see on most of the apps) UIBarButtonItem in Swift. I know how to do it but the thing is it is actually being round only when I am setting the width as 34 and height as 24. Are these magic numbers for UIBarButtonItems ? If I set the width or height (same , my desired frame is 30 x 30) for something else and calculate the cornerRadius based on the width then it is not perfect circle rather rounded rectangle. What is I am doing wrong ? My code is below :
let button = UIButton(type: .custom)
button.frame = CGRect(x: 0, y: 0, width: 34, height: 24)
button.backgroundColor = DarkModeUtil.isDarkMode() ? UIColor.white : UIColor.black
button.setTitle("\(self.pickedAppActions.count > 9 ? "9+" : "\(self.pickedAppActions.count)")", for: .normal)
button.setTitleColor(DarkModeUtil.isDarkMode() ? .black : UIColor.white, for: .normal)
button.contentHorizontalAlignment = .center
button.titleLabel?.fitSize()
button.layer.cornerRadius = button.bounds.size.width / 2
button.clipsToBounds = true
button.addTarget(self, action: #selector(counterTapped(_:)), for: [.touchUpInside])
let doneItem = UIBarButtonItem(image: UIImage(named: "done")?.withRenderingMode(.alwaysTemplate), style: .plain, target: self, action: #selector(doneButtonClicked(_:)))
doneItem.tintColor = DarkModeUtil.isDarkMode() ? .white : .black
let counterButton = UIBarButtonItem(customView: button)
let buttons:[UIBarButtonItem] = [doneItem,counterButton]
self.navigationItem.rightBarButtonItems = buttons
If I set same width and height for example 30 x 30 I get button like this:
make height and width 34 work for me. here is a code. also no need to change button.frame.size.width / 2.
let button = UIButton(type: .custom)
button.frame = CGRect(x: 0, y: 0, width: 34, height: 34)
button.backgroundColor = DarkModeUtil.isDarkMode() ? UIColor.white : UIColor.black
button.setTitle("\(self.pickedAppActions.count > 9 ? "9+" : "\(self.pickedAppActions.count)")", for: .normal)
button.setTitleColor(DarkModeUtil.isDarkMode() ? .black : UIColor.white, for: .normal)
button.contentHorizontalAlignment = .center
button.titleLabel?.fitSize()
button.layer.cornerRadius = button.bounds.size.width / 2
button.clipsToBounds = true
button.addTarget(self, action: #selector(counterTapped(_:)), for: [.touchUpInside])
let doneItem = UIBarButtonItem(image: UIImage(named: "done")?.withRenderingMode(.alwaysTemplate), style: .plain, target: self, action: #selector(doneButtonClicked(_:)))
doneItem.tintColor = DarkModeUtil.isDarkMode() ? .white : .black
let counterButton = UIBarButtonItem(customView: button)
let buttons:[UIBarButtonItem] = [doneItem,counterButton]
self.navigationItem.rightBarButtonItems = buttons
You can set corner radius of the Button using
button.frame = CGRect(x: 0, y: 0, width: 84, height: 40)
button.layer.cornerRadius = button.bounds.size.height / 2
Note: Button Maximum height: 44 and Minimum height: 34 in UINavigationBar as checked from view hierarchy.
Please try with this code :
For Round button you need to make height and width same value :
let button = UIButton(type: .custom)
button.frame = CGRect(x: 0, y: 0, width: 30, height: 30)
button.backgroundColor = UIColor.black
button.setTitle("999", for: .normal)
button.titleLabel?.font = UIFont.systemFont(ofSize: 12.0)
button.titleLabel?.minimumScaleFactor = 0.5
button.titleLabel?.numberOfLines = 0
button.titleLabel?.adjustsFontSizeToFitWidth = true
button.layer.cornerRadius = button.frame.size.height/2
button.clipsToBounds = true
let counterButton = UIBarButtonItem(customView: button)
let buttons:[UIBarButtonItem] = [counterButton]
self.navigationItem.rightBarButtonItems = buttons

imageView in iOS 11 using Swift

I created 2 customs buttons in my navigation Controller. I have one left button and one right, and both have some text + an arrow icon. Since I updated to iOS 11, the size of icons has changed and I don't know why.
This this the difference between iOS 10 (Left) and iOS 11 (right):
How can I change that?
This is a piece of my code:
func addRightButton(){
rightButton = UIButton.init(type: .custom)
rightButton.setImage(UIImage(named: "back"), for: .normal)
rightButton.imageView?.contentMode = .scaleAspectFit
let width = UIScreen.main.bounds.size.width
if width < 375 {
rightButton.titleLabel?.font = UIFont.systemFont(ofSize: 13, weight: UIFont.Weight.bold)
rightButton.frame = CGRect.init(x: 0, y: 0, width: 75, height: 10)
} else {
rightButton.titleLabel?.font = UIFont.systemFont(ofSize: 15, weight: UIFont.Weight.bold)
rightButton.frame = CGRect.init(x: 0, y: 0, width: 100, height: 10)
}
rightButton.imageView!.transform = rightButton.imageView!.transform.rotated(by: CGFloat((Double.pi / 2) * -1))
rightButton.setTitle(" Mixte",for: .normal)
rightButton.addTarget(self, action: #selector(self.switchSex(_:)), for: UIControlEvents.touchUpInside)
let barButton = UIBarButtonItem(customView: rightButton)
self.navigationItem.rightBarButtonItem = barButton
}
You need to add width constraint for your button in xCode 9. Like this:
let width = yourButton.widthAnchor.constraint(equalToConstant: 75)
let height = yourButton.heightAnchor.constraint(equalToConstant: 10)
heightConstraint.isActive = true
widthConstraint.isActive = true

Get rid of subview if collection view is empty

I have a collection view when I display a message to the user if the collection view is empty. I also programmatically add a button to let the user add a photo if the collection view is empty. However, once the photo is added and the I reload the collection view, I found a way to get rid of the label, however, how can I get rid of the button's subview? since I can't access "self.collectionViews?.addSubview(button)" since it is in a guard let statement. Thanks in advance!
guard let parseUSERS = parseJSON["users"] as? [AnyObject] else {
// if the collection view is empty, display a message
let messageLabel = UILabel(frame: CGRect(x: 20.0, y: 10, width: self.collectionViews!.bounds.size.width - 40.0, height: (self.collectionViews?.bounds.size.height)!))
messageLabel.text = "Collection view is empty!"
messageLabel.font = messageLabel.font.withSize(20)
messageLabel.font = UIFont.boldSystemFont(ofSize: messageLabel.font.pointSize)
messageLabel.textColor = UIColor.white
messageLabel.numberOfLines = 0
messageLabel.textAlignment = NSTextAlignment.center
messageLabel.sizeToFit()
let button = UIButton(frame: CGRect(x: 80.0, y: 320, width: 215, height: 50))
button.backgroundColor = UIColor.white
button.setTitle("create",for: .normal)
button.setTitleColor(colorCircleBlue, for: .normal)
button.addTarget(self, action: #selector(self.action(sender:)), for: .touchUpInside)
// round corners for login/register buttons
button.layer.cornerRadius = button.bounds.width / 20
self.collectionViews?.backgroundColor = UIColor.blue
self.collectionViews?.backgroundView = messageLabel
self.collectionViews?.addSubview(button)
return
}
self.collectionViews?.backgroundColor = UIColor.white
self.collectionViews?.backgroundView = nil
I would recommend making a UIView that contains both your UILabel and the UIButton. Then setting the aforementioned UIView as the backgroundView of the UICollectionView. Ensure userInteraction is enabled on the backgroundView.
This will make sure that the both the UILabel & the UIButton are removed when you set the backgroundView to nil.
Something like this should do the trick (Be aware I have not tested this):
//Container view
let view = UIView.init(frame: self.collectionViews?.frame)
//Label
let messageLabel = UILabel(frame: CGRect(x: 20.0, y: 10, width: self.collectionViews!.bounds.size.width - 40.0, height: (self.collectionViews?.bounds.size.height)!))
messageLabel.text = "Collection view is empty!"
messageLabel.font = messageLabel.font.withSize(20)
messageLabel.font = UIFont.boldSystemFont(ofSize: messageLabel.font.pointSize)
messageLabel.textColor = UIColor.white
messageLabel.numberOfLines = 0
messageLabel.textAlignment = NSTextAlignment.center
messageLabel.sizeToFit()
//Button
let button = UIButton(frame: CGRect(x: 80.0, y: 320, width: 215, height: 50))
button.backgroundColor = UIColor.white
button.setTitle("create",for: .normal)
button.setTitleColor(colorCircleBlue, for: .normal)
button.addTarget(self, action: #selector(self.action(sender:)), for: .touchUpInside)
// round corners for login/register buttons
button.layer.cornerRadius = button.bounds.width / 20
//Add elements to container view
view.addSubview(messageLabel)
view.addSubview(button)
self.collectionViews?.backgroundView = view
Then in the future when you want to remove both elements you can just set the backgroundView to nil.

Text Shadow - iOS, swift 3.0

I'm trying to make shadow size a bit bigger but I can't do it.
so far:
findAPlace.titleLabel?.layer.shadowOffset = CGSize(width: -1, height: 1)
findAPlace.titleLabel?.layer.shouldRasterize = true
findAPlace.titleLabel?.layer.shadowRadius = 1
findAPlace.titleLabel?.layer.shadowOpacity = 1
findAPlace.titleLabel?.layer.shadowColor = UIColor(red:0.07, green:0.07, blue:0.07, alpha:1.0).cgColor
how to scale shadow to be bigger than the text itself?
something like this.
Maybe with a border can be done, My text is the title of a UIButton!!!I expect it to be all around text of the uiButton
You can do in this way
Actually You need to use setTitleShadowColor instead of titleLabel?.layer.shadowColor
Here is full working code
let btnTemp = UIButton(type: .custom)
btnTemp.frame = CGRect(x: 50, y: 200, width: 150, height: 40)
btnTemp.setTitle("Hello", for: .normal)
btnTemp.titleLabel?.layer.shouldRasterize = true
btnTemp.titleLabel?.layer.shadowRadius = 1.0
btnTemp.titleLabel?.layer.shadowOpacity = 1.0
btnTemp.setTitleColor(UIColor.blue, for: .normal)
btnTemp.backgroundColor = UIColor.gray
btnTemp.titleLabel?.shadowOffset = CGSize(width: -1, height: 1)
btnTemp.setTitleShadowColor(UIColor(red:0.07, green:0.07, blue:0.07, alpha:1.0), for: .normal)
self.view.addSubview(btnTemp)
Hope it helps
Output:
You can follow this way to achieve the outlined text.
You have to use attributed string and use setAttributedTitle property of button to get required result.
Here is the code:
Swift 4
let strokeTextAttributes: [NSAttributedStringKey : Any] = [
NSAttributedStringKey.strokeColor : UIColor.red,
NSAttributedStringKey.foregroundColor : UIColor.gray,
NSAttributedStringKey.strokeWidth : -2.0,
]
let attributedString = NSAttributedString(string: "text", attributes: strokeTextAttributes)
self.btnTemp.setAttributedTitle(attributedString, for: .normal)
Swift 3
let strokeTextAttributes = [
NSStrokeColorAttributeName : UIColor.red,
NSForegroundColorAttributeName : UIColor.gray,
NSStrokeWidthAttributeName : -2.0,
] as [String : Any]
let attributedString = NSAttributedString(string: "text", attributes: strokeTextAttributes)
self.btnTemp.setAttributedTitle(attributedString, for: .normal)
Output:

Multiline Navigationbar Title

I am trying to set the title label in my navigation bar to allow multiple lines. I have custom navigation controller code that I am placing the multiline code into. I know that the code already there works, but my multiline part is not working.
let titleLabel = UILabel()
titleLabel.frame = CGRectMake(0, 0, self.navigationBar.frame.width, self.navigationBar.frame.height * 2)
titleLabel.numberOfLines = 0
titleLabel.lineBreakMode = .ByWordWrapping
navigationItem.titleView = titleLabel
But the text still runs off at the end. I've also tried putting this into the individual view controller itself, adding self.navigationController?. in front of navigationItem with the same results.
Is there something I'm missing in my code that would keep the title label from using multiple lines?
Here is a code example of how you can create a multiline navigationBar title
let label: UILabel = UILabel(frame: CGRectMake(0, 0, 400, 50))
label.backgroundColor = UIColor.clearColor()
label.numberOfLines = 2
label.font = UIFont.boldSystemFontOfSize(16.0)
label.textAlignment = .Center
label.textColor = UIColor.whiteColor()
label.text = "This is a\nmultiline string for the navBar"
self.navigationItem.titleView = label
Swift 5.x:
let label = UILabel()
label.backgroundColor = .clear
label.numberOfLines = 2
label.font = UIFont.boldSystemFont(ofSize: 16.0)
label.textAlignment = .center
label.textColor = .white
label.text = "This is a\nmultiline string for the navBar"
self.navigationItem.titleView = label
This is doable in a storyboard. Just drag a UIView into the Navigation bar, then drag a UILabel onto it in the document outline, set lines to 2 and alignment to center.
Use this to get the label position exactly as you want it:
let labelWidth = navBar.bounds.width - 110
let label = UILabel(frame: CGRect(x:(navBar.bounds.width/2) - (labelWidth/2), y:0, width:labelWidth, height:navBar.bounds.height))
label.backgroundColor = UIColor.clear
label.numberOfLines = 0
label.font = UIFont.boldSystemFont(ofSize: 13.0)
label.textAlignment = .center
label.textColor = UIColor.black
label.lineBreakMode = .byWordWrapping
label.text = loadedName
navBar.topItem?.title = nil
navBar.addSubview(label)
the 110 value in the top line is the spacing you want either side of the label.
swift 5+ very easy solution
func titleMultiLine(topText: String, bottomText: String) {
// let titleParameters = [NSForegroundColorAttributeName : UIColor.white,
// NSFontAttributeName : UIFont.<Font>]
// let subtitleParameters = [NSForegroundColorAttributeName : UIColor.<Color>(),
// NSFontAttributeName : UIFont.<Font>]
let titleParameters = [NSAttributedString.Key.foregroundColor : UIColor.white]
let subtitleParameters = [NSAttributedString.Key.foregroundColor : UIColor.white]
let title:NSMutableAttributedString = NSMutableAttributedString(string: topText, attributes: titleParameters)
let subtitle:NSAttributedString = NSAttributedString(string: bottomText, attributes: subtitleParameters)
title.append(NSAttributedString(string: "\n"))
title.append(subtitle)
let size = title.size()
let titleLabel = UILabel(frame: CGRect(x: 0, y: 0, width: size.width, height: size.height))
titleLabel.attributedText = title
titleLabel.numberOfLines = 0
titleLabel.textAlignment = .center
navigationItem.titleView = titleLabel
}
Function Calling
self.titleMultiLine(topText: "I am top text Title", bottomText: "bottom text")

Resources