I have a gridlist that looks like this
class ListViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout{
private var collection: ACollection?
private var collectionViewLayout:UICollectionViewFlowLayout?
override func loadView() {
super.loadView()
collectionViewLayout = UICollectionViewFlowLayout()
collectionViewLayout?.itemSize.width = 128
collectionViewLayout?.itemSize.height = 227
view = UICollectionView(frame: CGRect.zero, collectionViewLayout: collectionViewLayout!)
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let someObj: SomeObj = collection!.getObject(index: indexPath.item)
let cell: UICollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: NSStringFromClass(UICollectionViewCell.self), for: indexPath as IndexPath)
let cellView: UIImageView = UIImageView(image: object.image)
cellView.frame = cell.bounds
cell.contentView.addSubview(cellView)
return cell
}
I would like my cells to have different aspect ratios though depending on a value in someObj. How can I resize the cells without them overlapping? I have tried to make
cellView.frame = CGRect(x:0,y:0,width:100,height:300)
cellView.frame =cell.bounds
but the cells overlap.
Maybe I'll elaborate a little more about the problem.
First, if you implement collectionView(_:layout:sizeForItemAt:) method, you don't need to specify the following:
collectionViewLayout?.itemSize.width = 128
collectionViewLayout?.itemSize.height = 227
which is a default size for every cell.
Second, overlaps you see on top of every default cell are probably the cellViews (UIImageViews) that you are adding on reused cells. The problem is, you're trying to add UIImageView on the current cell every single time delegate asks for the cell. You'll need to check if the UIImageView is already there, since the entire cell may have been reused still having the image view which added previously.
Related
I am building a TVOS app where I have this collectionView:
The current cell (The cell which has scrolled to), gets highlighted in Orange.
For example, here the user scrolls to the third cell:
WHAT I AM TRYING TO ACHIEVE:
When the user scrolls to another cell, I want the Orange square, to remain in the first cell, and the whole collection to scroll to the left(or to the right if the user is scrolling in the opposite direction.
And I honestly have no idea how to achieve this, or what should I use exactly.
Should I embed the whole collection view inside of a scrollView?
Anyway, here's how implemented that collection view:
extension MoviesViewController2: UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
print("first function collectionView detected")
return items2.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier:
cellIdentifier, for: indexPath) as! movieCardCell
cell.movieImageView.sd_setImage(with: URL(string: items2[indexPath.item].imageURL))
return cell
}
// Handle collectionViewItem selection
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("didSelectItem\(indexPath)")
}
// Highlight the current cell
func collectionView(_ collectionView: UICollectionView, didUpdateFocusIn context: UICollectionViewFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) {
if let pindex = context.previouslyFocusedIndexPath, let cell = collectionView.cellForItem(at: pindex) {
cell.contentView.layer.borderWidth = 0.0
cell.contentView.layer.shadowRadius = 0.0
cell.contentView.layer.shadowOpacity = 0.0
}
if let index = context.nextFocusedIndexPath, let cell = collectionView.cellForItem(at: index) {
cell.contentView.layer.borderWidth = 8.0
cell.contentView.layer.borderColor = UIColor.orange.cgColor
cell.contentView.layer.shadowColor = UIColor.orange.cgColor
cell.contentView.layer.shadowRadius = 10.0
cell.contentView.layer.shadowOpacity = 0.9
cell.contentView.layer.shadowOffset = CGSize(width: 0, height: 0)
collectionView.scrollToItem(at: index, at: [.centeredHorizontally, .centeredVertically], animated: true)
}
}
}
If anyone can answer the question above, it'd be great. Also any tip or what I should use is most welcome.
As I understand, you want the orange rectangle to remain always on the same place. When scrolling you can make it disappear and re-appear once the scrolling has stopped maybe but that's a detail.
So you could put a UIView with the same dimensions as a cell (since all seem to have the same height and width) and make it appear once the user has stopped scrolling.
Anyway I'm looking again at your question and I think I didn't understand your issue correctly, specifically this part The current cell (The cell which has scrolled to), gets highlighted in Orange. in combination with this When the user scrolls to another cell, I want the Orange square, to remain in the first cell
The process might be as follows:
Set your collectionView's size to single cell size. And align it to the left
Make your collectionView's clipsToBounds property to false
Make UICollectionView paging enabled.
Place a rectangle view on top of your collectionView
I have a Table View with 4 cells. In cell 3 & 4 I have a collection view. I am trying to setup the collection view in Table View Cell 4, however for some reason whatever device I select in the interface builder is what get's referenced when I try to set the cell size.
In the TableViewController I have this code:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let flowLayout = collectionViewLayout as! UICollectionViewFlowLayout
let totalSpace = flowLayout.sectionInset.left
+ flowLayout.sectionInset.right
+ (flowLayout.minimumLineSpacing * 3)
let size = (collectionView.frame.width - totalSpace) / 4
return CGSize(width: size, height: 166)
}
Divide the cells into 4 with a height of 166. However, the collection view.frame.width is NOT referencing the actual collection view, it's referencing whatever the size was in interface builder.
When run, the cell size is dependant on the collectionview.frame.width, and that value, is wrong.
I have tested this both on the simulator and a device.
Not sure what's going on here?
UPDATE:
I've identified what's causing the issue, but not sure how to fix it. I'm setting the collection view's height constraint based on the content height size:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let topCell = tableView.dequeueReusableCell(withIdentifier: "topCell", for: indexPath)
switch indexPath.section {
case 1:
return secondCell
case 2:
let collectionViewCell = tableView.dequeueReusableCell(withIdentifier: "matchesCell", for: indexPath) as! collectionViewCellCustomClass
let height = collectionViewCell.collectionView.collectionViewLayout.collectionViewContentSize.height
collectionViewCell.heightConstant.constant = height
self.view.setNeedsLayout()
return collectionViewCell
default:
return topCell
}
}
This tells the collection view height to be whatever the height is of it's content. I set this in the tableView cell. However, whenever I remove this bit of code, the cell sizing works fine?
Problem was solved. Really simply actually:
If I set: collectionView.reloadData() it fixes it!
I want to have oval shaped collection cells with width based on the label/text length, but I am having trouble making all the cells look oval. I don't know how to resize based on the label's text length.
I am essentially trying to get something like the blank/pink picture below I saw on another post but the solution didn't work. I have also added what my view controller currently looks like.
1) How do I resize to get oval shape correctly and also 2) why are there longer spaces between some cells and how do I fix that?
Ideal Pic
Current Controller
Storyboard cell
(width of label is set to 150)
class HobbiesViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate{
#IBOutlet weak var collectionView: UICollectionView!
var items = ["karateeeeeeeeeee", "signup", "last", "madur", "open", "somelongword", "nice", "looooooooong", "karate", "karate","karate", "signup", "last", "madur"]
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.items.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "hobbyCell", for: indexPath) as! HobbiesViewCell
cell.label.text = self.items[indexPath.item]
cell.backgroundColor=UIColor.blue //try with different values untill u get the rounded corners
cell.layer.cornerRadius = cell.bounds.size.height / 2
cell.layer.masksToBounds=true
return cell
}
}
extension HobbiesViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "hobbyCell", for: indexPath) as! HobbiesViewCell
cell.label.text = items[indexPath.row]
cell.label.sizeToFit()
return CGSize(width: cell.label.frame.width + 10 , height: 70)
}
}
Ans 1. While setting the width of the collection view cell you need to have some minimum width for the cell so that the cell does not get so small that it looks like a circle. Your current height is 70 so that you should keep a condition that if the cell.label.frame.width + 10 is less than 160 then keep the size of the cell as 160.
Ans 2. Collection view itself manages the spacing between the cells according to the frame provided to collection view and the sized to the cell. To set the spacing right may be below link will be helpful to you.
Cell spacing in UICollectionView
From screen shot I can see that your font size also differs from the expected output so may be you can check that also.
Hope this helps you in some way.
I have collection view cells that contain a subview of which I am trying to get the frame of in relation to the superview.
So far, I've managed to successfully get the frame of the subview, however for the first x amount of visible cells, the returned frame is always (0,0,0,0).
After I scroll them out of view and scroll back to those x cells, the returned frame is fine and the frames for the subviews are computed properly.
Any thoughts?
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let window = UIApplication.shared.keyWindow
let selectedCell = self.collectionView(self.cellCollectionView, cellForItemAt: indexPath) as! postCell
let photoItem = selectedCell.photo
let photoItemPosition = photoItem.frame
let convertedFrame = selectedCell.convert(photoItemPosition, to: window)
print(photoItemPosition)
print(convertedFrame)
}
You have to update the frame of photo instance in layoutSubviews.
Override the layoutSubviews in your collectionView cell class
override func layoutSubviews ()
{
super.layoutSubviews()
//Set the self.photo frame
}
Have been having this issue that I considered to be an easy solve, but spent a lot of time cracking it with no result.
So, I have a UIViewController with UICollectionView in it. This collection is padded 75 px from the top and has cells with pretty simple setup - just 1 UIImageView set to fit the size of the container. Everything is made with AutoLayout.
My task is to make UIImageView go full screen on tap. What I am doing is making a temporary UIImageView and add to the hierarchy of UIViewController view.
The problem I am facing is I can't get the absolute frame of UIImageView in the cell I tap.
I tried various ways to calculate the frame, my most recent try is
var rect = cell.imageView.superview!.convertRect(cell.imageView.frame, toView: self.view)
However, it returns result that seems to be ignoring the collection view top constraint.
Update:
It turns out my problem was in the wrong way I was acquiring the cell from collection view. Instead of:
let cell = collectionView.cellForItemAtIndexPath(indexPath) as! UIImageCollectionViewCell
I was getting cell with
let cell = self.collectionView(collectionView, cellForItemAtIndexPath: indexPath) as! UIImageCollectionViewCell
Which obviously resulted in creating a new cell with the wrong frame. My bad, late night coding is not the best thing sometimes. Thanks to Arun Ammannaya for the quick example
This what i tried, works as expected.
class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
#IBOutlet var collectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
return collectionView.dequeueReusableCellWithReuseIdentifier("aaa", forIndexPath: indexPath)
}
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 10
}
#IBAction func frame(sender: AnyObject) {
print(String(sender.frame))
let rect = sender.superview??.convertRect(sender.frame, toView: self.view)
print(String(rect))
let addedView = UIView()
view.addSubview(addedView)
addedView.frame = rect!
addedView.backgroundColor = UIColor.yellowColor()
}
}
Story board looks like:
Output is looks like: