swift collection view resizing problems - swift

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.

Related

Dynamic collection view cell column from different iPhone device

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
}

Collection Views: Not fitting

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

How to set spacing between collectionview cells in Swift 3?

currently i am using swift 3 and storyboard, googled everything and looked over all stackoverflow similar questions, got nothing so far.
On my example Porject,
my Collection view looks like this
Simulator Screenshot
which is not what i want, i want a grid layout with no spacing at all, i edited the storyboard values ddin't got anything there, so for that i used this code
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
let width = UIScreen.main.bounds.width
layout.sectionInset = UIEdgeInsets(top: 0, left: 5, bottom: 0, right: 5)
layout.itemSize = CGSize(width: width / 2, height: width / 2)
layout.minimumInteritemSpacing = 0
layout.minimumLineSpacing = 0
collectionView!.collectionViewLayout = layout
didn't work either :(
'if let layout = self.collectionView.collectionViewLayout as? UICollectionViewFlowLayout{
let width = UIScreen.main.bounds.width
layout.sectionInset = UIEdgeInsets(top: 0, left: 5, bottom: 0, right: 5)
layout.itemSize = CGSize(width: width / 2, height: width / 2)
layout.minimumInteritemSpacing = 0
layout.minimumLineSpacing = 0
}'

Padding around UIImageView. Swift 3

I have a UIImageView, where I don't want the image to 'touch' the edge of the view, rather have some 'padding' around it. However, I have tried the following, and for some reason it doesnt change:
#IBOutlet weak var pictureOutletOne: UIImageView!
//set the image
pictureOutletOne.image = UIImage(named: itemOne)
//set the padding
pictureOutletOne.layoutMargins = UIEdgeInsetsMake(10, 10, 10, 10);
I have also tried:
pictureOutletOne.translatesAutoresizingMaskIntoConstraints = false
pictureOutletOne.layoutMargins = UIEdgeInsets(top: 10, left: 100, bottom: 10, right: 0)
I have read alot about this, but these are the solutions I have found, but they aren't working. Using Swift 3.
Thanks so much.
Swift 4.2 & 5
let imageView = UIImageView()
imageView.image = UIImage(named:
"image")?.withAlignmentRectInsets(UIEdgeInsets(top: -5, left: -5, bottom: -5,
right: -5))
Insets should be given in negative value
You can insert the imageView into a view and set constraints to sides, guaranteed approach :)
Override the alignmentRectInsets property in a new class:
class PaddedImageView: UIImageView {
override var alignmentRectInsets: UIEdgeInsets {
return UIEdgeInsets(top: -10, left: -10, bottom: -10, right: -10)
}
}
Swift 5.4 & Xcode 13
Here is a little helper extension I build:
extension UIImage {
func addPadding(_ padding: CGFloat) -> UIImage {
let alignmentInset = UIEdgeInsets(top: -padding, left: -padding,
bottom: -padding, right: -padding)
return withAlignmentRectInsets(alignmentInset)
}
}
let padding: CGFloat = 10
myImageView.contentMode = .scaleAspectFill
myImageView.image = UIImage(named: "myImage.png").resizableImage(withCapInsets: UIEdgeInsets(top: padding, left: padding, bottom: padding, right: padding), resizingMode: .stretch)
Swift 5
Adds padding to right and left of an image place in an image view.
let image = UIImage(systemName: "circle.fill")
let insets = UIEdgeInsets(top: 0, left: -15, bottom: 0, right: -15)
let imageView = UIImageView(image: image.withAlignmentRectInsets(insets))
Note: UIStackView honors alignment insets as contributors to an image view's intrinsic content size.
Use case example:
In my application, I have a vertical stack comprised of a small center-aligned UILabel stacked above a UIImageView in a UITableViewCell. Label width varies from cell to cell, varying respective vertical stack widths and shifting images' respective horizontal alignments. I.e. the images don't line up in the table.... By padding images with horizontal alignment insets, it forces vertical stack to have a consistent width greater than max expected label width, keeping images center-aligned vertically in the table.

Adding view controller in scrollview

I am currently working on an app that has been developed using storyboards.
I am trying to add a view controller programmatically into a paging scroll view at the beginning before 2 other views that are already added within the storyboard.
The view controller gets added but the width is slightly larger and goes across into the middle view.
let vc = Vc()
scrollView.addSubview(vc.view)
You have to assign a contentSize to the scrollview and a position for the frame of the ViewController
scrollView.contentSize = CGSize(width: 2 * view.frame.width, height: scrollView.frame.height)
let frameVC = CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height)
vc.view.frame = frameVC
vc.willMoveToParentViewController(self)
self.addChildViewController(vc)
vc.didMoveToParentViewController(self)
scrollView.addSubview(vc.view)
Note that you have to change the frameVC to match your requirements
Swift 5 sytax update
scrollView.contentSize = CGSize(width: 2 * view.frame.width, height: scrollView.frame.height)
let frameVC = CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height)
vc.view.frame = frameVC
vc.willMove(toParent: self)
addChild(vc)
vc.didMove(toParent: self)
scrollView.addSubview(vc.view)
Note: Frames vs Constraint layout
Instead of using a frame you can also use create a constraint layout to add a UIView to a UIScrollView
scrollView.contentSize = CGSize(width: 2 * view.frame.width, height: scrollView.frame.height)
scrollView.addSubview(vc.view)
vc.view.translatesAutoresizingMaskIntoConstraints = false
// add constrains here
vc.willMove(toParent: self)
addChild(vc)
vc.didMove(toParent: self)