Difference between UIView frame.size.width vs frame.width - uiview

var view = UIView(frame: CGRect(x: 5, y: 5, width:50, height: 30))
println(view.frame.size.width)
println(view.frame.width)
They both print out the same value, whats the difference between these two? Are there some specific scenarios where a particular one should be used?

CGRect extension has width and height properties as get method.
struct CGRect {
var origin: CGPoint
var size: CGSize
}
extension CGRect {
var width: CGFloat { get }
var height: CGFloat { get }
}
Basically they are the same the difference is
frame.width = 5 is not possible
frame.size.width = 5 is possible

Related

Add possible input types to CGRect Swift

I want to be able to pass a percentage value to a CGRect
I created a Percentage class to get the input and then created four values (x, y, width, height)
Now I need to create an extension for CGRect to be able to use the Percentage values in it. The extension returns an error.
extension CGRect {
init(x: Percentage, y: Percentage, width: Percentage, height: Percentage) {
self.init(x: Percentage.x, y: Percentage.y, width: Percentage.width, height: Percentage.height)
ERROR: Instance member 'x' cannot be used on type 'Percentage'
}
}
class Percentage {
let x: CGFloat
let y: CGFloat
let width: CGFloat
let height: CGFloat
init(_ value: CGFloat) {
self.x = UIScreen.main.bounds.width * value
self.y = UIScreen.main.bounds.height * value
self.width = UIScreen.main.bounds.width * value
self.height = UIScreen.main.bounds.height * value
}
}
Thanks for your help ;)
EDIT:
I wanna be able to use it like this:
CGRect(x: Percentage(0.5), y: 50, width: 100, height: 100)
Instance member 'x' cannot be used on type 'Percentage'
you're using type of class so even if you had in parameter percentage, it wouldn't work.
But better would be if you just passed certain Percentage as parameter for init and then use its properties (use it with small p because you need init parameter, not your class type)
init(percentage: Percentage) {
self.init(x: percentage.x, y: percentage.y, width: percentage.width, height: percentage.height)
}
After your edit I have to say that you don’t have to use custom init and you can just pass property of your Percentage
CGRect(x: yourPercentage.x, y: 50, ...)
Think there is no need for a custom extension/classes - just use:
let view = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
let viewRect = view.frame
let scaleFactor:CGFloat = 0.5
let scaledFrame = viewRect.applying(CGAffineTransform(scaleX: scaleFactor, y: scaleFactor))
print("Scaled size: \(scaledFrame)")
// Scaled size: (0.0, 0.0, 50.0, 50.0)
However, you also can move this "feature" to an extension as well.

Alternative to Inheritance from multiple classes swift

I have a class that manages positioning of UIKit elements using 'frame':
class EasyPos: UIView {
var screenWidth = UIScreen.main.bounds.width
var screenHeight = UIScreen.main.bounds.height
var x: CGFloat = 0 { didSet { self.updateFrame() } }
var y: CGFloat = 0 { didSet { self.updateFrame() } }
var width: CGFloat = 0 { didSet { self.updateFrame() } }
var height: CGFloat = 0 { didSet { self.updateFrame() } }
func updateFrame() {
frame = CGRect(x: x, y: y, width: width, height: height)
if x < 0 {
frame = CGRect(x: screenWidth - abs(x) - width, y: frame.minY, width: frame.width, height: frame.height)
}
if y < 0 {
frame = CGRect(x: frame.minX, y: screenHeight - abs(y) - height, width: frame.width, height: frame.height)
}
}
required init(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)
updateFrame()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Now I want to add one class that inherits from UIbutton and one that inherits from a UILabel. And they should both be able to use the methods from the EasyPos class. How do I do this? (I tried inheritance from two classes, didn't work)
I know it has something to do with protocols. But I couldn't get this to work either.
Thanks for you help ;)
One way you could do this is to write a protocol extension. Because you have properties you'll need to implement a component but it shouldn't be too difficult -
struct FrameComponent {
var x: CGFloat = 0
var y: CGFloat = 0
var width: CGFloat = 0
var height: CGFloat = 0
}
protocol EasyPos {
var fc: FrameComponent { get, set }
func updateFrame()
}
extension EasyPos where Self: UIView {
func updateFrame() {
frame = CGRect(x: fc.x, y: fc.y, width: fc.width, height: fc.height)
if fc.x < 0 {
frame = CGRect(x: screenWidth - abs(fc.x) - fc.width, y: frame.minY, width:
frame.width, height: frame.height)
}
if fc.y < 0 {
frame = CGRect(x: frame.minX, y: screenHeight - abs(fc.y) - fc.height, width:
frame.width, height: frame.height)
}
}
}
Something you should remember is extensions can't add property observers, so you will need to call updateFrame() manually.

UIScrollView with horizontal paging using UIView as Subviews

I have seen answers for this following question. I am new to swift programming and I am trying to implement a similar feature. I just wondered if you had any guidance on how to achieve this in swift 3 Xcode 8. I have been searching around for a suitable solution but I've had no luck.
I am trying use UIViews as a subview of UIscrollviews. I would also like to have each view fill the screen when pressed and shows another UIView. I have seen a similar feature on the GOLF app by 'Tyler the Creator'
The feature I am trying achieve is pictured below.
Any help you could give would be greatly appreciated.
This is a representation of the feature I am trying to create.
let scrollView : UIScrollView = UIScrollView(frame: CGRect(x: 80, y: 80,
width: 250, height: 300))
scrollView.isPagingEnabled = true
scrollView.backgroundColor = .orange
view.addSubview(scrollView)
let numberOfPages :Int = 5
let padding : CGFloat = 15
let viewWidth = scrollView.frame.size.width - 2 * padding
let viewHeight = scrollView.frame.size.height - 2 * padding
var x : CGFloat = 0
for i in 0...numberOfPages{
let view: UIView = UIView(frame: CGRect(x: x + padding, y: padding, width: viewWidth, height: viewHeight))
view.backgroundColor = UIColor.white
scrollView .addSubview(view)
x = view.frame.origin.x + viewWidth + padding
}
scrollView.contentSize = CGSize(width:x+padding, height:scrollView.frame.size.height)
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var scrollView: UIScrollView!
var colors:[UIColor] = [.red, .blue, .green, .yellow]
var frame: CGRect = CGRect(x: 0, y: 0, width: 0, height: 0)
override func viewDidLoad() {
super.viewDidLoad()
scrollView.isPagingEnabled = true
scrollView.backgroundColor = .orange
view.addSubview(scrollView)
let numberOfPages :Int = 3
let padding : CGFloat = 15
let viewWidth = scrollView.frame.size.width - 2 * padding
let viewHeight = scrollView.frame.size.height - 2 * padding
var x : CGFloat = 0
for i in 0...numberOfPages{
let view: UIView = UIView(frame: CGRect(x: x + padding, y: padding, width: viewWidth, height: viewHeight))
view.backgroundColor = colors[i]
scrollView .addSubview(view)
x = view.frame.origin.x + viewWidth + padding
}
scrollView.contentSize = CGSize(width:x+padding, height:scrollView.frame.size.height)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
You should use UIPageViewController. That class is exactly meant to do what you are looking for with ease.
See UIPageViewController
You can embed your UIPageViewController in a UIContainerView to fit it anywhere.

CGSizeMake not available [duplicate]

After converting code to latest swift 3.0 I am shown this error.
Also tell me solution for CGSize = CGSizeMake(0,0)
static var frameAtStartOfPan: CGRect = CGRectZero
static var startPointOfPan: CGPoint = CGPointZero
Which is also unavailable.
CGRect Can be simply created using an instance of a CGPoint or CGSize, thats given below.
let rect = CGRect(origin: CGPoint(x: 0,y :0), size: CGSize(width: 100, height: 100))
// Or
let rect = CGRect(origin: .zero, size: CGSize(width: 100, height: 100))
Or if we want to specify each value in CGFloat or Double or Int, we can use this method.
let rect = CGRect(x: 0, y: 0, width: 100, height: 100) // CGFloat, Double, Int
CGPoint Can be created like this.
let point = CGPoint(x: 0,y :0) // CGFloat, Double, Int
CGSize Can be created like this.
let size = CGSize(width: 100, height: 100) // CGFloat, Double, Int
Also size and point with 0 as the values, it can be done like this.
let size = CGSize.zero // width = 0, height = 0
let point = CGPoint.zero // x = 0, y = 0, equal to CGPointZero
let rect = CGRect.zero // equal to CGRectZero
CGRectZero & CGPointZero replaced with CGRect.zero & CGPoint.zero in Swift 3.0.
Quick fix for CGRectMake , CGPointMake, CGSizeMake in Swift3 & iOS10
Add these extensions :
extension CGRect{
init(_ x:CGFloat,_ y:CGFloat,_ width:CGFloat,_ height:CGFloat) {
self.init(x:x,y:y,width:width,height:height)
}
}
extension CGSize{
init(_ width:CGFloat,_ height:CGFloat) {
self.init(width:width,height:height)
}
}
extension CGPoint{
init(_ x:CGFloat,_ y:CGFloat) {
self.init(x:x,y:y)
}
}
Then go to "Find and Replace in Workspace"
Find CGRectMake , CGPointMake, CGSizeMake and Replace them with CGRect , CGPoint, CGSize
These steps might save all the time as Xcode right now doesn't give us quick conversion from Swift 2+ to Swift 3
In Swift 3, you can simply use CGPoint.zero or CGRect.zero in place of CGRectZero or CGPointZero.
However, in Swift 4, CGRect.zero and 'CGPoint.zero' will work
If you want to use them as in swift 2, you can use these funcs:
For CGRectMake:
func CGRectMake(_ x: CGFloat, _ y: CGFloat, _ width: CGFloat, _ height: CGFloat) -> CGRect {
return CGRect(x: x, y: y, width: width, height: height)
}
For CGPointMake:
func CGPointMake(_ x: CGFloat, _ y: CGFloat) -> CGPoint {
return CGPoint(x: x, y: y)
}
For CGSizeMake:
func CGSizeMake(_ width: CGFloat, _ height: CGFloat) -> CGSize {
return CGSize(width: width, height: height)
}
Just put them outside any class and it should work. (Works for me at least)
The structures as well as all other symbols in Core Graphics and other APIs have become cleaner and also include parameter names.
https://developer.apple.com/reference/coregraphics#symbols
CGRect(x: Int, y: Int, width: Int, height: Int)
CGVector(dx: Int, dy: Int)
CGPoint(x: Double, y: Double)
CGSize(width: Int, height: Int)
CGPoint Example:
let newPoint = stackMid.convert(CGPoint(x: -10, y: 10), to: self)
CGVector Example:
self.physicsWorld.gravity = CGVector(dx: 0, dy: gravity)
CGSize Example:
hero.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: 16, height: 18))
CGRect Example:
let back = SKShapeNode(rect: CGRect(x: 0-120, y: 1024-200-30, width: 240, height: 140), cornerRadius: 20)
Apple Blog
Swift syntax and API renaming changes in Swift 3 make the language feel more natural, and provide an even more Swift-y experience when calling Cocoa frameworks. Popular frameworks Core Graphics and Grand Central Dispatch have new, much cleaner interfaces in Swift.
Swift 3 Bonus: Why didn't anyone mention the short form?
CGRect(origin: .zero, size: size)
.zero instead of CGPoint.zero
When the type is defined, you can safely omit it.
Try the following:
var myToolBar = UIToolbar.init(frame: CGRect.init(x: 0, y: 0, width: 320, height: 44))
This is for the swift's latest version
You can use this with replacement of CGRectZero
CGRect.zero
For CGSize
CGSize(width: self.view.frame.width * 3, height: self.view.frame.size.height)
Instead of CGSizeMake add CGSize it will work.
CGSizeMake is used in objective c.
you don't want to use make with swift
In Swift 4 it works like below
collectionView.setContentOffset(CGPoint.zero, animated: true)

set the padding of a text field using swift in xcode

How to create some space at the beginning of a text field using swift?
I looked at the post
padding of text field
I don't understand what the subclass is doing and how do I use that class to padding.
Thank you very much
https://stackoverflow.com/a/27066764/846780
This answer is very clear,
If you subclass UITextField you can override textRectForBounds, editingRectForBounds and placeholderRectForBounds. These methods just allow you to add a rect (frame) to your textfield's label.
newBounds method create the rect (frame) that will be added to textfield's label.
Finally your padding is: let padding = UIEdgeInsets(top: 0, left: 5, bottom: 0, right: 5);
Now you have a custom UITextField that has a custom padding.
If you create your new subClass like this class MyTextField: UITextField for example, you only need to change the class of the UITextField that you've added into IB file.
Complementing the answer of klevison-matias this is the code I use when I want to add a padding to my TextField in Swift 3
//UITextField : override textRect, editingRect
class LeftPaddedTextField: UITextField {
override func textRect(forBounds bounds: CGRect) -> CGRect {
return CGRect(x: bounds.origin.x + 10, y: bounds.origin.y, width: bounds.width, height: bounds.height)
}
override func editingRect(forBounds bounds: CGRect) -> CGRect {
return CGRect(x: bounds.origin.x + 10, y: bounds.origin.y, width: bounds.width, height: bounds.height)
}
}
Then in my TextField I use in this way:
let emailTextField: LeftPaddedTextField = {
let textField = LeftPaddedTextField()
textField.placeholder = "Enter email"
textField.layer.borderColor = UIColor.lightGray.cgColor
textField.layer.borderWidth = 1
textField.keyboardType = .emailAddress
return textField
}()
let passwordTextField: LeftPaddedTextField = {
let textField = LeftPaddedTextField()
textField.placeholder = "Enter password"
textField.layer.borderColor = UIColor.lightGray.cgColor
textField.layer.borderWidth = 1
textField.isSecureTextEntry = true
return textField
}()
Create TextField outlet and use following code. Say "nameTextField" has to add padding.
let paddingView = UIView(frame: CGRectMake(x: 0, y: 0, width: 30, height: 30))
nameTextField.leftView = paddingView
nameTextField.leftViewMode = .always
nameTextField.placeholder = "Enter Name"
You can add Image in paddingView.
Based on #Jorge Casariego's answer I came up with this solution.
You can set PaddedTextField class and the desired padding through the Interface Builder!
class PaddedTextField: UITextField {
#IBInspectable var padding: CGFloat = 0
override func textRect(forBounds bounds: CGRect) -> CGRect {
return CGRect(x: bounds.origin.x + padding, y: bounds.origin.y, width: bounds.width - padding * 2, height: bounds.height)
}
override func editingRect(forBounds bounds: CGRect) -> CGRect {
return CGRect(x: bounds.origin.x + padding, y: bounds.origin.y, width: bounds.width - padding * 2, height: bounds.height)
}
}
full code sample:
make sure your TextField points to RoundedTextField via Story board
import UIKit
class RoundedTextField: UITextField {
override func awakeFromNib() {
// add rounded corner
self.layer.cornerRadius = 15.0
self.clipsToBounds = false
super.awakeFromNib()
}
// For the padding from the left
override func textRect(forBounds bounds: CGRect) -> CGRect {
return CGRect(x: bounds.origin.x + 15.0, y: bounds.origin.y, width: bounds.width, height: bounds.height)
}
override func editingRect(forBounds bounds: CGRect) -> CGRect {
return CGRect(x: bounds.origin.x + 15.0, y: bounds.origin.y, width: bounds.width, height: bounds.height)
}
}

Resources