Collection view Cells redirecting different ViewController - ios

I Have UICollectionView with Sections. Each Sections have variable cells which is defined by array count. I have declared array of strings for each section in viewDidLoad function.
I want each cell to open a New UIViewController on click of respective cell. How do i get the above result.
I am using Swift3 for coding.
class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
#IBOutlet weak var collectView: UICollectionView!
var sectionHeader = [String] ()
var sectionArr = [Any] ()
var enquire = [String] ()
var serviceRequest = [String] ()
var missedCall = [String] ()
var settings = [String] ()
var arr = [String] ()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
sectionHeader = ["Enquire","Service Request","Missed Call Recharge","Settings"]
enquire = ["Balance Enquiry","Mini Statement","Account Statement","Cheque Status Enquiry","Fixed Deposit Enquiry"]
serviceRequest = ["Stop Cheque Payment","Cheque Book Request","iPIN Regeneration"]
missedCall = ["Activate","Deactivate","Set Recharge Amount","Recharge"]
settings = ["Change Primary Account","Register"]
sectionArr = [enquire,serviceRequest,missedCall,settings]
collectView.dataSource = self
collectView.delegate = self
collectView.reloadData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func loadCollectionView(_ sender: Any) {
collectView.reloadData()
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return sectionArr.count
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if (section == 0) {
return enquire.count
}
else if (section == 1) {
return serviceRequest.count
}
else if (section == 2) {
return missedCall.count
}
else {
return self.settings.count
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let mycell:CustomCell = collectView.dequeueReusableCell(withReuseIdentifier: "MyCell", for: indexPath) as! CustomCell
arr = sectionArr[indexPath.section] as! [String]
let imagename = arr[indexPath.row]
let modified = imagename.replacingOccurrences(of: " ", with: "_")
let modified_imagename = modified + ".png"
mycell.functionalityImage.image = UIImage(named : modified_imagename)
mycell.functionalityName.text = arr[indexPath.row]
return mycell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
arr = sectionArr[indexPath.section] as! [String]
showAlert(mesgTitle: "SELECTED CELL", mesgText: arr[indexPath.row])
}
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
var reusea:UICollectionReusableView? = nil
if (kind == UICollectionElementKindSectionHeader) {
let header:HeaderTextHome = collectView.dequeueReusableSupplementaryView(ofKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "Header_Text", for: indexPath) as! HeaderTextHome
header.headerText.text = sectionHeader[indexPath.section ]
reusea = header
}
return reusea!
}
func showAlert(mesgTitle : String, mesgText : String) {
let alertController = UIAlertController(title: mesgTitle, message: mesgText, preferredStyle: UIAlertControllerStyle.alert)
let defaultAction = UIAlertAction(title: "Okay", style: UIAlertActionStyle.default, handler: nil)
let cancleAction = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.cancel, handler: nil)
alertController.addAction(defaultAction)
alertController.addAction(cancleAction)
present(alertController, animated: true, completion: nil)
}
}
Above code i display an alert on click.

If I understood your question correctly, then one way of doing this would be to set the identifier for each UIViewController in your storyboard and then calling this in your didSelectItemAt:
let vc = self.storyboard?.instantiateViewController(withIdentifier: sectionArr[indexPath.section]) as! UIViewController
self.present(vc, animated: true, completion: nil)

If you are using segue then Set up All viewController segue in storyboard then use bellow code.
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
arr = sectionArr[indexPath.section] as! [String]
let viewControllerIdentifire = arr[indexPath.item]
self.performSegue(withIdentifier: viewControllerIdentifire, sender: IfYouWantToPassDataThanPutHereElseNil)
// showAlert(mesgTitle: "SELECTED CELL", mesgText: arr[indexPath.row])
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "Enquire" {
let vc = segue.destinationViewController as! EnquireViewController
vc.data = sender // if you want to pass data to viewCotroller
}
}

Related

Error on Performing Segue with UICollectionView

When I click on any UICollectionView item, I got this error on PerformSegue line:
Thread 1: Fatal error: Index out of range
However, the compiler don't read the function and simply jumps straight to the PerformSegue, so I end up out of index. How can I fix that? When the user clicks on any UICollectionView index, I gotta replace the Indexpath in the function parameter and repeat the process.
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
getCategoriaPorID(IdCategoria: indexPath.row) { (data) in
DispatchQueue.main.async {
self.dataCategoriaID = data
}
}
performSegue(withIdentifier: "segueCategorias", sender:self.dataCategoriaID[indexPath.row])
}
Complete ViewController file:
import UIKit
class ViewController: UIViewController, UICollectionViewDataSource, UITableViewDataSource, UITableViewDelegate, UICollectionViewDelegate {
#IBOutlet weak var tableViewTopSell: UITableView!
#IBOutlet var collectionView: UICollectionView!
#IBOutlet weak var collectionViewBanner: UICollectionView!
var indexPathId = Int()
var dataSource: [Content] = [Content]()
var dataBanner: [Banner] = [Banner]()
var dataTopSold: [Top10] = [Top10]()
var dataCategoriaID: [CategoriaIDItems] = [CategoriaIDItems]()
override func viewDidLoad() {
super.viewDidLoad()
//Delegate TableView
self.tableViewTopSell.delegate = self
//SetupNavBarCustom
self.navigationController?.navigationBar.CustomNavigationBar()
let logo = UIImage(named: "tag.png")
let imageView = UIImageView(image:logo)
self.navigationItem.titleView = imageView
//CallAPIData
getTopSold { (data) in
DispatchQueue.main.async {
self.dataTopSold = data
self.tableViewTopSell.reloadData()
}
}
getBanner { (data) in
DispatchQueue.main.async {
self.dataBanner = data
self.collectionViewBanner.reloadData()
}
}
getAudiobooksAPI { (data) in
DispatchQueue.main.async {
self.dataSource = data
self.collectionView.reloadData()
}
}
}
//CollectionView
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if (collectionView == self.collectionView) {
return self.dataSource.count
}else{
return self.dataBanner.count
}}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if (collectionView == self.collectionView) {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionViewCell", for: indexPath) as! CollectionViewCell
let content = self.dataSource[indexPath.item]
cell.bookLabel.text = content.descricao
cell.bookImage.setImage(url: content.urlImagem, placeholder: "")
return cell
}else if (collectionView == self.collectionViewBanner) {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionViewCellBanner", for: indexPath) as! CollectionViewCell
let content = self.dataBanner[indexPath.item]
cell.bannerImage.setImage(url: content.urlImagem, placeholder: "")
return cell
}
return UICollectionViewCell()
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
getCategoriaPorID(IdCategoria: indexPath.row) { (data) in
DispatchQueue.main.async {
self.dataCategoriaID = data
}
}
performSegue(withIdentifier: "segueCategorias", sender:self.dataCategoriaID[indexPath.row])
}
//TableView
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.dataTopSold.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "topSoldCell", for: indexPath) as! TableViewCell
let content = self.dataTopSold[indexPath.row]
cell.labelNomeTopSell.text = content.nome
cell.imageViewTopSell.setImage(url: content.urlImagem, placeholder: "")
cell.labelPrecoDe.text = "R$ \(content.precoDe)"
//Colocar strike em cima do Preco Antigo
let oldPrice = "R$ \(content.precoDe)"
let promotionString = oldPrice + ""
let attributedStr = NSMutableAttributedString(string: promotionString)
let crossAttr = [NSAttributedStringKey.strikethroughStyle: NSUnderlineStyle.styleSingle.rawValue]
attributedStr.addAttributes(crossAttr, range: NSMakeRange(0, oldPrice.count))
cell.labelPrecoDe.attributedText = attributedStr
//
cell.labelPrecoPor.text = "R$ 119.99"
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "segueId", sender:self.dataTopSold[indexPath.row])
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "segueId" {
let des = segue.destination as? TelaDetalheProdutos
//.item possui uma propriedade instanciada na TelaDetalheProdutos
des?.item = (sender as? Top10)
//Segue para CollectionView Categorias
} else if segue.identifier == "segueCategorias" {
let desc = segue.destination as? TelaCategorias
desc?.item = (sender as? CategoriaIDItems)
}
}
}
//Cast UIImage Extension
extension UIImageView{
func setImage(url : String, placeholder: String, callback : (() -> Void)? = nil){
self.image = UIImage(named: "no-photo")
URLSession.shared.dataTask(with: NSURL(string: url)! as URL, completionHandler: { (data, response, error) -> Void in
guard error == nil else{
return
}
DispatchQueue.main.async(execute: { () -> Void in
let image = UIImage(data: data!)
self.image = image
if let callback = callback{
callback()
}
})
}).resume()
}
}
Use main thread only to update UI. The problem is you are setting dataCategoriaID on main thread I assume which is inside asynchronous network call function. So you are trying to perform segue before setting dataCategoriaID and that is the reason it is empty and throwing index out of range error.
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
getCategoriaPorID(IdCategoria: indexPath.row) { (data) in
self.dataCategoriaID = data
performSegue(withIdentifier: "segueCategorias", sender:self.dataCategoriaID[indexPath.row])
}
}

PerformSegue from UICollectionReusableView(Header) custom button Swift

I have a headerView in which I am having a float button. Since all the subitems in the float button are programmatically generated and it is a subview of headerView I am not able to call a performSegue. I tried creating a delegate method, But I totally messed it up. I know that protocols might be the fix, But i am quite unsure about how to exactly work it out.
I am attaching the image of the headerView below
headerView code :
class ProfileHeader: UICollectionReusableView, FloatyDelegate {
#IBOutlet weak var pname: UILabel!
#IBOutlet weak var pusername: UILabel!
#IBOutlet weak var profilePic: UIImageView!
#IBOutlet weak var userDesc: UILabel!
#IBOutlet weak var allviews: UILabel!
#IBOutlet weak var allphotos: UILabel!
var user : User!
var userposts = [String]()
var currentViewUser: String!
var floaty = Floaty()
let uid = KeychainWrapper.standard.string(forKey: KEY_UID)
override func awakeFromNib() {
super.awakeFromNib()
user = User()
fetchCurrentUser()
profilePic.addBlackGradientLayer(frame: profilePic.bounds)
layoutFAB()
}
func layoutFAB() {
floaty.openAnimationType = .slideDown
floaty.hasShadow = false
floaty.addItem("Edit Profile", icon: UIImage(named: "")) { item in
// here is where the segue is to be performed.
}
floaty.paddingY = (frame.height - 50) - floaty.frame.height/2
floaty.fabDelegate = self
floaty.buttonColor = UIColor.white
floaty.hasShadow = true
floaty.size = 45
addSubview(floaty)
}
func fetchCurrentUser(){
if uid != nil {
FBDataservice.ds.REF_CURR_USER.observeSingleEvent(of: .value, with: { (snapshot) in
if let allData = snapshot.value as? Dictionary<String, Any> {
if let cred = allData["credentials"] as? Dictionary<String, Any> {
let user = User(userid: snapshot.key, userData: cred)
self.pusername.text = user.username
self.pname.text = user.name
self.userDesc.text = user.aboutme
self.allphotos.text = String(user.photos)
self.allviews.text = String(user.views)
if user.userPic != nil {
let request = URL(string: user.userPic)
Nuke.loadImage(with: request!, into: self.profilePic)
} else {
return
}
}
}
})
}
}
}
CollectionViewController code:
class ProfileVC: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
#IBOutlet weak var collectionView: UICollectionView!
var user : User!
var userposts = [String]()
var post = [Posts]()
var currentViewUser: String!
var imagePicker: UIImagePickerController!
var fetcher: Fetcher!
var imageFromImagePicker = UIImage()
let uid = KeychainWrapper.standard.string(forKey: KEY_UID)
override func viewDidLoad() {
super.viewDidLoad()
user = User()
fetcher = Fetcher()
imagePicker = UIImagePickerController()
imagePicker.delegate = self
collectionView.delegate = self
collectionView.dataSource = self
initializeUserPost()
let nib = UINib(nibName: "ProfileCell", bundle: nil)
collectionView.register(nib, forCellWithReuseIdentifier: "ProfileCell")
}
func editProfileTapped() {
performSegue(withIdentifier: "manageconnections", sender: nil)
}
#IBAction func manageConnections(_ sender: Any) {
performSegue(withIdentifier: "manageconnections", sender: nil)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
collectionView.reloadData()
}
#IBAction func gotoSettings(_ sender: Any) {
performSegue(withIdentifier: "openSettings", sender: nil)
}
#IBAction func newPost(_ sender: Any) {
uploadNewPost()
}
#IBAction func backToFeed(_ sender: Any) {
performSegue(withIdentifier: "feedroute", sender: nil)
}
#IBAction func searchUsers(_ sender: Any) {
performSegue(withIdentifier: "searchNow", sender: nil)
}
func initializeUserPost() {
FBDataservice.ds.REF_POSTS.observe(.value, with: { (snapshot) in
if let snap = snapshot.value as? Dictionary<String, Any> {
for snapy in snap {
if let userimages = snapy.value as? Dictionary<String, Any> {
let author = userimages["author"] as? String
if author! == self.uid! {
let images = userimages["imageurl"] as? String
self.userposts.append(images!)
}
}
}
}
self.collectionView.reloadData()
})
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let userImages = userposts[indexPath.row]
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ProfileCell", for: indexPath) as! ProfileCell
cell.fillCells(uid: uid!, userPost: userImages)
return cell
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return userposts.count
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let selecteditem : String!
selecteditem = userposts[indexPath.row]
performSegue(withIdentifier: "lol", sender: selecteditem)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "lol" {
if let detailvc = segue.destination as? PhotoDetailVC {
if let bro = sender as? String {
detailvc.image = bro
}
}
}
}
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
let view = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "ProfileHeader", for: indexPath) as! ProfileHeader
return view
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = (collectionView.bounds.size.width/3) - 1
print(width)
let size = CGSize(width: width, height: width)
return size
}
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 1.0
}
func collectionView(_ collectionView: UICollectionView, layout
collectionViewLayout: UICollectionViewLayout,
minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 1.0
}
To solve your problem, you should use a pattern called delegate.
Delegate means that you need something to do the work of perform a segue for your HeaderView instead, something that can do it, in this case your ProfileVC.
1 - Create a protocol inside your HeaderView or another file, it's your call.
2 - Add a protocol variable type in your HeaderView as well and pass it from your viewController.
class ProfileHeader: UICollectionReusableView, FloatyDelegate {
#IBOutlet weak var pname: UILabel!
#IBOutlet weak var pusername: UILabel!
#IBOutlet weak var profilePic: UIImageView!
#IBOutlet weak var userDesc: UILabel!
#IBOutlet weak var allviews: UILabel!
#IBOutlet weak var allphotos: UILabel!
var user : User!
var userposts = [String]()
var currentViewUser: String!
var floaty = Floaty()
var delegate: HeaderViewDelegate!
let uid = KeychainWrapper.standard.string(forKey: KEY_UID)
override func awakeFromNib() {
super.awakeFromNib()
user = User()
fetchCurrentUser()
profilePic.addBlackGradientLayer(frame: profilePic.bounds)
layoutFAB()
}
func setDelegate(delegate: HeaderViewDelegate) {
self.delegate = delegate
}
func layoutFAB() {
floaty.openAnimationType = .slideDown
floaty.hasShadow = false
floaty.addItem("Edit Profile", icon: UIImage(named: "")) { item in
delegate.fabItemClicked()
}
floaty.paddingY = (frame.height - 50) - floaty.frame.height/2
floaty.fabDelegate = self
floaty.buttonColor = UIColor.white
floaty.hasShadow = true
floaty.size = 45
addSubview(floaty)
}
func fetchCurrentUser(){
if uid != nil {
FBDataservice.ds.REF_CURR_USER.observeSingleEvent(of: .value, with: { (snapshot) in
if let allData = snapshot.value as? Dictionary<String, Any> {
if let cred = allData["credentials"] as? Dictionary<String, Any> {
let user = User(userid: snapshot.key, userData: cred)
self.pusername.text = user.username
self.pname.text = user.name
self.userDesc.text = user.aboutme
self.allphotos.text = String(user.photos)
self.allviews.text = String(user.views)
if user.userPic != nil {
let request = URL(string: user.userPic)
Nuke.loadImage(with: request!, into: self.profilePic)
} else {
return
}
}
}
})
}
}
public protocol HeaderViewDelegate {
func fabItemClicked()
}
}
3 - Finally, edit your ProfileVC to implement the HeaderViewDelegate protocol and pass it to your HeaderView
class ProfileVC: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout, HeaderViewDelegate {
#IBOutlet weak var collectionView: UICollectionView!
var user : User!
var userposts = [String]()
var post = [Posts]()
var currentViewUser: String!
var imagePicker: UIImagePickerController!
var fetcher: Fetcher!
var imageFromImagePicker = UIImage()
let uid = KeychainWrapper.standard.string(forKey: KEY_UID)
override func viewDidLoad() {
super.viewDidLoad()
user = User()
fetcher = Fetcher()
imagePicker = UIImagePickerController()
imagePicker.delegate = self
collectionView.delegate = self
collectionView.dataSource = self
initializeUserPost()
let nib = UINib(nibName: "ProfileCell", bundle: nil)
collectionView.register(nib, forCellWithReuseIdentifier: "ProfileCell")
}
//Method from the new protocol
func fabItemClicked(){
//Perform your segue here.
}
func editProfileTapped() {
performSegue(withIdentifier: "manageconnections", sender: nil)
}
#IBAction func manageConnections(_ sender: Any) {
performSegue(withIdentifier: "manageconnections", sender: nil)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
collectionView.reloadData()
}
#IBAction func gotoSettings(_ sender: Any) {
performSegue(withIdentifier: "openSettings", sender: nil)
}
#IBAction func newPost(_ sender: Any) {
uploadNewPost()
}
#IBAction func backToFeed(_ sender: Any) {
performSegue(withIdentifier: "feedroute", sender: nil)
}
#IBAction func searchUsers(_ sender: Any) {
performSegue(withIdentifier: "searchNow", sender: nil)
}
func initializeUserPost() {
FBDataservice.ds.REF_POSTS.observe(.value, with: { (snapshot) in
if let snap = snapshot.value as? Dictionary<String, Any> {
for snapy in snap {
if let userimages = snapy.value as? Dictionary<String, Any> {
let author = userimages["author"] as? String
if author! == self.uid! {
let images = userimages["imageurl"] as? String
self.userposts.append(images!)
}
}
}
}
self.collectionView.reloadData()
})
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let userImages = userposts[indexPath.row]
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ProfileCell", for: indexPath) as! ProfileCell
cell.fillCells(uid: uid!, userPost: userImages)
return cell
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return userposts.count
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let selecteditem : String!
selecteditem = userposts[indexPath.row]
performSegue(withIdentifier: "lol", sender: selecteditem)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "lol" {
if let detailvc = segue.destination as? PhotoDetailVC {
if let bro = sender as? String {
detailvc.image = bro
}
}
}
}
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
let view = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "ProfileHeader", for: indexPath) as! ProfileHeader
view.delegate = self
return view
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = (collectionView.bounds.size.width/3) - 1
print(width)
let size = CGSize(width: width, height: width)
return size
}
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 1.0
}
func collectionView(_ collectionView: UICollectionView, layout
collectionViewLayout: UICollectionViewLayout,
minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 1.0
}
Don't forget to edit this method and pass self to your HeaderView:
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
let view = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "ProfileHeader", for: indexPath) as! ProfileHeader
view.delegate = self
return view
}

UICollectionView not loading on screen

I am trying to create a UICollectionView and its not loading on the screen. In my app delegate I even made it the entry screen and it does not appear just a black screen.
class ChatRoom: UIViewController, UINavigationControllerDelegate, UIImagePickerControllerDelegate, UICollectionViewDataSource, UICollectionViewDelegate {
// Struct of Objects
struct Object {
var image: UIImage!
var title: String!
}
// Properties
var object: Object?
var objects: [Object] = []
var picker: UIImagePickerController!
var ref: FIRDatabaseReference?
#IBOutlet weak var collectionView2: UICollectionView!
// Instance of a class
var secondClass : ChatCell?
// Do any additional setup after loading the view, typically from a nib.
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewDidLoad() {
super.viewDidLoad()
// Firebase Data
ref = FIRDatabase.database().reference()
// CollectionView
collectionView2?.delegate = self
collectionView2?.dataSource = self
collectionView2?.reloadData()
// User Logged In
checkIfUserLoggedIn()
picker = UIImagePickerController()
picker?.allowsEditing = false
picker?.delegate = self
picker?.sourceType = .photoLibrary
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! ChatCell
let object = objects[indexPath.row]
cell.chatLabel.text = object.title ?? ""
cell.chatImage.image = object.image ?? UIImage()
cell.layer.borderWidth = 2
cell.layer.borderColor = UIColor.white.cgColor
cell.layer.masksToBounds = true
cell.layer.cornerRadius = 6
return cell
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return objects.count
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let itemWidth = collectionView2.bounds.width
let itemHeight = collectionView2.bounds.height
return CGSize(width: itemWidth, height: itemHeight)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
switch info[UIImagePickerControllerOriginalImage] as? UIImage {
case let .some(image):
object?.image = image
default:
break
}
picker.dismiss(animated: true) {
self.showCellTitleAlert()
}
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
object = nil
dismiss(animated: true) {
self.collectionView2!.reloadData()
}
}
// Alerts
func showCellTitleAlert() {
let alert = UIAlertController(title: "Cell Title", message: nil, preferredStyle: .alert)
alert.addTextField { $0.placeholder = "Enter only 10 characters" }
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel) { _ in
self.object = nil
})
alert.addAction(UIAlertAction(title: "Save", style: .default) { _ in
self.object?.title = (alert.textFields?.first.flatMap { $0.text })!
self.object.flatMap { self.objects.append($0) }
self.collectionView2?.reloadData()
})
present(alert, animated: true, completion: nil)
}
// Create new Cell
#IBAction func didSelectCreateButton() {
object = Object()
present(picker, animated: true, completion: nil)
}
Here the collectionView appears blank because you are not filling the objects array which is the dataSource for the collectionView2.

How to display an Image in a new ViewController contain ImageView after download it from back endless database using Swift3

I'am using a UICollectionView to download and display Images from Backendless Database , How can I display these Images again in a ViewController that contain ImageView when I tap on any row of My CollectionView using Swift3 .
This is My CollectionView.
import UIKit
import SDWebImage
class GallaryCollectionViewController: UICollectionViewController {
var GallaryArray = [TestTable]()
let backendless = Backendless()
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
loaddatawithquery()
}
// MARK: UICollectionViewDataSource
override func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return GallaryArray.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as? GallaryCell {
let ImgURL = URL(string : self.GallaryArray[(indexPath as NSIndexPath).row].ImgURL!)
cell.GallImag.sd_setImage(with: ImgURL)
cell.ShowImg = {
if let myimage = (cell.GallImag.image) {
// Error here How to complete the code ?
}
}
return cell
}
else {
let cell = GallaryCell()
let ImgURL = URL(string : self.GallaryArray [(indexPath as NSIndexPath).row].ImgURL)
cell.GallImag.sd_setImage(with: ImgURL)
cell.ShowImg = {
if let myimage = (cell.GallImag.image) {
}
}
return cell
}
}
func loaddatawithquery() {
let dataQuery = BackendlessDataQuery()
dataQuery.queryOptions.pageSize = 50
backendless.data.of(TestTable.ofClass()).find(dataQuery,response: {( result: BackendlessCollection?) -> Void in
let data = result?.getCurrentPage()
for obj in data! as! [TestTable] {
self.GallaryArray.append(obj)
self.collectionView?.reloadData()
}
}, error: { (fault: Fault?) -> Void in
let alert = UIAlertController(title: "انتباه", message:"يرجى الاتصال بالانترنيت", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default) { _ in })
self.present(alert, animated: true){}
})
}
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {}
}
And this is My Cell.
import UIKit
class GallaryCell: UICollectionViewCell {
#IBOutlet weak var GallImag: UIImageView!
var ShowImg : (() ->Void)?
func setSelected(_ selected: Bool, animated: Bool) {
setSelected(selected, animated: animated)
self.ShowImg!()
}
}
I'm going to assume you have your images loading correctly in the collection view.
there is a delegate method you can use called didSelectRow...
func collectionView(_ collectionView: UICollectionView, didSelectRowAt indexPath: IndexPath) {
self.passingTestTable = self.GallaryArray[indexPath.row]
self.performSegue(withIdentifier: "segue for new view controller", sender: nil)
}
self.passingTestTable is another property you create globally at the top of TestTable() (this is how I do it, some may choose to create the instance inside the didSelectRow
the other thing you'll need to do is create an instance of TestTable on the receiving viewController (i.e self.receivedTestTable )
in prepare for segue you can select the item selected and send it over to the new viewController
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "yourSegueName" {
if let controller = segue.destination as? PassedImageDetailViewController {
controller.receivedTestTable = self.passingTestTable
}
else {
print("Your segue identifier is incorrect")
}
}
}
once you've done that, the detail View Controller has access to the image data and you can display in in an image view on that screen.

UICollectionView Functionality issues

I have a UICollectionViewCell on VC1, The cell contains, a image, a label, and 3 buttons.
When i click on the cell. That triggers my didSelectItemAtIndexPath to take me to an Edit item screen.
How can i access each button and relate it to the cell i am clicking on?
So if i have added 6 cells, and i click on cell 1, button 1, it takes me to a bio page with info on that person. if i click on cell 2 button 1, it brings me to same bio VC but with different info related to the cell i clicked on.
My confusion lies in where or how to set this up?
Thank you!
import UIKit
import Parse
class TrainersViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, AddNewTrainerViewControllerDelegate {
var trainers: [TrainerArray]
required init?(coder aDecoder: NSCoder) {
trainers = [TrainerArray]()
super.init(coder: aDecoder)
loadTrainerItems()
}
//connection to the collection view
#IBOutlet weak var collectionView: UICollectionView!
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
print("selected")
saveTrainerItems()
}
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return trainers.count
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("TrainerCell", forIndexPath: indexPath)
var buttonOne = cell.viewWithTag(10)
buttonOne = indexPath.row
let trainer = trainers[indexPath.row]
configureTrainerForCell(cell, withTrainerArray: trainer)
return cell
}
func configureTrainerForCell(cell: UICollectionViewCell, withTrainerArray trainer: TrainerArray) {
if trainer.trainerImage == nil {
let label = cell.viewWithTag(1000) as! UILabel
trainer.trainerImage = UIImage(named: "defaultImage")
label.text = trainer.name
} else {
let image = cell.viewWithTag(2000) as! UIImageView
image.image = trainer.trainerImage
let label = cell.viewWithTag(1000) as! UILabel
label.text = trainer.name
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//This method adds a new trainer to the trainer array
func addNewTrainerViewController(controller: AddNewTrainerViewController, didFinishAddingItem item: TrainerArray) {
let newRowIndex = trainers.count
trainers.append(item)
let indexPath = NSIndexPath(forRow: newRowIndex, inSection: 0)
let indexPaths = [indexPath]
collectionView.insertItemsAtIndexPaths(indexPaths)
dismissViewControllerAnimated(true, completion: nil)
saveTrainerItems()
}
func addNewTrainerViewController(controller: AddNewTrainerViewController, didFinishDeletingItem item: TrainerArray) {
if let index = trainers.indexOf(item) {
let indexPath = NSIndexPath(forRow: index, inSection: 0)
let indexPaths = [indexPath]
if let _ = collectionView.cellForItemAtIndexPath(indexPath) {
self.trainers.removeAtIndex(index)
self.collectionView.deleteItemsAtIndexPaths(indexPaths)
}
}
dismissViewControllerAnimated(true, completion: nil)
saveTrainerItems()
}
//This Method Edits a Trainer
func addNewTrainerViewController(controller: AddNewTrainerViewController, didFinishEditingItem trainer: TrainerArray) {
if let index = trainers.indexOf(trainer) {
let indexPath = NSIndexPath(forRow: index, inSection: 0)
if let cell = collectionView.cellForItemAtIndexPath(indexPath){
configureTrainerForCell(cell, withTrainerArray: trainer)
}
}
saveTrainerItems()
dismissViewControllerAnimated(true, completion: nil)
}
func addNewTrainerViewControllerDidCancel(controller: AddNewTrainerViewController) {
dismissViewControllerAnimated(true, completion: nil)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "AddTrainer" {
let navigationController = segue.destinationViewController as! UINavigationController
let controller = navigationController.topViewController as! AddNewTrainerViewController
controller.delegate = self
} else if segue.identifier == "EditTrainer" {
let navigationController = segue.destinationViewController as! UINavigationController
let controller = navigationController.topViewController as! AddNewTrainerViewController
controller.delegate = self
if let indexPath = collectionView.indexPathForCell(sender as! UICollectionViewCell) {
controller.trainerToEdit = trainers[indexPath.row]
}
}
}
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
}
func documentsDirectory() -> String {
let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
return paths[0]
}
func dataFilePath() -> String {
return (documentsDirectory() as NSString)
.stringByAppendingPathComponent("Trainers.plist")
}
func saveTrainerItems() {
let data = NSMutableData()
let archiver = NSKeyedArchiver(forWritingWithMutableData: data)
archiver.encodeObject(trainers, forKey: "TrainersArray")
archiver.finishEncoding()
data.writeToFile(dataFilePath(), atomically: true)
}
func loadTrainerItems() {
let path = dataFilePath()
if NSFileManager.defaultManager().fileExistsAtPath(path) {
if let data = NSData(contentsOfFile: path) {
let unarchiver = NSKeyedUnarchiver(forReadingWithData: data)
trainers = unarchiver.decodeObjectForKey("TrainersArray") as! [TrainerArray]
unarchiver.finishDecoding()
}
}
}
#IBAction func logOut(sender: AnyObject) {
let alert = UIAlertController(title: "Are You Sure You Want To Log Out?", message: "Please Enter Your Username", preferredStyle: UIAlertControllerStyle.Alert)
alert.addTextFieldWithConfigurationHandler { (textField) -> Void in
}
alert.addAction(UIAlertAction(title: "Log Out", style: UIAlertActionStyle.Default, handler: { (action) -> Void in
let textF = alert.textFields![0] as UITextField
if textF.text! != PFUser.currentUser()?.username {
self.displayGenericAlert("Incorrect Username!", message: "Please Enter a Valid Username")
} else if textF.text! == PFUser.currentUser()?.username {
PFUser.logOut()
_ = PFUser.currentUser()
self.dismissViewControllerAnimated(true, completion: nil)
}
}))
alert.addAction(UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Default, handler: { (action) -> Void in
if action == true {
self.dismissViewControllerAnimated(false, completion: nil)
}}))
self.presentViewController(alert, animated: true, completion: nil)
}
func displayGenericAlert(title: String, message: String) {
let alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "Ok", style: .Default, handler: { (action) -> Void in
}))
self.presentViewController(alert, animated: true, completion: nil)
}
#IBAction func bioSegueButton(sender: AnyObject) {
}
}
You can get data from your array from index 'indexpath.row' .
You can add a tag to the button that corresponds to the index of the cell it is in. In the cellForItemAtIndexPath you would add something like...
button.tag = indexPath.row
And in the selector for the button you can access it...
func buttonSelector(sender: UIButton) {
let index = sender.tag
let trainer = trainers[index]
}
EDIT:
A more complete version of what you might do in cellForRowAtIndexPath:
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("TrainerCell", forIndexPath: indexPath) as? MyCollectionViewCell
var buttonOne = cell?.button1
buttonOne?.tag = indexPath.row
let trainer = trainers[indexPath.row]
configureTrainerForCell(cell, withTrainerArray: trainer)
return cell!
}
Your collection view cell class:
class MyCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var button1: UIButton! // connect this to the button in your interface builder's collection view cell.
// Do the same for any other subviews.
}
Also in interface builder change the class of the collection view cell prototype to this new custom class.

Resources