Url Image in Swift - swift

I using the LJWebImage sample project, Which,I found from github on the following link https://github.com/likumb/LJWebImage. Project,similar to SDWebImage.I am successfully imported the sample project into my project.I am using collectionView to populating the image from plist which contain number of url links.I am trying pass the collectionView selected cellimage to my imageView but no luck so for.please someone point me the direction.my partial collectionView code below.
Thanks in Advance.
let apps: NSArray = AppInfo.appInfo()
#IBOutlet weak var imageView: UIImageView!
#IBOutlet weak var collectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
collectionView!.reloadData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
// MARK: - CollectionView data source
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return apps.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath as IndexPath) as! Cell
cell.app = apps[indexPath.row] as? AppInfo
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if let filePath = Bundle.main.path(forResource: "apps", ofType: "plist"),
let image = UIImage(contentsOfFile: filePath) {
imageView.contentMode = .scaleAspectFit
imageView.image = image
}
}
}

You can retrieve the corresponding app object from the data source array using the indexPath.
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
guard let app = apps[indexPath.row] as? AppInfo else { return }
guard let image = UIImage(contentsOfFile: app.filePath) else { return }
imageView.contentMode = .scaleAspectFit
imageView.image = image
}
Or you could retrieve the cell using the indexPath and get the image from it's imageView.
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
guard let cell = collectionView.cellForItem(at: indexPath) as? Cell else { return }
imageView.contentMode = .scaleAspectFit
imageView.image = cell.imageView.image
}

Related

Receiving an error of when trying to add text to a label in a collection view

I am trying to input the arrayOfValues[indexPath.item] as the text for my textLabel in the collection view, but receive an error when I run the program saying 'Fatal error: Index Out of Range'
How would I fix this so that the collectionView cells are populated with information from the arrayOfValues?
Here is the code.
import UIKit
class NetworkViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {
#IBOutlet weak var firstCollectionView: UICollectionView!
#IBOutlet weak var secondCollectionView: UICollectionView!
let arrayOfOrganizations = ["My Network", "Find Connections", "ss"]
let arrayOfValues = [""]
override func viewDidLoad() {
super.viewDidLoad()
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if (collectionView == secondCollectionView) {
return arrayOfOrganizations.count
}
return arrayOfValues.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let firstCell = firstCollectionView.dequeueReusableCell(withReuseIdentifier: "firstCell", for: indexPath) as! FirstCollectionViewCell
firstCell.textLabel.text = arrayOfValues[indexPath.item] //error on this line
if (collectionView == secondCollectionView) {
let secondCell = secondCollectionView.dequeueReusableCell(withReuseIdentifier: "secondCell", for: indexPath) as! SecondCollectionViewCell
secondCell.backgroundColor = .black
return secondCell
}
return firstCell
}
}
class FirstCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var textLabel: UILabel!
}
class SecondCollectionViewCell: UICollectionViewCell {
}
The problem you had was the the first two lines of your cellForItemAt function were getting executed no matter the collectionView. So, essentially, you need to make sure the block of code corresponding to the firstCollectionView gets executed only when collectionView == firstCollectionView, and same goes for the secondCollectionView. In short, you just need to change your function to this instead:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if (collectionView == secondCollectionView) {
let secondCell = secondCollectionView.dequeueReusableCell(withReuseIdentifier: "secondCell", for: indexPath) as! SecondCollectionViewCell
secondCell.backgroundColor = .black
return secondCell
} else {
let firstCell = firstCollectionView.dequeueReusableCell(withReuseIdentifier: "firstCell", for: indexPath) as! FirstCollectionViewCell
firstCell.textLabel.text = arrayOfValues[indexPath.item] //error on this line
return firstCell
}
}

Print image name to console from UICollectionView

I'm working with a UICollectionView where I have a UIImage with a Tap Gesture Recogniser as the cell model for my CollectionView. I also have 57 images with different names that I want to print to the console depending on which image I tap on.
Here is my code:
import UIKit
class ViewController: UIViewController {
let OLLData = OLLCases()
// MARK: - Outlets
#IBOutlet weak var collectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
// MARK: - Navigation
#IBAction func isSelected(_ sender: Any) {
print("selected \(caseName)")
}
}
//MARK: - Data source
extension ViewController: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return OLLData.list.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PhotoCell", for: indexPath) as! PhotoCell
let image = OLLData.list[indexPath.item].image
let caseName = OLLData.list[indexPath.item].image
cell.label.text = caseName
cell.imageView.image = UIImage(named: image)
return cell
}
}
I then have another swift file (PhotoCell )where I have the IBOutlets for label and imageView.
What methods are there of doing this?
Thanks.
You can use UICollectionViewDelegate method to detect tap on cell but to use that first of all your UICollectionView need to confirm the delegate with your UIViewController like:
collectionView.delegate = self
in your viewDidLoad method.
then you need to replace
extension ViewController: UICollectionViewDataSource {
with
extension ViewController: UICollectionViewDataSource, UICollectionViewDelegate {
and use delegate method
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
}
and you can get selected image name with
let caseName = OLLData.list[indexPath.item].image
print(caseName)
and didSelectItemAt will look like:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let caseName = OLLData.list[indexPath.item].image
print(caseName)
}
EDIT:
Your extension will look like:
extension ViewController: UICollectionViewDataSource, UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return OLLData.list.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PhotoCell", for: indexPath) as! PhotoCell
let image = OLLData.list[indexPath.item].image
let caseName = OLLData.list[indexPath.item].image
cell.label.text = caseName
cell.imageView.image = UIImage(named: image)
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let caseName = OLLData.list[indexPath.item].image
print(caseName)
}
}
You should implement didSelectItemAt method, then get the cell you've selected like this:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath) as! PhotoCell
print(cell.imageView)
print(cell.label)
}
Hope this help
Add an extension for UICollectionViewDelegate below the last extension in your ViewController:
extension ViewController: UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print(OLLData.list[indexPath.item].image)
}
}

iOS Collection View Lagging

In my App I am using a CollectionView to display some Images. When I start scrolling performance is quite poor and big lags occur. I tried utilising an Image cache so the Images are not reloaded every time the cell appears. I have also tried removing the rounded edges and utilising layer.shouldRasterize. Nothing seems to help. The Images are in the Assets of the App.
let imageCache = NSCache<AnyObject, AnyObject>()
...
class MainMenuController: UIViewController, UICollectionViewDataSource, UICollectionViewDataSourcePrefetching, UICollectionViewDelegateFlowLayout {
#IBOutlet weak var collectionView: UICollectionView!
let reuseIdentifier = "cell"
override func viewDidLoad() {
super.viewDidLoad()
....
}
//Collection View
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return items.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath as IndexPath) as! MainMenuCell
cell.titleLabel.text = self.items[indexPath.item].getName()
cell.titleLabel.textColor = ColorInterface.sharedInstance.ultra_textcolor
if let imageFromCache = imageCache.object(forKey: items[indexPath.item].getKey() as AnyObject) as? UIImage {
cell.imageView.image = imageFromCache
}
else
{
let imageToCache = UIImage(named: items[indexPath.item].getImage())!
imageCache.setObject(imageToCache, forKey: items[indexPath.item].getKey() as AnyObject)
cell.imageView.image = imageToCache
}
cell.layer.cornerRadius = 7
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let totalHeight: CGFloat = (collectionView.frame.width / 2)
let totalWidth: CGFloat = (collectionView.frame.width / 2)
return CGSize(width: ceil(totalWidth - 5),height: ceil(totalHeight - 5))
}
func collectionView(_ collectionView: UICollectionView, prefetchItemsAt indexPaths: [IndexPath]) {
for index in indexPaths
{
if imageCache.object(forKey: items[index.item].getKey() as AnyObject) == nil
{
let imageToCache = UIImage(named: items[index.item].getImage())!
imageCache.setObject(imageToCache, forKey: items[index.item].getKey() as AnyObject)
}
}
}
}
After I scrolled to the bottom once everything is silky smooth which originally lead me to believing it is the loading of the images which is causing problems. What am I doing wrong here ?

Swift 3 Image Slider with button can't change imageview

There is image slider. I have made a image slider and each is button. I also change the image of button, and now I can't click the button in image slider to change the UIImageView "imgtoy". I want to click the button, then UIImageView will change to each photo in my choosetoy array. Anyone can help me? Here is my code:
#IBOutlet weak var imgtoy: UIImageView!
var itemImage: Int = 2
var imageName: String = ""
var imgBackground = [UIImage(named: "btnballicon.png"), UIImage(named: "btneastfin.png"), UIImage(named: "btnmarblefin.png"), UIImage(named: "btnplanefin.png"), UIImage(named: "btntoyfin.png")]
private let choosetoy = ["ballfin.png", "eastfin.png", "marblefin.png", "planefin.png", "toyfin.png"]
override func viewDidLoad() {
super.viewDidLoad()
imageName = choosetoy[itemImage]
self.imgtoy.image = UIImage(named: imageName)
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return imgBackground.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "foodCollectionViewCell", for: indexPath) as! foodCollectionViewCell
cell.imgfood.setImage(imgBackground[indexPath.row],for: UIControlState.normal)
itemImage = indexPath.row
return cell
}
#IBAction func choosetoy(_ sender: Any) {
if itemImage != nil {
imageName = choosetoy[itemImage]
self.imgtoy.image = UIImage(named: imageName)
}
}
Update code as below,
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "foodCollectionViewCell", for: indexPath) as! foodCollectionViewCell
cell.imgfood.setImage(imgBackground[indexPath.row],for: UIControlState.normal)
cell.imgfood.tag = indexPath.row
return cell
}
#IBAction func choosetoy(_ sender: UIButton) {
imageName = choosetoy[sender.tag]
self.imgtoy.image = UIImage(named: imageName)
}

Toggle image in UICollectionViewCell when cell selected

I have a UICollectionView of items, and I would like an image in a cell to be toggled when the user selects the cell.
I have a custom UICollectionViewCell:
class RDCell: UICollectionViewCell {
var textLabel: UILabel!
var imageView: UIImageView!
var isSelected: Bool!
...(do init and all that good stuff)
}
And selctected item in collection view :
func collectionView(collectionView: UICollectionView, shouldSelectItemAtIndexPath indexPath: NSIndexPath) -> Bool {
let celld = (collectionView.dequeueReusableCellWithReuseIdentifier("collectionCell", forIndexPath: indexPath) as? RDCell)!
let indexPaths = collectionView.indexPathsForSelectedItems()
let newCell = collectionView.cellForItemAtIndexPath(indexPath) as! RDCell
if(celld.selected){
var image: UIImage = UIImage(named: "notSelected")!
newCell.imageView.image = image
newCell.selected = false
}else{
var image: UIImage = UIImage(named: "selected")!
newCell.imageView.image = image
newCell.selected = true
}
return true
}
My attempt partially works, after selecting and unselecting one item I am not able to select it again after, I need to select a different cell before returning to select the first, and this same bug happens on all selected cells.
Any suggestions or another way to implement the functionality I seek would be greatly appreciated.
Swift 4
I just use the property "highlightedImage" in the "cellForItemAt indexPath" method of the collectionView and set another image on it.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
cell.backgroundColor = UIColor.clear
let imageView = cell.viewWithTag(1) as! UIImageView
imageView.image = imagesArray1[indexPath.row]
imageView.highlightedImage = imagesArray2[indexPath.row]
imageView.contentMode = .scaleAspectFill
return cell
}
In my case, i assigned a tag in the imageView and call it through it.
Best regards.
You should never call cellForItemAtIndexPath directly. You have no guarantee of what cell you're getting and the changes you make may have no effect.
The proper way to do this is to track your state within the class and change the state of the cell in cellForItemAtIndexPath. Then you simply call collectionView?.reloadData() when you need to update the views.
Simple example for reference:
var selectionTracking: [[Bool]] = []
func collectionView(collectionView: UICollectionView, shouldSelectItemAtIndexPath indexPath: NSIndexPath) -> Bool {
if let selected = selectionTracking[indexPath.section][indexPath.row] {
return selected
}
else{
selectionTracking[indexPath.section][indexPath.row] = false
}
return true
}
override func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
if let selected = selectionTracking[indexPath.section][indexPath.row] {
selectionTracking[indexPath.section][indexPath.row] = !selectionTracking[indexPath.section][indexPath.row]
}
else{
selectionTracking[indexPath.section][indexPath.row] = true
}
collectionView?.reloadData()
return true
}
My approach will be different for this, i would have used the didDeselectItemAt method of the collectionView...
Swift 3:
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
let newCell = collectionView.cellForItem(at: indexPath)
newCell.imageView.image = imageAfterSelection[indexPath.row]
}
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
let newCell = collectionView.cellForItem(at: indexPath)
newCell.imageView.image = imagesAfterDeselection[indexPath.row]
}
Swift 4/5:
Inside your collectionViewCell class define a variable called imageName
then override isSelected property to set the image name based on selected state and in collectionView cellForItemAt method set the value for imageName variable for each cell.
CollectionViewCell Class:
class YourCollectionViewCell: UICollectionViewCell
{
#IBOutlet var cellIcon: UIImageView!
var imageName = ""
override var isSelected: Bool {
didSet {
if self.isSelected {
self.cellIcon.image = UIImage(named: "\(self.imageName) Highlighted")
} else {
self.cellIcon.image = UIImage(named: "\(self.imageName) Unhighlighted")
}
}
}
}
CollectionView DataSource:
class YourCollectionVewController: UICollectionViewDataSource
{
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
// this line is an extension don't copy paste
let cell = collectionView.dequeueReusableCell(with: YourCollectionViewCell.self, for: indexPath)
let imageName = "yourImageName Unhighlighted"
cell.cellIcon.image = UIImage(named: imageName)
cell.imageName = imageName
return cell
}
}