When I select an image from a CollectionView and this cell, I want to get the name of that image and save it to CloudKit. My main question is how to get the name of the selected image?
This is my CollectionViewCell:
class AddImageViewCell: UICollectionViewCell {
#IBOutlet weak var addListImageView: UIImageView!
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.layer.cornerRadius = self.frame.size.width * 0.2
self.layer.borderWidth = 2
self.layer.borderColor = UIColor.clear.cgColor
}
}
Some of my AddListViewController:
class AddListViewController: UIViewController {
var imageArray : [UIImage] = [UIImage(named: "Images/do001.png")!,
UIImage(named: "Images/do002.png")!,
UIImage(named: "Images/do003.png")!,
UIImage(named: "Images/do004.png")!,
UIImage(named: "Images/do005.png")!,
UIImage(named: "Images/do006.png")!,
UIImage(named: "Images/do007.png")!,
UIImage(named: "Images/do008.png")!,
UIImage(named: "Images/do009.png")!,
UIImage(named: "Images/do010.png")!,
UIImage(named: "Images/do011.png")!,
UIImage(named: "Images/do012.png")!,
UIImage(named: "Images/do013.png")!,
UIImage(named: "Images/do014.png")!,
UIImage(named: "Images/do015.png")!,
UIImage(named: "Images/do016.png")!]
let selectedImage = 0
And here I want to get the name of the image file:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = addImageCollectionView.cellForItem(at: indexPath) as! AddImageViewCell
cell.layer.borderColor = UIColor.white.cgColor
var imageInCell = cell.addListImageView.image
print("\(String(describing: imageInCell))")
}
Here CellForItemAt:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell : AddImageViewCell = addImageCollectionView.dequeueReusableCell(withReuseIdentifier: "AddImageCell", for: indexPath) as! AddImageViewCell
cell.addListImageView.image = imageArray[indexPath.item]
return cell
}
Don't read the value from the cells. Cells are reused. Instead, use your model.
I'd suggest to do:
var imageNameArray: [String] = ["Images/do001.png", "Images/do002.png", ...]
In collectionView(_:cellForItemAt:):
let imageName = imageNameArray[indexPath.item]
let image = UIImage(named: imageName)
cell.addListImageView.image = image
In collectionView(_:didSelectItemAt:):
let selectedImageName = imageNameArray[indexPath.item]
You can use this extension,
it creates a property name and set it value using custom init,
if you did't use the custom init it will return empty String
extension UIImage {
convenience init?(named: String, saveName: Bool) {
self.init(named: named)
if saveName {
self.name = named
}
}
struct Name {
static var name: String = ""
}
var name: String {
get {
return Name.name
}
set(newValue) {
Name.name = newValue
}
}
}
Usage:
let img = UIImage(named: "test.png", saveName: true)
img?.name // "test.png"
// With image view
let imageView = UIImageView(image: img)
imageView.image?.name
Related
I have custom CollectionViewCell with function to set title, description and image, but a I cant understand how to set it when 1 cell is selected and second is not. I use this code. I find center of collectionView and I get array of my indexPath.item [0,1], but I can get access to my cell
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
let centerPoint = CGPoint(x: self.collectionView.center.x, //+ self.collectionView.contentOffset.x,
y: self.collectionView.center.y) //+ self.collectionView.contentOffset.y)
let collectionViewCenterPoint = self.view.convert(centerPoint, to: collectionView)
for cell in collectionView.visibleCells {
let indexPath = collectionView.indexPathForItem(at: collectionViewCenterPoint)
switch indexPath?.item {
case 0:
break
case 1:
break
case .none:
break
case .some(_):
break
}
}
}
this is my cell
class RoleCollectionViewCell: UICollectionViewCell, NiBLoadable {
#IBOutlet weak var circleView: UIView!
#IBOutlet weak var imageView: UIImageView!
#IBOutlet weak var roleLabel: UILabel!
#IBOutlet weak var descriptionTextView: UITextView!
override func awakeFromNib() {
super.awakeFromNib()
Decorator.decorate(self)
}
func setActive(image: UIImage, borderColor: CGColor) {
circleView.layer.borderColor = borderColor
imageView.image = image
}
func setTitle(text: String) {
roleLabel.text = text
}
func setDescription(text: String) {
descriptionTextView.text = text
}
}
and this is my method to return cells
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let centerPoint = CGPoint(x: self.collectionView.center.x, y: self.collectionView.center.y)
let collectionViewCenterPoint = self.view.convert(centerPoint, to: collectionView)
let models = model[indexPath.row]
switch models {
case .client:
if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: RoleCollectionViewCell.name, for: indexPath) as? RoleCollectionViewCell {
return cell
}
case .barber:
if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: RoleCollectionViewCell.name, for: indexPath) as? RoleCollectionViewCell {
let activeBarberImage = UIImage(named: "barber_a")
let deactiveBarberImage = UIImage(named: "barber_b")
cell.setActive(image: activeBarberImage!, borderColor: burbColor.cgColor)
cell.setTitle(text: "Barber")
cell.setDescription(text: "I can make you look real cool")
return cell
}
}
return UICollectionViewCell.init()
}
Use cellForItem(at:) to get the cell at a particular indexPath, i.e.
collectionView.cellForItem(at: indexPath)
You can get index path of visible cells
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
for cell in collectionView.visibleCells {
let indexPath = collectionView.indexPath(for: cell)
print(indexPath)
let cell = collectionView.cellForItemAtIndexPath(indexPath) as? yourCustomCellName
// here you get visible cell At index path
cell.yourCellMethod()
}
}
Combining your's and #jawadali answer
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
for cell in collectionView.visibleCells {
let indexPath = collectionView.indexPath(for: cell)
// here you get visible cell At index path
let models = model[indexPath.row]
switch models {
case .client:
if let cell = collectionView.cellForItemAtIndexPath(indexPath) as? RoleCollectionViewCell {
return cell
}
case .barber:
if let cell = collectionView.cellForItemAtIndexPath(indexPath) as? RoleCollectionViewCell {
let activeBarberImage = UIImage(named: "barber_a")
let deactiveBarberImage = UIImage(named: "barber_b")
cell.setActive(image: activeBarberImage!, borderColor: burbColor.cgColor)
cell.setTitle(text: "Barber")
cell.setDescription(text: "I can make you look real cool")
}
}
}
}
**I made this. it works. but now my all cells become active. I need to set 1 cell is active, and another is not. **
// MARK: - for switching cells
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
let centerPoint = CGPoint(x: self.collectionView.center.x, y: self.collectionView.center.y)
let collectionViewCenterPoint = self.view.convert(centerPoint, to: collectionView)
let indexPath = collectionView.indexPathForItem(at: collectionViewCenterPoint)
let cell: RoleCollectionViewCell = collectionView.cellForItem(at: indexPath!) as! RoleCollectionViewCell
let models = model[indexPath!.item]
switch models {
case .client:
cell.setActive(image: activeBarberImage!, borderColor: burbColor.cgColor)
case .barber:
cell.setActive(image: activeClientImage!, borderColor: burbColor.cgColor)
}
}
I have an array of 115 objects containing name and photo url string from Firebase. Printing the data shows results so i know its pulling data correctly.
The problem is the Cells are never populated by the data.
If i add a print(name) inside the class DJProfileCell: UICollectionViewCell it never gets called so i believe thats where the issue is.
class VLCDJProfileViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
#IBOutlet weak var similarArtistsCollection: UICollectionView!
var ref: DatabaseReference!
let profileCellID = "cellId"
var djObject = SimilarDJ(image: "image1", name: "name1")
var djsSimilarArray = [SimilarDJ]()
override func viewDidLoad() {
super.viewDidLoad()
ref = Database.database().reference()
loadDJs()
collectionView?.register(DJProfileCell.self, forCellWithReuseIdentifier: profileCellID)
}
func loadDJs(){
let allDJs = self.ref.child("DJ")
allDJs.observeSingleEvent(of: .value, with: { snapshot in
for child in snapshot.children {
let snap = child as! DataSnapshot
let djsDict = snap.value as! [String: Any]
let PhotoUrl = djsDict["PhotoUrl"] as! String
let name = djsDict["name"] as! String + " "
self.djObject = SimilarDJ (image: PhotoUrl, name: name + " ")
self.djsSimilarArray.append(self.djObject)
self.similarArtistsCollection.reloadData();
}
})
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return djsSimilarArray.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: profileCellID, for: indexPath) as! DJProfileCell
cell.djprofile = djsSimilarArray[indexPath.item]
return cell
}
class DJProfileCell: UICollectionViewCell {
var djprofile: SimilarDJ? {
didSet {
guard let djImageProfile = djprofile?.image else {return}
guard let djNameProfile = djprofile?.name else {return}
let url = URL(string: djImageProfile)
djImageView.kf.indicatorType = .activity
djImageView.kf.setImage(with: url)
djImageLabel.text = djNameProfile
djImageLabel.adjustsFontSizeToFitWidth = true
}
}
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
func setup(){
self.backgroundColor = .white
self.addSubview(djImageView)
self.addSubview(djImageLabel)
}
let djImageView: UIImageView = {
let iv = UIImageView()
// iv.contentMode = .scaleAspectFit
// iv.backgroundColor = .green
return iv
}()
let djImageLabel: MarqueeLabel = {
let label = MarqueeLabel()
label.text = "Name"
label.textColor = UIColor.black
label.font = label.font.withSize(14)
label.textAlignment = .center
return label
}()
required init?(coder aDecoder: NSCoder) {
fatalError("init has not been implemented")
}
}
struct SimilarDJ {
let image: String?
let name: String?
}
in cell class - djImageView and djImageLabel are never added to the view's hierarchy. I see no IBOutlet and no addSubview().
How to Retrieve the images from firebase storage in which I have manually created folders according the category of my "wallpaper app" and I have created a list of "items" according to the category of my wallpaper. I am not understanding how to retrieve the images according to the "items"-(it is there in the code below) from the storage of firebase and display it accordingly.
I just want to store all the images according to the category of the "items" which is specified in the code below and display it in the app.
import UIKit
import GlidingCollection
import FirebaseStorage
import Firebase
class ViewController: UIViewController {
#IBOutlet var glidingView: GlidingCollection!
fileprivate var collectionView: UICollectionView!
fileprivate var items = ["riches", "animals", "nature", "architecture","toys"]
fileprivate var images: [[UIImage?]] = []
override func viewDidLoad() {
super.viewDidLoad()
setup()
}
func setup() {
setupGlidingCollectionView()
loadImages()
}
func setupGlidingCollectionView() {
glidingView.dataSource = self
let nib = UINib(nibName: "CollectionCell", bundle: nil)
collectionView = glidingView.collectionView
collectionView.register(nib, forCellWithReuseIdentifier: "Cell")
collectionView.delegate = self
collectionView.dataSource = self
collectionView.backgroundColor = glidingView.backgroundColor
}
func loadImages() {
let storage = Storage.storage()
let storageRef = storage.reference()
let starsRef = storageRef.child("Animals")
starsRef.downloadURL { url, error in
if let error = error {
print("not there")
} else {
for item in self.items {
let imageURLs = FileManager.default.fileUrls(for: "jpeg", fileName: item)
var images: [UIImage?] = []
for url in imageURLs {
guard let data = try? Data(contentsOf: url) else { continue }
let image = UIImage(data: data)
images.append(image)
}
self.images.append(images)
}
}
}
}
}
// MARK: - Setup
// MARK: - CollectionView 🎛
extension ViewController: UICollectionViewDataSource, UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return images.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as? CollectionCell else { return UICollectionViewCell() }
let section = glidingView.expandedItemIndex
let image = images[section][indexPath.row]
cell.imageView.image = image
cell.contentView.clipsToBounds = true
let layer = cell.layer
let config = GlidingConfig.shared
layer.shadowOffset = config.cardShadowOffset
layer.shadowColor = config.cardShadowColor.cgColor
layer.shadowOpacity = config.cardShadowOpacity
layer.shadowRadius = config.cardShadowRadius
layer.shouldRasterize = true
layer.rasterizationScale = UIScreen.main.scale
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let section = glidingView.expandedItemIndex
let item = indexPath.item
print("Selected item #\(item) in section #\(section)")
}
}
// MARK: - Gliding Collection 🎢
extension ViewController: GlidingCollectionDatasource {
func numberOfItems(in collection: GlidingCollection) -> Int {
return items.count
}
func glidingCollection(_ collection: GlidingCollection, itemAtIndex index: Int) -> String {
return "– " + items[index]
}
}
in another swift file linked to the cell of the collection view."CollectionCell.xib"
import UIKit
class CollectionCell: UICollectionViewCell {
#IBOutlet weak var imageView: UIImageView!
}
I want all the images categorised and according to the items displayed in my app.
Here is my class
class myCell: UICollectionViewCell {
public var myProp:String = ""
let myControl:UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.Text = myProp
return label
}()
}
I want to use the myProp within the creation of my UI elements but the compiler is saying I cannot use myProp.
or why is this incorrect
class myCell: UICollectionViewCell {
public var myLabel:UILabel = UILabel()
let myControl:UIView = {
let ui = UIView()
myLabel = {
let lbl = UILabel()
lbl.translatesAutoresizingMaskIntoConstraints = false
return lbl
}()
ui.AddSubView(myLabel)
return ui
}()
}
This will work
class CollectionViewCell: UICollectionViewCell {
public var myProp:String = ""
override init(frame: CGRect) {
super.init(frame: frame)
}
func setText() {
let myControl:UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.text = myProp
return label
}()
self.addSubview(myControl)
}
}
During rendering, in cellForRowAtIndex need to implement this for adding subview with text.
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! CollectionViewCell
cell.myProp = "text"
cell.setText()
return cell
}
I am using this code: https://www.youtube.com/watch?v=bNtsekO51iQ , but when I implement my data and use collectionView.reloadData() it crashes with error code *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'the collection view's data source did not return a valid cell from -collectionView:cellForItemAtIndexPath: for index path <NSIndexPath: 0xc000000000000016> {length = 2, path = 0 - 0}'
class ChatLogController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
var userId:Int?
var position:Int = 0
var otherAvatar:UIImage = UIImage(named: "defaultAvatar")!
var otherName:String = ""
var otherSex:String = ""
var otherBanned:Int = 0
var otherBlocked:Int = 0
var messagesDates:[String] = []
var messagesText:[String] = []
var messagesIds:[String] = []
var messagesPics:[UIImage?] = []
var messagesSeen:[Int] = []
var messagesWhoSendIt:[Int] = []
private let cellId = "cellId"
override func viewDidLoad() {
super.viewDidLoad()
collectionView?.register(ChatLogMessageCell.self, forCellWithReuseIdentifier: cellId)
collectionView!.isPrefetchingEnabled = false
loadChatsFor(position: position)
} override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return messagesIds.count
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath as IndexPath) as! ChatLogMessageCell
cell.messageTextView.text = messagesText[indexPath.row]
cell.profileImageView.image = UIImage(named: "defaultAvatar")!
let size = CGSize(width:250,height:1000)
let options = NSStringDrawingOptions.usesFontLeading.union(.usesLineFragmentOrigin)
let estimatedFrame = NSString(string: messagesText[indexPath.row]).boundingRect(with: size, options: options, attributes: [NSFontAttributeName: UIFont.systemFont(ofSize: 18)], context: nil)
cell.messageTextView.frame = CGRect(x:48 + 8, y:0, width:estimatedFrame.width + 16, height:estimatedFrame.height + 20)
cell.textBubbleView.frame = CGRect(x:48, y:0, width:estimatedFrame.width + 16 + 8, height:estimatedFrame.height + 20)
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let size = CGSize(width:250,height:1000)
let options = NSStringDrawingOptions.usesFontLeading.union(.usesLineFragmentOrigin)
let estimatedFrame = NSString(string: messagesText[indexPath.row]).boundingRect(with: size, options: options, attributes: [NSFontAttributeName: UIFont.systemFont(ofSize: 18)], context: nil)
return CGSize(width:view.frame.width, height:estimatedFrame.height + 20)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsetsMake(8, 0, 0, 0)
}
}
class ChatLogMessageCell: BaseCell {
let messageTextView: UITextView = {
let textView = UITextView()
textView.font = UIFont.systemFont(ofSize: 18)
textView.text = "Sample message"
textView.backgroundColor = UIColor.clear
return textView
}()
let textBubbleView: UIView = {
let view = UIView()
view.backgroundColor = UIColor(white: 0.95, alpha: 1)
view.layer.cornerRadius = 15
view.layer.masksToBounds = true
return view
}()
let profileImageView: UIImageView = {
let imageView = UIImageView()
imageView.contentMode = .scaleAspectFill
imageView.layer.cornerRadius = 15
imageView.layer.masksToBounds = true
return imageView
}()
override func setupViews() {
super.setupViews()
addSubview(textBubbleView)
addSubview(messageTextView)
addSubview(profileImageView)
addConstraintsWithFormat(format:"H:|-8-[v0(30)]", views: profileImageView)
addConstraintsWithFormat(format:"V:[v0(30)]|", views: profileImageView)
profileImageView.backgroundColor = UIColor.red
}
}
extension UIView {
func addConstraintsWithFormat(format: String, views: UIView...) {
var viewsDictionary = [String: UIView]()
for (index, view) in views.enumerated() {
let key = "v\(index)"
viewsDictionary[key] = view
view.translatesAutoresizingMaskIntoConstraints = false
}
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: format, options: NSLayoutFormatOptions(), metrics: nil, views: viewsDictionary))
}
}
class BaseCell: UICollectionViewCell {
override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setupViews() {
}
}
In loadChatsFor I get the array data from web and I use collectionView.reloadData(), but when this function is performed it crashes my app. I've searched for answer, but unsuccessfully. I've added IOS 10 function collectionView!.isPrefetchingEnabled = false in view did load from this answer UICollectionView exception in UICollectionViewLayoutAttributes from iOS7, but also not working. Even the method collectionViewLayout invalidateLayout before reloadData and after reloadData doesn't stop the crash. So what else I can do to make it work ?
I am coming in this CollectionViewController from UITableViewCell
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let layout = UICollectionViewFlowLayout()
let controller = ChatLogController(collectionViewLayout: layout)
controller.userId = chatUserIds[indexPath.row]
navigationController?.pushViewController(controller, animated: true)
}
I've added UICollectionViewDelegateFlowLayout in the class of the tableview
You are not implementing correct cellForItemAt method of UICollectionViewDataSource. Signature of this method is changed in Swift 3 like this.
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath as IndexPath) as! ChatLogMessageCell
cell.messageTextView.text = messagesText[indexPath.row]
cell.profileImageView.image = UIImage(named: "defaultAvatar")!
let size = CGSize(width:250,height:1000)
let options = NSStringDrawingOptions.usesFontLeading.union(.usesLineFragmentOrigin)
let estimatedFrame = NSString(string: messagesText[indexPath.row]).boundingRect(with: size, options: options, attributes: [NSFontAttributeName: UIFont.systemFont(ofSize: 18)], context: nil)
cell.messageTextView.frame = CGRect(x:48 + 8, y:0, width:estimatedFrame.width + 16, height:estimatedFrame.height + 20)
cell.textBubbleView.frame = CGRect(x:48, y:0, width:estimatedFrame.width + 16 + 8, height:estimatedFrame.height + 20)
return cell
}