UIButton sizeToFit not working - ios

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.

Related

Swift text attribute issue: Letter Spacing + Highlighted

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?

Remove title shadow from shadowed button

I'm trying to remove shadow from my button title.
How I make shadow and corner radius:
func makeShadowRounded() {
layer.cornerRadius = 25
layer.shadowColor = UIColor.darkGray.cgColor
layer.shadowOffset = CGSize(width: 0, height: 2)
layer.shadowRadius = 3
layer.shadowOpacity = 0.15
}
My button with white background:
let signInButton: UIButton = {
let button = UIButton()
button.layer.borderColor = UIColor.customBlue.cgColor
button.layer.borderWidth = 0.5
button.setTitle("Sign In", for: .normal)
button.setTitleColor(.customBlue, for: .normal)
button.makeShadowRounded()
return button
}()
For removing/replacing (by different color) shadow i replaced setTitle and setTitleColor by:
let shadow = NSShadow()
shadow.shadowColor = UIColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
shadow.shadowOffset = CGSize(width: 0, height: 2)
shadow.shadowBlurRadius = 2
let attributedString = NSAttributedString(string: "Sign In", attributes: [
NSAttributedStringKey.shadow : shadow,
NSAttributedStringKey.foregroundColor : UIColor.customBlue
])
button.setAttributedTitle(attributedString, for: .normal)
However, It isn't working properly. What will be the better solution for that issue?

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
//

add drop shadow on a table view header

I have this following header for my table view header section
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let view = UIView()
view.backgroundColor = .white
// add a button
let button = UIButton(type : .system)
button.showsTouchWhenHighlighted = false
button.frame = CGRect(x: 0 , y: 0 , width: 20 , height: 20 )
if(collapsed[section])
{ button.backgroundColor = #colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 1)}
else
{ button.backgroundColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)}
button.addTarget(self, action: #selector(reloadTable), for: .touchUpInside)
button.tag = section
view.addSubview(button)
button.bindFrameToSuperviewBounds()
// add an Image
let image = UIImageView(image: UIImage(named: "sup1"))
image.frame = CGRect(x: 150 , y: 5 , width: 100 , height: 100)
image.contentMode = .scaleAspectFit
view.addSubview(image)
// add a label
let lblNew = UILabel()
lblNew.frame = CGRect(x: 20, y: 100 , width: 100, height: 30)
lblNew.text = "١٢٣ ر.س"
lblNew.textColor = UIColor.myDarkGreen
lblNew.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(lblNew)
// view.dropShadow()
return view
}
Now I want to add drop shadow effect on the section header to look like this
I have tried some solutions here but it works on simple view that is not used as a viewForHeaderInSection, any tips?
Use the view's layer's shadow properties:
view.layer.shadowOpacity = 1
view.layer.shadowOffset = CGSize(width: 0, height: 1)
view.layer.shadowRadius = 1
Result:

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)
}

Resources