I try to create a dynamic cell column from different iPhone devices with collectionView.
I already try for iPhone SE to have a 3 column and success, but when I try to make iPhone 11 Pro Max to have a 4 column it have a space between each cell.
iPhone 11 Pro Max
iPhone SE
I calculate my cell like this
enum UIHelper {
static func createCollectionViewFlowLayout() -> UICollectionViewFlowLayout {
let screenWidth = UIScreen.main.bounds.width
let padding: CGFloat = 12
let minimumInterimSpacing: CGFloat = 10
let availableWidth = screenWidth - (padding * 2) - (minimumInterimSpacing * 2)
var numberOfColumn: CGFloat
// 375 is iPhone SE width
if screenWidth > 375 {
numberOfColumn = 4
} else {
numberOfColumn = 3
}
let itemWidth = availableWidth / numberOfColumn
let flowLayout = UICollectionViewFlowLayout()
flowLayout.sectionInset = UIEdgeInsets(top: padding, left: padding, bottom: padding, right: padding)
flowLayout.itemSize = CGSize(width: itemWidth, height: itemWidth)
return flowLayout
}
}
and in my view controller I create it like this
override func viewDidLoad() {
super.viewDidLoad()
collectionView.delegate = self
collectionView.dataSource = self
collectionView.collectionViewLayout = UIHelper.createCollectionViewFlowLayout()
}
what am I missing?
Your setup seems to be fine, The issue seems to be with the logic / math in this line
let availableWidth = screenWidth - (padding * 2) - (minimumInterimSpacing * 2)
The logic is that if you have 3 cells in a row, there will be 2 gaps between the 3 cells, but if you have 4 cells in a row, you will have 3 gaps.
So if I change the available width also based on the number of cells I intend to have, you will get the desired results. So I have made some small changes to change the available width based on how many cells you want in a row.
I have made some minor edits to your code, I have included some comments to show what I have changed, however, you will need to organize my updates better as I made quick changes to show you the fix in the logic.
static func createCollectionViewFlowLayout() -> UICollectionViewFlowLayout {
let screenWidth = UIScreen.main.bounds.width
let padding: CGFloat = 12
let minimumInterimSpacing: CGFloat = 10
// Updated this to a var
var availableWidth = screenWidth - (padding * 2) - (minimumInterimSpacing * 2)
var numberOfColumn: CGFloat
// 375 is iPhone SE width
if screenWidth > 375 {
numberOfColumn = 4
// Update the width available as well
availableWidth = screenWidth - (padding * 2) - (minimumInterimSpacing * (numberOfColumn - 1))
} else {
numberOfColumn = 3
}
let itemWidth = availableWidth / numberOfColumn
print(numberOfColumn)
let flowLayout = UICollectionViewFlowLayout()
flowLayout.minimumInteritemSpacing = minimumInterimSpacing
flowLayout.sectionInset = UIEdgeInsets(top: padding, left: padding, bottom: padding, right: padding)
flowLayout.itemSize = CGSize(width: itemWidth, height: itemWidth)
return flowLayout
}
Related
I need to add a text watermark to the image.
The height of the text varies with the height of the image.
Now I know the height of the image, and I know the height of the text.
How do I know the font size of the text?
In short, how to determine the font size of the text from the height?
Now my solution is as follows. Does anyone have a better way?
Thanks!!!
/// - Parameter height: target height for font
func textFontSize(from height: CGFloat) -> CGFloat {
var fontSize: CGFloat = 30
var textFont = UIFont.systemFont(ofSize: fontSize)
while (textFont.lineHeight < (height * 4 / 5) ||
textFont.lineHeight > height){
//decrease font size
if textFont.lineHeight > height {
fontSize = fontSize - 0.5
// increase
}else if textFont.lineHeight < (height * 4 / 5) {
fontSize = fontSize + 0.5
}
textFont = UIFont.systemFont(ofSize: fontSize)
}
return fontSize
}
The correct way has been tested
/// - Parameter height: target height for font
func textFontSize(from height: CGFloat) -> CGFloat {
let defaultSize: CGFloat = 30
let defaultFont = UIFont.systemFont(ofSize: defaultSize)
let boundSize = self.size(withAttributes: [NSAttributedString.Key.font : defaultFont])
let pointsPerPixel = defaultFont.pointSize / boundSize.height
let desiredPointSize = height * pointsPerPixel
return desiredPointSize
}
I am working on a crossword app but I keep missing something when I calculate each itemSize of the UICollectionView. I get the right size for iPhone SE but the wrong size for iPhone XR. What am I doing wrong?
func setLayout() -> UICollectionViewFlowLayout {
let layout = UICollectionViewFlowLayout()
layout.itemSize = getCellSize()
layout.minimumInteritemSpacing = 0
layout.minimumLineSpacing = 0
layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
return layout
}
func getCellSize() -> CGSize {
let width:CGFloat = self.view.frame.width/CGFloat(crossWordData[0].count)
let height:CGFloat = (self.view.frame.height - TitleView.frame.height)/CGFloat(crossWordData.count) - cellsBorderWidth
//cellsBorderWidth = 1.2
let cellSize = CGSize(width:width , height:height)
return cellSize
}
This is because self.view ends where is bottom of the display. New iPhones (X, Xs, Xs Max, Xr) have on the bottom this place for "home gesture". So for your calculation, content of your CollectionView is bigger than CollectionView because your CollectionView has bottom constraint equal to safe area bottom constraint which is for new iPhones higher than where bottom of the display is. So when you need width and height instead of this
let width:CGFloat = self.view.frame.width/CGFloat(crossWordData[0].count)
let height:CGFloat = (self.view.frame.height - TitleView.frame.height)/CGFloat(crossWordData.count) - cellsBorderWidth
call this
let width:CGFloat = self.yourCollectionView.frame.width/CGFloat(crossWordData[0].count)
let height:CGFloat = self.yourCollectionView.frame.height/CGFloat(crossWordData.count) - cellsBorderWidth
Eventually this is how I changed my code -
let width:CGFloat = self.view.frame.width/CGFloat(crossWordData[0].count)
let height:CGFloat = self.view.frame.height*0.85/CGFloat(crossWordData.count)
The collections view height is 85% in the screen layout
I have an images that are 182x150 and I set the collection cell to that and made sure it can contain rows of 2 images. But when I run the simulator, the rows only have 1 image. I don't know if it's my code or that I need to resize my image.
let itemSize = UIScreen.main.bounds.width/2 - 2
let layout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 6, left: 4, bottom: 6, right: 4)
layout.minimumInteritemSpacing = 4
layout.minimumLineSpacing = 4
layout.itemSize = CGSize(width: itemSize , height: itemSize)
myCollectionView.collectionViewLayout = layout
Looks like you just need to include section insets in your itemSize calculation
// 8 for left and right section insets, 4 for item spacing.
let availableWidth = view.bounds.width - 8 - 4
let itemSize = availableWidth / 2
I'm creating label and characters, I want set frame (X, Y and width) of UILabel by characters and Y-axis is constant of all devices, so how can I set center of X-axis and controlling by count of characters, and width (50) gets smaller and bigger per device ??
This my code :
func createTarget(id: Int) {
listdata = dbHelpr.getDatabase(rowId: id)
for data in listdata {
let lengthOfChar : CGFloat = data.ans.length
let targetSize : CGFloat = self.view.frame.width / 2
var xAxis : CGFloat = self.view.frame.width / 2 + 55
let yAxis : CGFloat = self.view.frame.height / 2 + 70
let targetLabel = UILabel(frame: CGRect(x: xAxis, y: yAxis, width: 50, height: 5))
xAxis -= 50 + (lengthOfChar)
}
}
In this picture is my label its position is center of X-axis of iPhone 7 plus simulator and numbers of label it's per count of characters, so I want like this position (X, Y and width) in all devices and width gets smaller and biggest and if count of characters for example is 9 it's must be on center of X-axis and width must be gets smaller little and spaces right and left of device.
How can I do it ?!
Thank you :)
This is the solution :
func createTarget(id: Int) {
listdata = dbHelpr.getDatabase(rowId: id)
for data in listdata {
let lengthOfChar : CGFloat = data.ans.length
let yAxis : CGFloat = self.view.frame.height / 2 + 70
let width: CGFloat = view.frame.size.width - 40 // frame width
var targetWidth: CGFloat = (width - (lengthOfChar - 1) * 5) / lengthOfChar
if targetWidth > 50 {
targetWidth = 50
}
let totalWidth: CGFloat = (targetWidth * lengthOfChar) + ((lengthOfChar - 5) * 5)
for (indexTar, tar) in data.ans.characters.enumerated() {
let x : CGFloat = (width / 2) - (totalWidth / 2)
let xx : CGFloat = (CGFloat(indexTar) * targetWidth) + (CGFloat(indexTar) * 5) + 20
var xAxis : CGFloat = (x + xx)
xAxis = width - xAxis
let targetLabel = UILabel(frame: CGRect(x: xAxis, y: yAxis, width: targetWidth, height: 5))
targetLabel.backgroundColor = .white
targetLabel.layer.masksToBounds = true
targetLabel.layer.cornerRadius = 5
targetLabel.text = String(describing: tar)
targetLabel.textAlignment = .center
targetLabel.textColor = .white
self.view.addSubview(targetLabel)
}
}
}
So the problem which I have is, the collection view, depending on what simulator I am using it displays either 3(iPhone 5) columns in one setting or 4 columns(iPhone 6) in another. I want the collection view to always displays 4 columns no matter how big or small the screen is. Here is some code I am using so far:
override func viewDidLoad() {
super.viewDidLoad()
let screenWidth = UIScreen.mainScreen().bounds.size.width
let screenHeight = UIScreen.mainScreen().bounds.size.height
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 20, left: 10, bottom: 10, right: 10)
layout.itemSize = CGSize(width: 100, height: 80)
collview1 = UICollectionView(frame: CGRectMake(0, 0, screenWidth, screenHeight), collectionViewLayout: layout)
[collview1.reloadData];
}
You'll want to change your layout.itemSize to a calculated value.
Something like:
layout.itemSize = CGSize(width: (screenWidth - spacing) / numberOfColumns, height: desiredHeight)
Spacing would be the total inter item spacing in a row plus the left and right insets.
DesiredHeight should probably be a calculated value to maintain the aspect ratio of your cells between devices.
Hopefully that's helpful.