Swift text attribute issue: Letter Spacing + Highlighted - ios

I have a button
buttonSign
created and tested with the highlighted change of colour.
I need to create also -0.5 letter spacing with:
let attributedString = NSMutableAttributedString(string: (buttonSign.titleLabel?.text!)!)
attributedString.addAttribute(NSAttributedString.Key.kern, value: -0.5, range: NSRange(location: 0, length: (buttonSign.titleLabel?.text!.count)!))
buttonSign.setAttributedTitle(attributedString, for: .normal)
The button code:
let buttonSign = UIButton(frame: CGRect(x: UIScreen.main.bounds.width/2 - 170, y: UIScreen.main.bounds.height-41-56-16-56, width: 340, height: 56))
buttonSign.setTitleColor(UIColor.white, for: UIControl.State.normal)
buttonSign.setTitleColor(UIColor.blue, for: UIControl.State.highlighted)
buttonSign.backgroundColor = UIColor(red: 95.0 / 255.0, green: 84.0 / 255.0, blue: 216.0 / 255.0, alpha: 1.0)
buttonSign.addTarget(self, action: #selector(signUpAction), for: .touchUpInside)
buttonSign.layer.cornerRadius = buttonSign.bounds.size.height / 2
buttonSign.clipsToBounds = true
buttonSign.setTitle("SIGN UP",for: .normal)
buttonSign.titleLabel?.font = UIFont(name: "SFProDisplay-Bold", size: 20)
buttonSign.titleLabel?.textColor = UIColor(red: 111.0 / 255.0, green: 107.0 / 255.0, blue: 244.0 / 255.0, alpha: 1.0)
view.addSubview(buttonSign)
This works but when I apply
attributedString
It doesn't change the colour of text when highlighted.
How is that possible?

Related

auto layout and bottom line textfield

I've set constraints for these UITextField like this
But when I custom the textfield it's gone over the constraint
emailTextField.backgroundColor = UIColor.clear
emailTextField.attributedPlaceholder = NSAttributedString(string: emailTextField.placeholder!, attributes: [NSAttributedString.Key.foregroundColor: #colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 1)])
emailTextField.borderStyle = .none
emailTextField.tintColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
let bottomLayer = CALayer()
bottomLayer.frame = CGRect(x: 0, y: 20, width: 1000, height: 0.7)
bottomLayer.backgroundColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
emailTextField.layer.addSublayer(bottomLayer)
Run..
Please tell me why? Many thanks for that...
You have set CALayer width 1000. It should be width of your TextField.
Change below code:
Add below code to get updated frame of emailTextField and set the width of Layer:
emailTextField.setNeedsLayout()
emailTextField.layoutIfNeeded()
bottomLayer.frame = CGRect(x: 0, y: 20, width: emailTextField.frame.size.width, height: 0.7)
UPDATE
If you want to reuse this textField configuration you can create one function like below:
func setupTextField(textField: UITextField) {
textField.backgroundColor = UIColor.clear
textField.attributedPlaceholder = NSAttributedString(string: textField.placeholder!, attributes: [NSAttributedString.Key.foregroundColor: #colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 1)])
textField.borderStyle = .none
textField.tintColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
textField.setNeedsLayout()
textField.layoutIfNeeded()
let bottomLayer = CALayer()
bottomLayer.frame = CGRect(x: 0, y: 20, width: textField.frame.size.width, height: 0.7)
bottomLayer.backgroundColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
textField.layer.addSublayer(bottomLayer)
}
You can call above method this way:
setupTextField(textField: textField)

Getting transparent UIButton after applying gradient

I am learning Swift by trying to develop an app.I want to design a button by adding gradient layer, but the problem is it doesn't appear on the screen. It does its function when I clicked where it should appear tho.
extension UIColor {
convenience init(red: Int, green: Int, blue: Int) {
assert(red >= 0 && red <= 255, "Invalid red component")
assert(green >= 0 && green <= 255, "Invalid green component")
assert(blue >= 0 && blue <= 255, "Invalid blue component")
self.init(red: CGFloat(red) / 255.0, green: CGFloat(green) / 255.0, blue: CGFloat(blue) / 255.0, alpha: 1.0)
}
convenience init(rgb: Int) {
self.init(
red: (rgb >> 16) & 0xFF,
green: (rgb >> 8) & 0xFF,
blue: rgb & 0xFF
)
}
}
extension UIButton
{
func applyGradient(colors: [CGColor])
{
let gradientLayer = CAGradientLayer()
gradientLayer.colors = colors
gradientLayer.startPoint = CGPoint(x: 0, y: 0)
gradientLayer.endPoint = CGPoint(x: 1, y: 1)
gradientLayer.frame = self.bounds
self.layer.addSublayer(gradientLayer)
}
lazy var loginButton: UIButton = {
let button = UIButton(type: .system)
let color1 = UIColor(red: 26, green: 41, blue: 128)
let color2 = UIColor(red: 38, green: 208, blue: 206)
button.applyGradient(colors: [color1.cgColor, color2.cgColor])
button.setTitle("Log in", for: .normal)
button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 16)
button.setTitleColor(.black, for: .normal)
button.addTarget(self, action: #selector(handleButtonLogin), for: .touchUpInside)
return button
}()
Actually, it should say Log in(white color) with blue to green gradient layer. If I set the log in title color to black. I can see it when I run the code.
You only miss the frame
loginButton.frame = self.view.frame
self.view.addSubview(loginButton)
loginButton.applyGradient(colors: [UIColor.red.cgColor,UIColor.blue.cgColor])
//
Also change this line
self.layer.addSublayer(gradientLayer)
to
self.layer.insertSublayer(gradientLayer, at: 0)
as not to hide the title of the button
//

UIButton sizeToFit not working

This is my code :
let button_video = UIButton(type: .custom)
button_video.frame = CGRect.zero
if subsession.VideoUrl != nil
{
button_video.frame = CGRect(x: 10, y: yAxis + 15, width: 300, height: 30)
button_video.contentEdgeInsets = UIEdgeInsets(top: 3, left: 28, bottom: 7, right: 5)
if iVideoNumber == 0
{
button_video.setTitle(String(format: "Video #%i", 1), for: .normal)
}
else
{
button_video.setTitle(String(format: "Video #%i", iVideoNumber+1), for: .normal)
}
button_video.titleLabel?.font = UIFont(name: "OpenSans-Regular", size: 15)
button_video.titleLabel?.textColor = UIColor.white
button_video.setTitleColor(UIColor.white, for: .normal)
button_video.titleLabel?.numberOfLines = 0
button_video.titleLabel?.lineBreakMode = .byWordWrapping
button_video.titleLabel?.textAlignment = .center
button_video.tag = iCount
button_video.addTarget(self, action: #selector(CourseDetailViewController.loadVideo(sender:)), for: .touchUpInside)
let btnGradient = CAGradientLayer()
btnGradient.frame = button_video.bounds
btnGradient.cornerRadius = 6
btnGradient.colors = [(UIColor(red: 174.0 / 255.0, green: 127.0 / 255.0, blue: 183.0 / 255.0, alpha: 1.0).cgColor as CGColor), (UIColor(red: 78.0 / 255.0, green: 57.0 / 255.0, blue: 96.0 / 255.0, alpha: 1.0).cgColor as CGColor)]
button_video.layer.insertSublayer(btnGradient, at: 0)
button_video.sizeToFit()
view_scrollView.addSubview(button_video)
}
}
The button however occupies the whole width of 300
You are inserting sublayer with defined frame, and inserting it in your button. So sizetofit is working its size is equal to largest layes in button which is 300 due to size of gradient layer.
If you are using multiple titles for different UIControlState, make sure to change the UIControlState before asking for sizeToFit.
In my UIButton I had to use multiple titles, one for UIControlState.normal and another for .selected state, I was expecting the result of .normal state, but the button was on .selected state.

Issues with animation in swift

I am trying to make some buttons look like they are growing. Could anybody tell my why this code only makes the buttons appear after the while loop completes?
var size = CGFloat(5)
let b1 = UIButton()
b1.backgroundColor = UIColor(red: 200, green: 0, blue: 0, alpha: 100)
b1.setTitle("", forState: .Normal)
b1.setTitleColor(UIColor(red: 255, green: 255, blue: 255, alpha: 100), forState: .Normal)
b1.frame = CGRectMake((view.frame.width/2)-105, (view.frame.height/2-105), CGFloat(size), CGFloat(size))
b1.titleLabel?.font = UIFont(name: "Helvetica", size: 24)
let b2 = UIButton()
b2.backgroundColor = UIColor(red: 0, green: 0, blue: 200, alpha: 100)
b2.setTitle("", forState: .Normal)
b2.setTitleColor(UIColor(red: 255, green: 255, blue: 255, alpha: 100), forState: .Normal)
b2.frame = CGRectMake((view.frame.width/2)+5, (view.frame.height/2)-105, CGFloat(size), CGFloat(size))
b2.titleLabel?.font = UIFont(name: "Helvetica", size: 24)
let b3 = UIButton()
b3.backgroundColor = UIColor(red: 0, green: 200, blue: 0, alpha: 100)
b3.setTitle("", forState: .Normal)
b3.setTitleColor(UIColor(red: 255, green: 255, blue: 255, alpha: 100), forState: .Normal)
b3.frame = CGRectMake((view.frame.width/2)-105, view.frame.height/2+5, CGFloat(size), CGFloat(size))
b3.titleLabel?.font = UIFont(name: "Helvetica", size: 24)
let b4 = UIButton()
b4.backgroundColor = UIColor(red: 200, green: 200, blue: 0, alpha: 100)
b4.setTitle("", forState: .Normal)
b4.setTitleColor(UIColor(red: 255, green: 255, blue: 255, alpha: 100), forState: .Normal)
b4.frame = CGRectMake((view.frame.width/2)+5, view.frame.height/2+5, CGFloat(size), CGFloat(size))
b4.titleLabel?.font = UIFont(name: "Helvetica", size: 24)
while (size < 100) {
size+=1
b1.frame = CGRectMake(CGFloat(view.frame.width/2)-105/*+CGFloat(100-size)*/, CGFloat(view.frame.height/2-105)+CGFloat(100-size), CGFloat(size), CGFloat(size))
b2.frame = CGRectMake(CGFloat(view.frame.width/2)+5/*+CGFloat(100-size)*/, (view.frame.height/2)-105+(100-size), CGFloat(size), CGFloat(size))
b3.frame = CGRectMake(CGFloat(view.frame.width/2)-105/*+CGFloat(100-size)*/, view.frame.height/2+5+(100-size), CGFloat(size), CGFloat(size))
b4.frame = CGRectMake(CGFloat(view.frame.width/2)+5/*+CGFloat(100-size)*/, view.frame.height/2+5+(100-size), CGFloat(size), CGFloat(size))
view.addSubview(b1)
view.addSubview(b2)
view.addSubview(b3)
view.addSubview(b4)
}'
UI Changes don't take effect until after your code returns and the program visits the event loop. All the UI changes you make in a function call get saved up and then applied on the next pass through the event loop.
Your while loop runs all the way to the end, and THEN the view changes are rendered to the screen, all at once.
As JYeh says in his answer, you should use UIView animation methods in the family animateWithDuration.
I suggest reading up on how to use a UIView Animation: https://www.raywenderlich.com/76200/basic-uiview-animation-swift-tutorial
Instead of the while loop, use a UIView.animateWithDuration function call. The reason the buttons are just appearing is because the while loop finishes so fast that you can't see anything happening, and while loops shouldn't be used to do animation.
How about this?
// make an array containing 4 CGRect values:
var frames = Array<CGRect>(count: 4, repeatedValue: CGRectNull)
// divide view into 4 parts: left and right, then divide left and right into 2 parts each, top and bottom
let (left, right) = view.bounds.divide( view.bounds.width * 0.5, fromEdge: .MinXEdge )
(frames[0], frames[2]) = left.divide( view.bounds.height * 0.5, fromEdge:.MinYEdge)
(frames[1], frames[3]) = right.divide( view.bounds.height * 0.5, fromEdge:.MinYEdge)
// iterate over the range 0 to 3
(0...3).forEach { // this block (function) has the current number as its input
// I didn't name the input, so Swift names it $0
let b = UIButton( type: .System ) // make a standard button
b.frame = frames[ $0 ] // give the button a frame
/*
...Add code to customize your button `b` here
*/
view.addSubview( b ) // add button to our view
b.layer.addAnimation({ // add an animation to the button's layer.
// We will scale to current size from 5% size:
let anim = CABasicAnimation( keyPath: "transform" )
anim.fromValue = NSValue( CATransform3D: CATransform3DMakeScale( 0.05, 0.05, 1.0))
anim.duration = 5.0 // animation takes 5.0 s, just for demo purposes
return anim // the created animation, to be added
}(), forKey: nil)
}

Weird line sticking out on the end of UILabel

I have a UILabel on each section of my tableview. I have this line sticking out on the end of the label and this is coming from an iPhone 6. I've encountered it before on the iPhone 5 and managed to make it disappear by changing the width of the UILabel.
Here's the code on viewForHeaderInSection:
let view = UIView(frame: CGRectMake(0, 0, self.view.bounds.width, 30))
view.backgroundColor = UIColor(red: 248/255, green: 247/255, blue: 243/255, alpha: 1.0)
let label = UILabel(frame: CGRectMake((self.view.bounds.width - (self.view.bounds.width * 0.4)) / 2, 0, self.view.bounds.width * 0.4, 25))
label.backgroundColor = UIColor(red: 248/255, green: 247/255, blue: 243/255, alpha: 1.0)
label.textColor = UIColor(red: 163/255, green: 144/255, blue: 99/255, alpha: 1.0)
label.textAlignment = .Center
label.text = "YOUR TITLE HERE"
let line1 = UIView(frame: CGRectMake((self.view.bounds.width - (self.view.bounds.width * 0.8)) / 2, 13, self.view.bounds.width * 0.8, 1))
line1.backgroundColor = UIColor(red: 163/255, green: 144/255, blue: 99/255, alpha: 1.0)
view.addSubview(line1) // Adds the line first
view.addSubview(label) // Then the label on top of the line for the look.
return view

Resources