I'm working on Swift 5 with Xcode 11.7 in a project. In here, I have a button and draw a rectangle around it. Everything is fine until I run it in iPhone 11 (11 pro, 11 pro max) simulator. Even I have set x,y of rectangle as same as the button's but they are skewed, other simulator didn't have this situation.
How can I fix this problem. Many thanks.
Question to me if it is not clear enough for you.
Here is my code to make a rectangle and make it around the button.
let rect = CGRect(x: btnSignIn2.frame.origin.x - 10, y: btnSignIn2.frame.origin.y + btnSignIn2.layer.bounds.height + 10, width: btnSignIn2.layer.bounds.width + 20, height: btnSignIn2.layer.bounds.height + 20)
let spotlight1 = AwesomeSpotlight(withRect: rect,
shape: .roundRectangle,
text: "message_please_login".localized(),
labelPosition: CGRect(x: 0, y: rect.maxY - btnSignIn2.layer.bounds.height + 25, width: UIScreen.main.bounds.width, height: 100),
isAllowPassTouchesThroughSpotlight: true)
The screenshot I put down here is the problem I have. The left side is iPhone11, and the other side is one of other simulator.
While I am learning Core Graphic by ray wenderlich,
one step is to transform UIBezierPath, var transform = CGAffineTransform(scaleX: 0.8, y: 0.8),
I do not know why the step after is right,which is transform = transform.translatedBy(x: 15, y: 30)?
I don't know how the x and y position is calculated out.
By printing the UIBezierPath currentPoint print(medallionPath.currentPoint), I thought the width should be (x1 - x2) * 0.5, the height should be y1 - y2, I really don't know why it is
(x: 15, y: 30)
The whole code is following , tested in Playground
let size = CGSize(width: 120, height: 200)
UIGraphicsBeginImageContextWithOptions(size, false, 0.0)
let context = UIGraphicsGetCurrentContext()!
//Gold colors
let darkGoldColor = UIColor(red: 0.6, green: 0.5, blue: 0.15, alpha: 1.0)
let midGoldColor = UIColor(red: 0.86, green: 0.73, blue: 0.3, alpha: 1.0)
let medallionPath = UIBezierPath(ovalIn: CGRect(x: 8, y: 72, width: 100, height: 100))
print(medallionPath.currentPoint)
// (108.0, 122.0)
print(medallionPath.bounds)
// (8.0, 72.0, 100.0, 100.0)
context.saveGState()
medallionPath.addClip()
darkGoldColor.setFill()
medallionPath.fill()
context.restoreGState()
// question
var transform = CGAffineTransform(scaleX: 0.8, y: 0.8)
// transform = transform.translatedBy(x: 15, y: 30)
medallionPath.lineWidth = 2.0
//apply the transform to the path
medallionPath.apply(transform)
print(medallionPath.currentPoint)
// (86.4, 97.6)
print(medallionPath.bounds)
// (6.4, 57.6, 80.0, 80.0)
medallionPath.stroke()
//This code must always be at the end of the playground
let image = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
transform = transform.translatedBy(x: 15, y: 30)
is a translation. It shifts the entire path to the right by 15 and down by 30. Your question is where did the magic numbers 15 and 30 come from.
The medallion drawing has a circle with dimensions 100 x 100 starting at position (8, 72) as established by this line of code:
let medallionPath = UIBezierPath(ovalIn: CGRect(x: 8, y: 72, width: 100, height: 100))
The code then adds an inner ring by scaling the original path by 0.8, so it will be an 80 x 80 circle. So that the center of this smaller ring lines up with the center of the bigger circle, it will need to be offset an additional 10 in both the horizontal and vertical directions. (The smaller circle is 20 smaller horizontally and vertically, so shifting it by 1/2 of 20 gets it to align properly). The goal then is to have it positioned at (18, 82) with width: 80, height: 80.
So, we need to apply a translation (a shift) in the X and Y directions, such that when the path is scaled we end up with a path anchored at (18, 82). The tricky bit is that the scaling gets applied to the shift values, so that has to be accounted for as well.
So, we are starting with an X position of 8, and we want to apply some translation value dx so that when the result is scaled by 0.8 we end up with the value 18:
(8 + dx) * 0.8 = 18
solving for dx:
dx = (18 / 0.8) - 8
dx = 14.5
Similarly for Y, we are starting with a Y position of 72 and want to apply a translation dy such that when it is scaled by 0.8 we end up with 82:
(72 + dy) * 0.8 = 82
solving for dy:
dy = (82 / 0.8) - 72
dy = 30.5
So, the mathematically correct translation is (14.5, 30.5):
transform = transform.translatedBy(x: 14.5, y: 30.5)
Ray Wenderlich rounded those to (15, 30) for some reason known only to them (because the round numbers look better in the code perhaps?). It's possible that they didn't bother to do the math and just tried values until it looked right.
here scale is 0.8 means 80% of the current so its x, y, width and height all reduce to 80%
so new scale difference is
scaleDifference = ((1/ 0.8) - 1.0) * 100 = 25%
now total size difference is 0.25, here inner circle is in centre so centre point does not change so its x and y position change to calculate x and y
here path rect is (8, 72, 100, 100)
so formula to calculate
circle reduce 10% from both side, to keep it in centre needs to increase 10% x and y and reduce 10% in width and height so circle will be in centre
here scale is set to 80% so what ever x and y translation we are giving all will be calculated to 80%, for example if we give translate x = 10 and y = 10 system converts to its 80% so x = 8 and y = 8.
we have to add width difference to the x and y to keep it in centre
width and height is 100 so
100 * (scaleDifference / 2.0)
100 * (0.25 / 2.0) = 12.5
and due to scaling x and y also reduce to 0.8% so to make it 100% is
xDifference = 8 * scaleDifference = 2.0
yDifference = 72 * scaleDifference = 18.0
to keep circle in centre we have to add width difference with dx and height difference with dy to get final x and y translation value
dx = xDifference + widthDifference = 2.0 + 12.5 = 14.5
dy = yDifference + heightDifference = 18.0 + 12.5 = 30.5
How do i add spacing between each cell here -
for i in 0...50 {
let cell = UIView()
cell.backgroundColor = .lightGray
cell.frame = CGRect(x: Double(i) * Double(32.52), y: 90, width: 350, height: 500)
view.addSubview(cell)
}
Because with the code above the view looks like this
Your cells are much too wide for the increment you're using horizontally. Your increment offsets them by 32.52 (why the fractional part?) and the views have a width of 350.
So your view spans will be:
From X up to
------ -----
0 350
32.52 403.52 (overlapping from 32.53 to 350)
65.04 456.04 (overlapping from 65.04 to 403.52)
and so on ...
You probably meant to use a narrower frame width (or a larger increment).
The spacing will be the difference between your increment and the frame width.
For example: an increment of 32 with a width of 30 will give you a 2 pixel gap between views.
I'm setting my button's title with this line of code:
self.timerButton.setTitle(String(Int(duration)), for: .normal)
The button is as large as 1/3 of the screen, the text size is 60, this was fine in my previous projects, but now with the value of duration changes ( from 120 ~ 0 ), the text often shows ... instead, sometimes even half of a number, what's wrong with this?
Here are the constraints shown in the debugger:
Try this it may help you :
self.timerButton.titleLabel?.adjustsFontSizeToFitWidth = true
#Deny's comment is very helpful, I looked into my constraints and found out I set the button's image size with this method:
self.contentEdgeInsets = UIEdgeInsets(top: (self.frame.height - imageSize) / 2, left: (self.frame.width - imageSize) / 2, bottom: (self.frame.height - imageSize) / 2, right: (self.frame.width - imageSize) / 2)
which cause the titleLabel's size to be smaller than it should be, so I changed the above code to this:
self.imageEdgeInsets = UIEdgeInsets(top: (self.frame.height - imageSize) / 2, left: (self.frame.width - imageSize) / 2, bottom: (self.frame.height - imageSize) / 2, right: (self.frame.width - imageSize) / 2)
then it worked.
TL;DR
The problem is caused by constraints.
Not a perfect solution but setting a width constraint forces the button to not scale down too much, like so:
myButton.translatesAutoresizingMaskIntoConstraints = false
myButton.widthAnchor.constraint(greaterThanOrEqualToConstant: 180).isActive = true
I'm trying to set my buttons and images to be in a specific spot on all Iphone screen sizes. Normally I would use CGPoint(width: self.frame.width, height: self.frame.height) , but in buttons you use .Frame which is different, and I write .frame = CGRect(x: self.frame.width / 7.7, y: self.frame.height / 2.6, width: self.frame.width / 10, height: self.frame.height / 12)
, but it works on one screen for say iphone 6, but then on a iphone 5 it is in a different spot... any suggestions??