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
}'
Related
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
}
I'm trying to align vertically a text in a view.
For this, I call contentInset function, like this:
override func alignCenterVertical() {
let fittingSize = CGSize(width: bounds.width, height: CGFloat.greatestFiniteMagnitude)
let size = sizeThatFits(fittingSize)
let topOffset = (bounds.size.height - size.height * zoomScale) / 2
let positiveTopOffset = max(1, topOffset)
contentInset = UIEdgeInsets(top: positiveTopOffset, left: 0, bottom: 0, right: 0)
}
But this only work when the value "positiveTopOffset" is negative. (reverse that I want)
I want exactly this comportment but with "positiveTopOffset" positive, like in this part of code here.
When I let the code like this, with "positiveTopOffset" positive, nothing append. Why?
thanks a lot!
I finally found the problem.
I have to add isScrollingEnable = true, like this:
override func alignCenterVertical() {
let fittingSize = CGSize(width: bounds.width, height: CGFloat.greatestFiniteMagnitude)
isScrollingEnabled = true
let size = sizeThatFits(fittingSize)
let topOffset = (bounds.size.height - size.height * zoomScale) / 2
let positiveTopOffset = max(1, topOffset)
contentInset = UIEdgeInsets(top: positiveTopOffset, left: 0, bottom: 0, right: 0)
}
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
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.
I'm trying to make a UIButton that has a UIImage on either side (left and right) of the button's title. Ideally, the images would be pinned to the left and right sides of the button, and the title would be centered, but I can live with the images being right next to the title label I suppose. I have been able to add one image, which appears right before the title, but how would I add a second?
I know this is an old question but since no code was provided and someone asked for it I figured I would share my solution for this.
What I did was create a new class which subclasses a UIButton. I made sure that you can see all the changes you do instantly in your interface builder as well. So you can just drag in a UIButton. Specify the class to your own class and it will allow you to set the images and see it being drawn instantly
Here is what I did to achieve this
import UIKit
#IBDesignable
class AddProfilePictureView: UIButton {
#IBInspectable var leftHandImage: UIImage? {
didSet {
leftHandImage = leftHandImage?.withRenderingMode(.alwaysOriginal)
setupImages()
}
}
#IBInspectable var rightHandImage: UIImage? {
didSet {
rightHandImage = rightHandImage?.withRenderingMode(.alwaysTemplate)
setupImages()
}
}
func setupImages() {
if let leftImage = leftHandImage {
self.setImage(leftImage, for: .normal)
self.imageView?.contentMode = .scaleAspectFill
self.imageEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: self.frame.width - (self.imageView?.frame.width)!)
}
if let rightImage = rightHandImage {
let rightImageView = UIImageView(image: rightImage)
rightImageView.tintColor = COLOR_BLUE
let height = self.frame.height * 0.2
let width = height
let xPos = self.frame.width - width
let yPos = (self.frame.height - height) / 2
rightImageView.frame = CGRect(x: xPos, y: yPos, width: width, height: height)
self.addSubview(rightImageView)
}
}
}
I would break it into two buttons within a collection view- it's very flexible and can work great for something like this.
Add a UIImageView with an image to the button by addSubview and another to the button by setImage, it can be adjusted with titleEdgeInsets and imageEdgeInsets.
if you need a code sample – let me know.
Hope it helps!
Swift 5, XCode 11.6
Please use the below code in your extension or in a custom UIButton class. I have used the below code in my custom class. The function will set left or right image respectively and align the text.
/// Sets a left and right image for a button
/// - Parameters:
/// - right: right image
/// - left: left image
func setImages(right: UIImage? = nil, left: UIImage? = nil) {
if let leftImage = left, right == nil {
setImage(leftImage, for: .normal)
imageEdgeInsets = UIEdgeInsets(top: 5, left: (bounds.width - 35), bottom: 5, right: 5)
titleEdgeInsets = UIEdgeInsets(top: 0, left: 10, bottom: 0, right: (imageView?.frame.width)!)
contentHorizontalAlignment = .left
}
if let rightImage = right, left == nil {
setImage(rightImage, for: .normal)
imageEdgeInsets = UIEdgeInsets(top: 5, left: 5, bottom: 5, right: (bounds.width - 35))
titleEdgeInsets = UIEdgeInsets(top: 0, left: (imageView?.frame.width)!, bottom: 0, right: 10)
contentHorizontalAlignment = .right
}
if let rightImage = right, let leftImage = left {
setImage(rightImage, for: .normal)
imageEdgeInsets = UIEdgeInsets(top: 5, left: 5, bottom: 5, right: (bounds.width - 35))
titleEdgeInsets = UIEdgeInsets(top: 0, left: (imageView?.frame.width)!, bottom: 0, right: 10)
contentHorizontalAlignment = .left
let leftImageView = UIImageView(frame: CGRect(x: bounds.maxX - 30,
y: (titleLabel?.bounds.midY)! - 5,
width: 20,
height: frame.height - 10))
leftImageView.image?.withRenderingMode(.alwaysOriginal)
leftImageView.image = leftImage
leftImageView.contentMode = .scaleAspectFit
leftImageView.layer.masksToBounds = true
addSubview(leftImageView)
}
}
Usage:
vegaButton.setImage(right: myImage) // for right image
vegaButton.setImage(left: myImage) // for left image
vegaButton.setImage(right: myImage, left: myImage) // for both images.