How to change the size AND the color of an SF Symbol ? (UIKit) - uikit

I'm trying to add an SF Symbol to a Button.
And I've found that I can change it's pointSize, weight and scale OR it's tint.
But I don't know how to implement both kind of customization.
self.Button = makeToolBarButton(buttonTitle: "plus", buttonFont: NSFont.systemFont(ofSize: buttonSize), image: NSImage(named: "plus.circle.filled")?.withSymbolConfiguration(.init(pointSize: 15, weight: .bold, scale:.large)), { button in
button.params["actionType"] = ButtonType.image
}

This combines both point size and color in one expression:
let button = UIButton()
button.setImage(UIImage(systemName: "plus.circle.filled", withConfiguration: UIImage.SymbolConfiguration(pointSize: 15.0))?.withTintColor(UIColor.red), for: .normal)

Related

What can cause UIStackView subviews to collapse?

I'm programmatically building a vertical UIStackView to show 3 short UILabel's:
import UIKit
import PlaygroundSupport
let box = UIView(frame: CGRect(origin: CGPoint(x:0, y:0), size: CGSize(width: 100, height: 100)))
box.backgroundColor = .white
let labels: [UILabel] = (1...3).map{ index in
let label = UILabel()
label.text = "item \(index)"
return label
}
let sv = UIStackView(arrangedSubviews: labels)
sv.axis = .vertical
sv.alignment = .center
sv.translatesAutoresizingMaskIntoConstraints = false
box.addSubview(sv)
sv.centerXAnchor.constraint(equalTo: box.centerXAnchor).isActive = true
sv.centerYAnchor.constraint(equalTo: box.centerYAnchor).isActive = true
// performing this font change on a single item collapses the stack view
if let label = sv.subviews[1] as? UILabel {
label.font = UIFont.italicSystemFont(ofSize: UIFont.labelFontSize)
}
PlaygroundPage.current.liveView = box
Performing font change of a single label from the stack view as shown above makes the labels collapse onto each other turning into unreadable blob of letters:
Instead of
I get
Am I missing some basic required constraint?
I should mention I'm using Xcode 10.2.1 Playground to develop this view.

Top part of a tableView specific color even if refreshing

I've run into a simple problem, that I can not solve even after looking everywhere..
I made a grey table view, and at the top I have a cell with white background.
Is it possible to whenever the user refreshes, make it also white (on the top)?
Try this code
let refresh = UIRefreshControl()
let backgroundColor = UIColor.red
refresh.backgroundColor = backgroundColor
refresh.addTarget(self, action: #selector(self.refreshs), for: .valueChanged)
tableView.addSubview(refresh)
var frame = tableView.bounds
frame.origin.y = -frame.size.height
let backgroundView = UIView(frame: frame)
backgroundView.autoresizingMask = .flexibleWidth
backgroundView.backgroundColor = backgroundColor // background color pull to refresh
tableView.insertSubview(backgroundView, at: 0)

ConvertPointToView Function not working in Swift Xcode 7 Beta

So I reverently updated to Xcode 7 Beta and I'm somewhat unsure as to whether that is pertinent information but I figured I'd mention it anyway. My issue is that when I use the convertPointToView() function, it calls for an argument of type SKScene whereas (obviously) I want to it to take a point. I have another class which doesn't inherit SKScene where I want to use this function and it errors with "use of unresolved identifier convertPointToView" (I am importing SKScene). I find this to be very strange since I've written other programs that use this function and work fine even with the Xcode 7 beta, however, it doesn't seem to be working here. If anyone knows why I am having all this trouble, I'd really appreciate some help.
import Foundation
import SpriteKit
import SceneKit
class StandardLabel: UILabel {
init(x: Double, y: Double, width: Double, height: Double, doCenter: Bool, text: String, textColor: UIColor, backgroundColor: UIColor, font: String, fontSize: CGFloat, border: Bool, sceneWidth: Int) {
var frame = CGRect()
if doCenter {
frame = CGRect(x: convertPointToView(CGPoint(x: sceneWidth / 2, y: 0)).x, y: height, width: width, height: height)
} else {
frame = CGRect(x: x, y: y, width: width, height: height)
}
super.init(frame: frame)
self.text = text
self.textColor = textColor
self.backgroundColor = backgroundColor
self.textAlignment = NSTextAlignment.Center
self.font = UIFont(name: font, size: fontSize)
if border {
super.layer.borderColor = UIColor.blackColor().CGColor
super.layer.borderWidth = 5
}
}
I'd suggest that if you want to add text within your scene, that you use SKLabelNode, because it uses the same coordinate system as the other items that you'll be aligning, and you won't have to worry about converting your coordinates between different systems.
Use a UILabel if you want to display text outside of your scene (although for a SpriteKit (2D) game this wouldn't make sense because they're full screen, and I think would make sense mostly if you're making a SceneKit (3D) game).
Also, you don't need to make a subclass just to set default color and text size, it probably makes more sense to have this as a private helper method on your scene.
SKLabelNode doesn't have any 'border' property (like UILabel.layer does) so instead you'll need to draw an outline using SKShapeNode. This example uses the exact frame of the label so the text and the border are touching. You probably want to add a gap so there's space between the text and border but I'll leave that to you.
Here's a commented code snippet that adds two labels to a scene: "Baore" at size 80 with red text and border, and the label "Hello" at size 30 with blue text and border. Both are centered horizontally, "Baore" is also centered vertically, "Hello" is offset from the center by 150.
You could have also moved the position logic into the helper function, but to me that just feels weird... but up to you to decide how you want to do that!
import SpriteKit
class GameScene: SKScene {
override func didMoveToView(view: SKView) {
// `makeLabelWithOutline` is a helper function that takes 3 parameters
// - labelText
// - textSize
// - tint color to use for text and outline
// because textSize and tint have default values, you can
// omit them, and the default values will be used instead
// so this will be a label with text "Baore" at size 80 and red text and outline
let baoreLabel = self.makeLabelWithOutline("Baore")
baoreLabel.position = CGPoint(x:CGRectGetMidX(self.frame), y:CGRectGetMidY(self.frame))
self.addChild(baoreLabel)
// so this will be a label with text "Hello" at size 30 and blue text and outline
let helloLabel = self.makeLabelWithOutline("hello", textSize: 30, tint: UIColor.blueColor())
helloLabel.position = CGPoint(x:CGRectGetMidX(self.frame), y:CGRectGetMidY(self.frame)+150)
self.addChild(helloLabel)
}
private func makeLabelWithOutline(labelText:String, textSize:CGFloat = 80, tint:UIColor = UIColor.redColor()) -> SKNode {
let myLabel = SKLabelNode(fontNamed:"Futura-CondensedExtraBold")
myLabel.text = labelText
myLabel.fontColor = tint
myLabel.fontSize = textSize
// create the outline for the label
let labelOutline = SKShapeNode(rect: myLabel.frame)
labelOutline.strokeColor = tint
labelOutline.lineWidth = 5
labelOutline.addChild(myLabel)
return labelOutline
// we're returning an SKNode with this hierachy:
// SKShapeNode (the outline)
// ↳ SKLabelNode (the "Baore" label)
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
}
}
convertPointToView is an instance method of an SKScene object so you'll need to call it on some instance of an SKScene (maybe pass in a reference to the entire scene instead of just the sceneWidth?)
I'm not sure if it helps, but there's also convertPoint:toView: which might make more sense if you're dealing with a UILabel (??)

NSButton change width

I have a button with a title and image. The title of the button change dependent on the selected language. So i want that the button has always the width of the title plus image. I thought it was something easy like this:
var size = selectMenuItemButton.attributedTitle.size
myButton.bounds.size.width = size.width + 10.0
But the width of the button stay the same. What i'm doing wrong?
Edit:
Also try
myButton.frame.size.width = size.width + 10.0
And
myButton.sizeToFit()
Didn't work neither
Edit2:
I have created a clear project with two buttons. If the one button is clicked the title of the another button is changed. The outcome is the same, i want that the width is change too, but i can't achieve that
#IBAction func buttonClicked(sender: AnyObject) {
println(test.attributedTitle.size.width)
myButton.title = "blublublublub"
var size = test.attributedTitle.size
myButton.frame.size.width = size.width
println(test.attributedTitle.size.width)
}
I think i have the answer, i needed just set title again after i set the size:
myButton.title = "blublublublub"
var size = myButton.attributedTitle.size
myButton.frame.size.width = size.width
myButton.title = "blublublublub"
If someone want to change the size outside #IBAction you need to use dispatch:
dispatch_async( dispatch_get_main_queue()){
self.myButton.title = "blublublublub"
var size = self.myButton.attributedTitle.size
self.myButton.frame.size.width = size.width
self.myButton.title = "blublublublub"
}

iOS 8 Swift Xcode 6 - Set top nav bar bg color and height

I have looked everywhere and tested all the code snippets posted on Stack, but nothing works for me as I need it to work.
I simply want to set:
Nav bar height
Nav bar bg color in RGB
Nav bar centered logo
I'm working with iOS8, Xcode 6 and Swift.
Many thanks for a clear answer!
This is my code in ViewController.swift
// Set nav bar height
navigationController?.navigationBar.frame.origin.y = -10
// Set nav bar bg color
var navBarColor = UIColor(red: 4 / 255, green: 47 / 255, blue: 66 / 255, alpha: 1)
navigationController?.navigationBar.barTintColor = navBarColor
// Set nav bar logo
let navBarImageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 30, height: 30))
navBarImageView.contentMode = .ScaleAspectFit
let navBarImage = UIImage(named: "navBarLogo.png")
navBarImageView.image = navBarImage
navigationItem.titleView = navBarImageView
After applying the code in the accepted answer, the height doesn't seem to change at all..
It's not an easy job...and I've surveyed several articles online (most of them in Objective-C).
The most useful one is this: http://www.emdentec.com/blog/2014/2/25/hacking-uinavigationbar
But its final solution does not put items in the middle, and it's not in Swift.
So I come up with a workable version in Swift. Hope it helps some people as I was saved so many precious time on SO.
Solution in Swift:
The following code will solve some issues you may have encountered:
The title & items are not placed in the middle of the navigation bar
The title & items would flick when the user navigates between view controllers
You need to subclass the UINavigationBar first, and in your storyboard, select the navigation bar element, and in the "Identity Inspector" tab, set the new class as the Custom Class
import UIKit
class UINavigationBarTaller: UINavigationBar {
///The height you want your navigation bar to be of
static let navigationBarHeight: CGFloat = 64
///The difference between new height and default height
static let heightIncrease:CGFloat = navigationBarHeight - 44
override init(frame: CGRect) {
super.init(frame: frame)
initialize()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
initialize()
}
private func initialize() {
let shift = UINavigationBarTaller.heightIncrease/2
///Transform all view to shift upward for [shift] point
self.transform =
CGAffineTransformMakeTranslation(0, -shift)
}
override func layoutSubviews() {
super.layoutSubviews()
let shift = UINavigationBarTaller.heightIncrease/2
///Move the background down for [shift] point
let classNamesToReposition: [String] = ["_UINavigationBarBackground"]
for view: UIView in self.subviews {
if classNamesToReposition.contains(NSStringFromClass(view.dynamicType)) {
let bounds: CGRect = self.bounds
var frame: CGRect = view.frame
frame.origin.y = bounds.origin.y + shift - 20.0
frame.size.height = bounds.size.height + 20.0
view.frame = frame
}
}
}
override func sizeThatFits(size: CGSize) -> CGSize {
let amendedSize:CGSize = super.sizeThatFits(size)
let newSize:CGSize = CGSizeMake(amendedSize.width, UINavigationBarTaller.navigationBarHeight);
return newSize;
}
}
Also on my gist: https://gist.github.com/pai911/8fa123d4068b61ad0ff7
iOS 10 Update:
Unfortunately, this code breaks in iOS 10, there is someone who helps fix it, here you go:
iOS 10 custom navigation bar height
And to be clear, this code is kind of hacky since it depends on the navigation bar's internal structure...so if you decide to use it anyway, be prepared for any upcoming changes that may break this code...
Nav bar height:
In a custom navigation controller subclass...
The trick with this one is to NOT change the actual height of the navigation bar and instead adjust its origin.
func viewDidLoad() {
super.viewDidLoad()
navigationBar.frame.origin.y = -10
}
Nav bar bg color in RGB:
In a custom navigation controller subclass...
func viewDidLoad() {
super.viewDidLoad()
navigationBar.barTintColor = // YOUR COLOR
}
or use the appearance proxy
UINavigationBar.appearance().barTintColor = // YOUR COLOR
Nav bar centered logo
In a custom view controller...
func viewDidLoad() {
super.viewDidLoad()
navigationItem.titleView = UIImageView(image: // YOUR LOGO)
}
Great answer from Bon Bon!
In Swift 3 however make sure you replace
let classNamesToReposition: [String] = ["_UINavigationBarBackground"]
with
let classNamesToReposition: [ String ] = [ "_UIBarBackground" ]
Otherwise, it wont work.

Resources