Swift: Setting width and height within a UIButton class - ios

So I have a 60x60 button on my storyboard and set a class for it.
class CustomRedButton: UIButton {
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.layer.cornerRadius = 0.5 * self.bounds.size.width
self.backgroundColor = UIColor.redColor()
self.titleLabel!.font = UIFont(name: "Futura", size: 25)
self.titleLabel!.textAlignment = .Center
}
}
What I want to do is adjust the size of the button, and the font in it, based on the size of the screen.

Use view.bounds.maxX and view.bounds.maxY within the ViewController when you initialize it.
this is what I'm doing, but it only changes the width, not the height or the font size.
button1 = UIButton(frame: CGRect(x: 0, y: 0, width: (view.bounds.maxX / 2) - 10, height: 50))
button1.center = CGPoint(x: view.bounds.midX - button1.bounds.width / 2 - 5, y: view.bounds.maxY - 160)
button2 = UIButton(frame: CGRect(x: 0, y: 0, width: (view.bounds.maxX / 2) - 10, height: 50))
button2.center = CGPoint(x: view.bounds.midX + button1.bounds.width / 2 + 5, y: view.bounds.maxY - 160)
button3 = UIButton(frame: CGRect(x: 0, y: 0, width: (view.bounds.maxX / 2) - 10, height: 50))
button3.center = CGPoint(x: view.bounds.midX - button1.bounds.width / 2 - 5, y: view.bounds.maxY - 100)
button4 = UIButton(frame: CGRect(x: 0, y: 0, width: (view.bounds.maxX / 2) - 10, height: 50))
button4.center = CGPoint(x: view.bounds.midX + button1.bounds.width / 2 + 5, y: view.bounds.maxY - 100)
To do it for the height set the height to (view.bounds.maxY / 16 (or whatever number its up to you)) - 10 (spacing between buttons times 2) and change the center point to reflect the changes in height
To do the same for font size use view.bounds.maxX and divide it by something like 40. You get the idea.

Related

Change UILabel.frame when orientation changes using viewWillTransition

I programmatically create a set of buttons in the viewDidLoad() of my UIInputViewController. I am trying to change the size of these buttons when the orientation changes from landscape to portrait and vice-versa.
I am trying to do this by using
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator)
but when I go through the same code I used to create my buttons in viewDidLoad() with only the UIlabel.frame change to accommodate the new height and width, the view is not updated. Do I have to first remove the buttons and load them from scratch or is there another method to do this?
Below is the full code from the function.
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
let width = screensize.width
var height = CGFloat(141)
let sizey = screensize.height
switch sizey {
case 1366:
height = CGFloat(383-15)
case 1112:
height = CGFloat(320-15)
case 812:
height = CGFloat(141-15)
case 1024:
height = CGFloat(320-15)
case 736:
height = CGFloat(226-15)
case 667:
height = CGFloat(216-15)
case 568:
height = CGFloat(216-15)
case 768:
height = CGFloat(420-15)
default:
height = CGFloat(141-15)
}
connection.frame = CGRect(x: 0, y: 0, width: width/2, height: 15)
serialNum.frame = CGRect( x: width/2, y: 0, width: width/2, height:15)
plus.frame = CGRect(x:0, y: 15, width: width/5,height: height/4)
minus.frame = CGRect(x:0, y: height/4+15, width: width/5,height: height/4)
left.frame = CGRect(x:0, y: height/2+15, width: width/5,height: height/4)
nextKeyboardButton.frame = CGRect(x:0,y: 3*height/4+15, width: width/5,height: height/4)
num1.frame = CGRect(x:width/5, y: 15, width: width/5,height: height/4)
num4.frame = CGRect(x:width/5, y: height/4+15, width: width/5,height: height/4)
num7.frame = CGRect(x:width/5, y: height/2+15, width: width/5,height: height/4)
comma.frame = CGRect(x:width/5, y: 3*height/4+15, width: width/5,height: height/4)
num2.frame = CGRect(x:width*2/5,y: 15, width: width/5,height: height/4)
num5.frame = CGRect(x:width*2/5,y: height/4+15, width: width/5,height: height/4)
num8.frame = CGRect(x:width*2/5,y: height/2+15, width: width/5,height: height/4)
num0.frame = CGRect(x:width*2/5,y: 3*height/4+15, width: width/5,height: height/4)
num3.frame = CGRect(x:width*3/5,y: 15, width: width/5,height: height/4)
num6.frame = CGRect(x:width*3/5,y: height/4+15, width: width/5,height: height/4)
num9.frame = CGRect(x:width*3/5,y: height/2+15, width: width/5,height: height/4)
period.frame = CGRect(x:width*3/5,y: 3*height/4+15, width: width/5,height: height/4)
back.frame = CGRect(x:width*4/5, y: 15, width: width/5, height: height/4)
spaceBar.frame = CGRect(x: width*4/5, y: height/4+15, width: width/5, height: height/4)
right.frame =
CGRect(x: width*4/5, y: height/2+15, width: width/5, height: height/4)
returnKey.frame = CGRect(x:width*4/5, y: height*3/4+15, width: width/5, height: height/4)
self.view.addSubview(spaceBar)
self.view.addSubview(num1)
self.view.addSubview(num2)
self.view.addSubview(num3)
self.view.addSubview(num4)
self.view.addSubview(num5)
self.view.addSubview(num6)
self.view.addSubview(num7)
self.view.addSubview(num8)
self.view.addSubview(num9)
self.view.addSubview(num0)
self.view.addSubview(plus)
self.view.addSubview(minus)
self.view.addSubview(back)
self.view.addSubview(left)
self.view.addSubview(right)
self.view.addSubview(period)
self.view.addSubview(comma)
self.view.addSubview(nextKeyboardButton)
self.view.addSubview(returnKey)
You need to use the ‘size’ argument that you get in the ‘viewWillTransition’ method to set the new ‘width’ and ‘sizey’ properties in stead of ‘screensize’.
You shouldn't call addSubview on orientation change if you've already added the buttons in viewDidLoad. Updating the frame should be enough.
Since you have added these set of buttons in the viewDidLoad() of your UIInputViewController, you don't need to use addSubview in viewWillTransition to size method.
Even after rotating the device still you are using the old screen size.
Change
let width = screensize.width
let sizey = screensize.height
To
let width = UIScreen.main.bounds.width
let sizey = UIScreen.main.bounds.height
Or
let width = size.width
let sizey = size.height

updating classes in swift

I am looking for a solution to my problem. I have a class that creates a UIButton for me:
class MenuButton: UIButton {
var x: CGFloat
var y: CGFloat
var width: CGFloat
var height: CGFloat
required init(parent: UIView = UIView(), x: CGFloat = 0, y: CGFloat = 0, width: CGFloat = 40, height: CGFloat = 40) {
self.x = x
self.y = y
self.width = width
self.height = height
super.init(frame: .zero)
frame = CGRect(x: x, y: y, width: width, height: height)
backgroundColor = global.labelColor
setTitleColor(#colorLiteral(red: 0, green: 0, blue: 0, alpha: 1), for: .normal)
layer.cornerRadius = self.frame.height / 2
if x < 0 {
frame = CGRect(x: superview?.frame.width ?? 0 - abs(x) - frame.width, y: frame.minY, width: frame.width, height: frame.height)
}
if y < 0 {
frame = CGRect(x: frame.minX, y: superview?.frame.height ?? 0 - abs(y) - frame.height, width: frame.width, height: frame.height)
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Then I add a constant that is assigned to this class:
let pauseButton = MenuButton()
This works fine and the button is shown on the scene with everything to default. Now I want to add those things in the viewDidLoad() (I added the subview to acces it in the class):
view.addSubview(pauseButton)
pauseButton.x = -20
pauseButton.y = 20
pauseButton.width = 40
pauseButton.height = 40
This does not update the stuff I specified in the init(). How do I call the init again (without doing pauseButton = MenuButton() again) or is there like an update() I can use?
Thank you for your help ;)
You can actually pass those values in the initializer as below,
let pauseButton = MenuButton(parent: view, x: -20, y: 20, width: 40, height: 40)
If you want to make your button update immediately as you change any of these properties then you can use didSet callback to set the frame as below,
class MenuButton: UIButton {
var x: CGFloat {
didSet {
self.updateFrame()
}
}
var y: CGFloat {
didSet {
self.updateFrame()
}
}
var width: CGFloat {
didSet {
self.updateFrame()
}
}
var height: CGFloat {
didSet {
self.updateFrame()
}
}
private func updateFrame() {
frame = CGRect(x: x, y: y, width: width, height: height)
}
required init(parent: UIView = UIView(), x: CGFloat = 0, y: CGFloat = 0, width: CGFloat = 40, height: CGFloat = 40) {
self.x = x
self.y = y
self.width = width
self.height = height
super.init(frame: .zero)
frame = CGRect(x: x, y: y, width: width, height: height)
backgroundColor = .green
setTitleColor(#colorLiteral(red: 0, green: 0, blue: 0, alpha: 1), for: .normal)
layer.cornerRadius = self.frame.height / 2
if x < 0 {
frame = CGRect(x: superview?.frame.width ?? 0 - abs(x) - frame.width, y: frame.minY, width: frame.width, height: frame.height)
}
if y < 0 {
frame = CGRect(x: frame.minX, y: superview?.frame.height ?? 0 - abs(y) - frame.height, width: frame.width, height: frame.height)
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
each UIViewController have UIView accessed inside of it as view
you are adding the subview already here.
view.addSubview(pauseButton)
so just pass it into the init() you have and add it there.
your code could be something like this.
class MenuButton: UIButton {
var x: CGFloat
var y: CGFloat
var width: CGFloat
var height: CGFloat
required init(parent: UIView = UIView(), x: CGFloat = 0, y: CGFloat = 0, width: CGFloat = 40, height: CGFloat = 40) {
self.x = x
self.y = y
self.width = width
self.height = height
super.init(frame: .zero)
frame = CGRect(x: x, y: y, width: width, height: height)
backgroundColor = global.labelColor
setTitleColor(#colorLiteral(red: 0, green: 0, blue: 0, alpha: 1), for: .normal)
layer.cornerRadius = self.frame.height / 2
if x < 0 {
frame = CGRect(x: superview?.frame.width ?? 0 - abs(x) - frame.width, y: frame.minY, width: frame.width, height: frame.height)
}
if y < 0 {
frame = CGRect(x: frame.minX, y: superview?.frame.height ?? 0 - abs(y) - frame.height, width: frame.width, height: frame.height)
}
parent.addSubview(self)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
And use it in ViewDidLoad like this.
let _ = MenuButton(parent: view, x: -20, y: 20, width: 40, height: 40)
init() method is called only once when you instantiating your button. You should try to instantiate the button with the desired properties. Try something like this:
let pauseButton = MenuButton(parent: UIView(), x: -20, y: 20, width: 40, height:40)
Then in your viewDidLoad() method you can have just this line:
view.addSubview(pauseButton)
Another problem that I noticed is that you are referencing to the superview in your init() method, but superview is always nil in that case, since your button is not yet added as a subview.
have you tried ?
button.frame = CGRect(x:xPostion, y:yPostion, width:buttonWidth, height:buttonHeight)
or u can declare a funtion called updateFrame in ur Menu button class and pass new position as argument , like this :
func updateFrame(x:CGFloat, y: CGFloat, width: CGFloat, height: CGFloat){
self.frame = CGRect(x:xPostion, y:yPostion, width:buttonWidth, height:buttonHeight)
}
and in your VideDidLoad :
button.updateFrame(x:xPostion, y:yPostion, width:buttonWidth, height:buttonHeight)
what you are doing at the moment is just assigning some values to your Button's properties, how should your button knows to use them to reset its frame ??

why is content in UICollectionViewCell located incorrectly?

I have next code in controller, which set frame of UICollectionViewCell:
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
layout.itemSize = CGSize(width: self.view.frame.size.width / 3.8, height: self.view.frame.size.width / 3.8)
layout.minimumInteritemSpacing = 0
layout.minimumLineSpacing = 0
layout.scrollDirection = .vertical
devicesCollectionView.collectionViewLayout = layout
Chunk of code in delegate method, which call cell's method, which set data in it:
if let deviceCell = cell as? DevicesCollectionViewCell , let devices = room?.devices, let roomName = room?.roomName {
deviceCell.setDeviceInfoInCell(device: devices[indexPath.item], roomName: roomName, width: self.view.frame.size.width / 3.8)
}
chunk of code in cell's class:
self.frame = CGRect(x: self.frame.origin.x, y: self.frame.origin.y, width: width, height: width)
self.stateImageView.frame = CGRect(x: self.frame.origin.x + width - (width / 3), y: self.frame.origin.y, width: width / 3, height: width / 3)
self.lightImageView.frame = CGRect(x: self.frame.origin.x + 10, y: self.frame.origin.y + 10, width: width / 3, height: width / 3)
self.sensImageView.frame = CGRect(x: self.frame.origin.x + 10, y: self.frame.origin.y + 10, width: width / 5, height: width / 5)
self.humdityImageView.frame = CGRect(x: self.frame.origin.x + 10, y: self.frame.origin.y + sensImageView.frame.size.height + 15, width: width / 5, height: width / 5)
But when my CollectionView is showed, imageviews inside placed incorrectly, sometimes I didn't see them. Why they gets incorrect coordinates?
Screenshots: only one picture in one cell
and here icons goes anywhere:
Updating
according the comments I'm trying to use layoutIfNeeds and adding this method to my cell's class:
override func layoutSubviews() {
self.layoutIfNeeded()
self.stateImageView.layoutIfNeeded()
self.sensImageView.layoutIfNeeded()
self.humdityImageView.layoutIfNeeded()
self.lightImageView.layoutSubviews()
}
But it is don't solved my problem, and now labels goes anywhere too. Please help me. New screenShot:

Wrong alignment of subviews in a UIScrollView

I have the following code, which creates UIView, and some of its subViews, and adds them to a UIScrollView, all in a loop :
var count:CGFloat=bookScrollView.frame.minX
for var i=0;i<10;i++ {
var view=UIView(frame: CGRect(x: count + 20, y: bookScrollView.frame.minY + 30, width: 200, height: 300))
view.backgroundColor=UIColor.whiteColor()
view.layer.cornerRadius = 5;
view.layer.masksToBounds = true;
var imageView=UIImageView(frame: CGRect(x: count, y: view.frame.minY - 30, width: 150, height: 220))
// imageView.image=UIImage(named: "Sample_Book")!
view.addSubview(imageView)
var titleLabel=UILabel(frame: CGRect(x: count + 10, y: imageView.frame.maxY + 30, width: 185, height: 60))
titleLabel.text="Head First Javascript"
titleLabel.backgroundColor=UIColor.clearColor()
titleLabel.font=UIFont(name: "Menlo-Bold ", size: 15)
titleLabel.textAlignment = NSTextAlignment.Center
titleLabel.textColor=UIColor.grayColor()
view.addSubview(titleLabel)
bookScrollView.addSubview(view)
count+=220
}
bookScrollView.contentSize=CGSize(width: count, height: 200)
It works fine,except the fact that other than in the first view,imageView and titleLabel are not visible.
The label and the imageView have moved towards the right from the second view onwards.
Frames are expressed according to the superview's coordinate space.
Since you're adding your image view and label to the view not the scroll view, their frames should be specified in view's coordinate space. So you do not need to add count to their x position.
var imageView=UIImageView(frame: CGRect(x: 0.0, y: 0.0, width: 150, height: 220))
And:
var titleLabel=UILabel(frame: CGRect(x: 10.0, y: imageView.frame.maxY + 30, width: 185, height: 60))
Note: You should look into UICollectionView and autolayout for a more robust way of achieving this.

AutoLayout for programmatically created uiview element

When i try to create an uiview with loading text and activityindicator, even though it looks centered in iphone 6, it is not centered in iphone 5.
How can i use auto layout for this programatically created UIView ?
I am trying to center this uiview in all screen sizes
boxView = UIView(frame: CGRect(x: TableView.frame.midX - 60, y: TableView.frame.midY - 15, width: 180, height: 50))
boxView.backgroundColor = UIColor.blackColor()
boxView.alpha = 0.5
boxView.layer.cornerRadius = 10
var activityView = UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.WhiteLarge)
activityView.frame = CGRect(x: 0, y: 0, width: 50, height: 50)
activityView.startAnimating()
var textLabel = UILabel(frame: CGRect(x: 60, y: 0, width: 200, height: 50))
textLabel.textColor = UIColor.whiteColor()
textLabel.text = "Loading"
boxView.addSubview(activityView)
boxView.addSubview(textLabel)
TableView.addSubview(boxView)
EDIT: I tried this and it seems working good
var bounds: CGRect = UIScreen.mainScreen().bounds
var width:CGFloat = bounds.size.width
var height:CGFloat = bounds.size.height
boxView = UIView(frame: CGRect(x: width/2 - 90, y: height/2 - 100, width: 180, height: 50))

Resources