The collectionView shows cells without any problem except the spacing, some spacing are not equal to others, they are a little bit bigger than others. Even I set margin = 0, some spacing still comes out.
Here is the code:
let margin = 1
let cellSize = (size.width-margin*(cellsPerRow+1)) / cellsPerRow
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: margin, left: margin, bottom: margin, right: margin)
layout.itemSize = CGSize(width: cellSize, height: cellSize)
layout.minimumInteritemSpacing = margin
layout.minimumLineSpacing = margin
Thanks.
You need to define the cell size based on maximum (integer) width/height that fits your whole area, then take the "leftover" (=area_width_or_height - (cell_size*cell_amount) ) and divide it by two to get the size of margins you need to leave to left/right/top/bottom to make the grid even. Now you get your cells slightly random based on whether you round to lower or higher number.
Related
I'm using a selectionIndicatorImage for a UITabBar, which is 49 points high, like this: UITabBar.appearance().selectionIndicatorImage = UIImage(named: "bg-tab-selected")
Works just fine across all devices:
Except for the iPhone X:
I've tried setting the images to be vertically sliced only in the asset catalog, but that doesn't seem to have the desired effect. For some reason it also stretches horizontally? And there is a bit of padding on top.
Any ideas how I can fix this?
I had the same issue. I "fixed" it by subtracting the height by 1 pixel, so 48 pixels for the height of the selection image. It seems to be an iPhone X bug.
Adding 1 point to the top or bottom of your tabBar's selectionIndicatorImage Insets seems to "fix" this for now.
tabBar.selectionIndicatorImage?.resizableImage(withCapInsets: UIEdgeInsets.init(top: 1, left: 0, bottom: 0, right: 0))
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
In my app, for one screen, I am setting the size and centering the background of a SpriteKit node. For example, I'm setting the size of the background subview as follows:
backgroundNode.size = self.frame.size
While this is working on the iPhone 6 Plus, the smaller screen/lower resolution of the iPhone 5 means the default size of the other nodes makes is too large to fit within their scene.
How can I force other nodes conform to the size of the background node?
I wanted to divide each subview's size by the background subview's size, but math operations can't be done directly on the size property.
SpriteKit scenes (SKScene) contain nodes, nodes (SKNode), which have size and position properties (of type CGSize and CGPoint, respectively).
UIKit UIView.frame and bounds properties are a CGRect structs comprised of the same CGSize and CGPoint type structs.
So it really helps to understand how to work with CGRect, CGSize and CGPoint.
Be aware, CGRect, CGSize and CGPoint as structs, in Swift, are always passed by value to functions, not by references as classes are, so you can't modify fields inside the structs passed into a function, and have them propagate back to the caller's copy of the struct without taking extra steps.
Because size and position properties are compound types, you can't use them like scalars in simple in math and logic operations; as they contain multiple properties.
For example:
CGSize contains width and height properties,
CGPoint consists of x and y properties.
If want to divide size, you have to access width and height properties of the CGSize struct individually.
You can assign the size in one operation (i.e. single constructor):
node.size = CGSize(
width: node.size.width / backgroundNode.size.width,
height: node.size.height / backgroundNode.size.height)
Or you could do it discretely:
node.size.width = node.size.width / backgroundNode.size.width
node.size.height = node.size.height / backgroundNode.size.height
When dealing with CGRect fields, sometimes it's useful to deal with it as a single entity. For example,
view.frame = CGRect(x: 0, y: 0, width: 10, height: 10)
Others sometimes it's more practical to set size and origin properties separately:
view.frame.origin = CGPoint (x: 0, y: 0)
view.frame.size = CGSize (width: 10, height: 10)
or even:
view.frame.origin.x = 0
view.frame.origin.y = 0
view.frame.size.width = 10
view.frame.size.height = 10
It's also worth knowing about the "zero" static property of each of the struct, as convenient crisp shorthand equivalents:
CGRect .zero ... CGRect (x: 0, y: 0, width: 0, height: 0)
CGPoint.zero ... CGPoint (x: 0, y: 0)
CGSize .zero ... CGSize (width: 0, height: 0)
If you do a lot of adjusting of size and position, to reduce code bloat, you might consider borrowing or developing convenient Swift extensions to `CGRect, CGSize and CGPoint` to simplify applying delta values to sizes or origins.
I have a UIImageView as part of a UICollectionViewCell that I would like to use to visually display a quantity (like a progress bar). In this case the ImageView and its offset represent the percentage remaining of a given item represented by the cell.
Imagine an image of water inside a glass. When the glass is full you see all of the water texture. When the glass is half full, you see half of the water image. so on and so forth...
I want to adjust the top margin of the ImageView based on the percentage remaining. for example:
var image : UIImageView
var item = inventoriedItem(percentageRemaining : 100)
var pctLeft = item.percentageRemaining
pctLeft = 42
// PSEUDOCODE:
image.topMarginOffset = 100 - pctLeft
You could try adjusting the frame of the UIImageView based on the percentage left.
var image = UIImageView(frame: CGRect(x: 20, y: 10, width: 50, height: 100))
var pctLeft = 0.42
//assuming you want a vertical progress bar (like a glass of water).
image.frame = CGRect(x: 20, y: 10 + (100 * (1 - pctLeft)), width: 50, height: 100 * pctLeft)
Here I programmatically push the Y value down based on the reduced size of the bar. Let me know if this is what you were looking for...