Programmatically fill UIImageView with UIImage and place in UICollectionViewCell - ios

I have been trying to fill in a UIImageView with a UIImage (car system image). I have tried numerous solutions online but can not seem to have it fill the UICollectionViewCell, awkward spacing seen here:
I figured since the UIView is the size of the UICollectionViewCell as seen here:
It must be the image is not scaling to the view. So I modified the content mode to scale to fill of the image view when creating the cells for the collection view, then adding this image view into the collection view cell:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CarCell", for: indexPath)
let carImageView = UIImageView(image: UIImage(systemName: "car"))
carImageView.contentMode = .scaleToFill
cell.addSubview(carImageView)
return cell
}
This doesn't seem to have any effect (even when using .bottom for the content mode the image does not move), but looking in the view hierarchy it seems this is what should be fixing it.
Does anyone know what I may be doing wrong?
Here is the storyboard:
Update:
I have added constraints to the image view with this code:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CarCell", for: indexPath)
let carImage = UIImage(systemName: "car")
let carImageView = UIImageView(image: carImage)
carImageView.contentMode = .scaleToFill
cell.addSubview(carImageView)
carImageView.topAnchor.constraint(equalTo: cell.topAnchor).isActive = true
carImageView.bottomAnchor.constraint(equalTo: cell.bottomAnchor).isActive = true
carImageView.leftAnchor.constraint(equalTo: cell.leftAnchor).isActive = true
carImageView.rightAnchor.constraint(equalTo: cell.rightAnchor).isActive = true
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let columns: CGFloat = 2
let collectionViewWidth = collectionView.bounds.width
let flowLayout = collectionViewLayout as! UICollectionViewFlowLayout
let spaceBetweenCells = flowLayout.minimumInteritemSpacing * (columns - 1)
let adjustedWidth = collectionViewWidth - spaceBetweenCells
let width: CGFloat = floor(adjustedWidth / columns)
let height: CGFloat = width
return CGSize(width: width, height: height)
}
But it ends up shrinking the image view rather than growing it to the size of the cell:

Give constraint to your imageView is zero from all side of collectionView cell and set image content mode to .scaleToFill and than show the result.
Thanks

I got you there. As I previously commented to show how you are giving constraints to image view, thus the error was there. There is a property called "translatesautoresizingmaskintoconstraints" which you need set while giving constraints to your views. You can read about it here.
Now, in your cellForItemAt you need to change:-
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CarCell", for: indexPath)
let carImage = UIImage(systemName: "car")
let carImageView = UIImageView(image: carImage)
carImageView.contentMode = .scaleToFill
carImageView.translatesautoresizingmaskintoconstraints = false
cell.addSubview(carImageView)
carImageView.centerXAnchor.constraint(equalTo: cell.contentView.centerXAnchor).isActive = true
carImageView.centerYAnchor.constraint(equalTo: cell.contentView.centerYAnchor).isActive = true
carImageView.heightAnchor.constraint(equalTo: cell.contentView.heightAnchor).isActive = true
carImageView.widthAnchor.constraint(equalTo: cell.contentView.widthAnchor).isActive = true
return cell
}
As you can notice I've also changed the constraint to give an idea about how you should give the constraints if you want to set the image size as exact as your cell. You should always access cell's content view when you're giving constraint not the cell.

Related

Table view cell scrolling issue

I have a table view and collection view to display image. Table view for vertical scroll and collection view for horizontal scroll. The image is displayed as full screen for the device. But when I scroll vertically half of previous cell is displayed and half of next cell is displayed. I used Table view constant is 0 to superview on all 4 constraints.
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return myTableView.frame.size.height;
}
To return the height of the cell but even this is causing same issue.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = self.myTableView.dequeueReusableCell(withIdentifier: "TableViewCell", for: indexPath) as! TableViewCell
return cell
}
This table view cell contains collection view
class TableViewCell: UITableViewCell,UICollectionViewDataSource,UICollectionViewDelegate,UICollectionViewDelegateFlowLayout{
func setUpCollectionView(){
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
collectionView = UICollectionView(frame: .zero,collectionViewLayout: layout)
collectionView?.register(VideoCollectionViewCell.self, forCellWithReuseIdentifier: VideoCollectionViewCell.identifier)
collectionView?.isPagingEnabled = true
collectionView?.dataSource = self
collectionView?.delegate = self
self.contentView.addSubview(collectionView!)
collectionView?.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
collectionView!.topAnchor.constraint(equalTo: contentView.topAnchor),
collectionView!.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
collectionView!.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
collectionView!.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
])
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: self.frame.width, height: self.frame.height)
}
}
This is my implementation, I don't want images to be displayed on half/half portion. I am trying to show it on full screen. Can anyone tell me why this is happening?
you need only UICollectionView display list images and set property scroll horizontal in UICollectionViewFlowLayout
myCollectionView.dataSource = self
myCollectionView.delegate = self
myCollectionView.contentMode = .scaleAspectFill
// scroll the images page by page, set property isPagingEnabled is true
myCollectionView.isPagingEnabled = true
let layout = UICollectionViewFlowLayout()
// set sroll horizontal here
layout.scrollDirection = .horizontal
myCollectionView.collectionViewLayout = layout

Can't get a view to change it's size

I have a UIImageView inside a ForecastCell Class (for a UICollectionView), anyhow, I can't get the UIImageView inside the cell to change it's size. This is what I tried:
private func setupWeatherIcon(){
self.addSubview(mWeatherIcon)
//mWeatherIcon.frame.size.width = CGFloat(self.frame.width) / 2
//mWeatherIcon.frame.size.height = CGFloat(self.frame.height) / 2
mWeatherIcon.frame.size.width = 20
mWeatherIcon.frame.size.height = 20
mWeatherIcon.centerXAnchor.constraint(equalTo: self.safeAreaLayoutGuide.centerXAnchor).isActive = true
mWeatherIcon.centerYAnchor.constraint(equalTo: self.safeAreaLayoutGuide.centerYAnchor).isActive = true
}
This is mWeatherIcon:
var mWeatherIcon: UIImageView = {
let image = UIImageView(image: UIImage(named: "partly-cloudy"))
image.translatesAutoresizingMaskIntoConstraints = false
return image
}()
No matter what width and height I set, It always stays the same width and height.
You need width and height constraints
self.contentView.addSubview(mWeatherIcon)
NSLayoutConstraint.activate([
mWeatherIcon.centerXAnchor.constraint(equalTo:contentView.centerXAnchor),
mWeatherIcon.centerYAnchor.constraint(equalTo:contentView.centerYAnchor),
mWeatherIcon.widthAnchor.constraint(equalTo:contentView.widthAnchor,multiplier:0.5),
mWeatherIcon.heightAnchor.constraint(equalTo:contentView.heightAnchor,multiplier:0.5)
])
Don't forget to implement this method
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize

How to trigger didSelectItemAtIndexPath at select center cell once the scroll end in ios swift?

Here UPCarouselFlowLayout is used for carousel scroll. As of now, user must tap a cell in order to trigger collection view didSelectItemAtIndexPath. Is there a way to select the center cell once the scrolling ended automatically?
here is the code i used to carousel:
let layout = UPCarouselFlowLayout()
layout.itemSize = CGSize(width: 211, height: 75)
layout.scrollDirection = .horizontal
layout.spacingMode = UPCarouselFlowLayoutSpacingMode.fixed(spacing: 10)
layout.spacingMode = UPCarouselFlowLayoutSpacingMode.overlap(visibleOffset: 65)
carCollection.collectionViewLayout = layout
here the code used for collection view:
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return carCategory.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! carCollectionViewCell
cell.carName.text = carCategory[indexPath.row]
cell.carImage.image = UIImage(named: carCategoryImage[indexPath.row])
cell.carMeters.text = carCategoryMeter[indexPath.row]
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("selected index::\(indexPath.row)")
}
If you look at ViewController.swift from the Demo included with ** UPCarouselFlowLayout**, you will see the function scrollViewDidEndDecelerating. That is triggered when the scroll stops moving and a cell become the "center" cell.
In that function, the variable currentPage is set, and that's where the labels below the collection view are changed.
So, that's one place to try what you want to do.
Add the two lines as shown here... when the scroll stops, you create an IndexPath and manually call didSelectItemAt:
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
let layout = self.collectionView.collectionViewLayout as! UPCarouselFlowLayout
let pageSide = (layout.scrollDirection == .horizontal) ? self.pageSize.width : self.pageSize.height
let offset = (layout.scrollDirection == .horizontal) ? scrollView.contentOffset.x : scrollView.contentOffset.y
currentPage = Int(floor((offset - pageSide / 2) / pageSide) + 1)
// add these two lines
let indexPath = IndexPath(item: currentPage, section: 0)
collectionView(self.collectionView, didSelectItemAt: indexPath)
}
You will almost certainly want to add some error checking and additional functionality (like only calling didSelect if the cell actually changed, as opposed to just sliding it a little but remaining on the current cell), but this is a starting point.

UIImageView in UICollectionView not drawing correctly

I have an app with a screen that is divided into four equal cells. Each cell has an image, label, and color. I'm trying to add the images in, but for some reason, only the image in the first cell works.
It looks like this now:
Here is my code:
In ViewController.swift:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
colorArray += [UIColor.red, UIColor.blue, UIColor.green, UIColor.yellow]
pictureArray += [UIImage(named: "budget")!, UIImage(named: "journey")!,
UIImage(named: "learn")!, UIImage(named: "settings")!]
titleArray += ["Budget", "Journey", "Learn", "Settings"]
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 4
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as UICollectionViewCell
// Set cell properties
cell.backgroundColor = colorArray[indexPath.row]
let imageview:UIImageView=UIImageView(image: pictureArray[indexPath.row])
let size = CGSize(width: 100, height: 100)
imageview.center = cell.center
imageview.bounds = CGRect(origin: cell.bounds.origin, size: size)
cell.contentView.addSubview(imageview)
let label = cell.viewWithTag(1) as! UILabel
label.text = titleArray[indexPath.row]
return cell
}
The labels and colors work fine, but for some reason, the image views seem to be off the screen. I have a feeling that my center/bounds restrictions are forcing the images off the screen, but I've tried many combinations, and none of them seem to work for me.
How should I do this?
I'm posting the correct answer for who ever will google here. (And because it was solved an hour ago without anyone posting the answer)
The best practice is to subclass UICollectionViewCell, connect all the outlets (label, image etc.) and work with this class on the cells
Good luck to all
This is what worked, after Yogesh Suthar's comment:
I subclassed UICollectionViewCell, connected the image and label:
class NavigationCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var navImage: UIImageView!
#IBOutlet weak var navLabel: UILabel!
}
Then, in the ViewController, I did this:
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! NavigationCollectionViewCell
// Set cell properties
cell.backgroundColor = colorArray[indexPath.row]
cell.navImage.image = imageArray[indexPath.row]
cell.navLabel.text = titleArray[indexPath.row]
return cell
}
Set the size and position of the image and label in Main.storyboard!
insert the desired view as a subclass and setup all constrains to cell.heightAchor and so on. this will fix the bug for some reason. It works if the subview is added to the cell as a subview but not as an attribute of the cell

Swift : How to set image to label that fits as per label size?

I've UICollectionViewCell that is generated programmatically. There is label placed over cell.
Now, I want to set image to label present on cell but that image should resize according to size of cell.
Below is code used but it didn't worked :
let objImage : UIImage = UIImage(named: "OK")!
let objCGSize = cell.lblNumber?.frame.size
UIGraphicsBeginImageContext(objCGSize!)
objImage.drawInRect(CGRectMake(0, 0, (cell.lblNumber?.frame.size.width)!, (cell.lblNumber?.frame.size.height)!))
let objNewImage : UIImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
cell.lblNumber!.text = ""
cell.lblNumber!.backgroundColor = UIColor(patternImage: objNewImage)
Any other fix?
I tried using UIButton instead of UILabel as suggested by someone. But here another issues cropped-up like Alignment of text, Image is not set..
. . . //Code for UIButton instead of UILabel
cell.btnNumber.setTitle("", forState: .Normal)
//cell.btnNumber.setImage(UIImage(named: "OK"), forState: .Normal)
cell.btnNumber.imageView?.image = UIImage(named: "OK")
cell.btnNumber.imageView?.contentMode = UIViewContentMode.ScaleAspectFit
. . .
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("hobbiesCell", forIndexPath: indexPath) as! HobbiesTagCell
self.configureCell(cell, forIndexPath: indexPath)
return cell
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
self.configureCell(self.sizingCell!, forIndexPath: indexPath)
return self.sizingCell!.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)
}
func configureCell(cell: HobbiesTagCell, forIndexPath indexPath: NSIndexPath) {
let tag = tags[indexPath.row]
cell.hobbiesTagName.text = yourArrname[indexPath.item]
}
Can you try setting content mode of the UIImageView after setting its frame? It can be done as follows
objImage.contentMode = UIViewContentMode.ScaleToFill
You can use ScaleToFill or ScaleAspectFill depending on your requirement. You can find more information about content modes here
set your button image view Content mode as ScaleAspectFit and at the same time set your button property setImage instead of setBackgroundImage?
yourbutton.imageView?.contentMode =.ScaleAspectFit
yourbutton.contentHorizontalAlignment = .Fill
yourbutton.contentVerticalAlignment = .Fill
yourbutton.setImage(UIImage(named: stretchImage)!, forState: .Normal)
for additional Help see this

Resources