I'm pretty new to swift but I've managed to follow along for the most part. However, there's an issue with my code that the code itself can't even identity apparently(I'm not receiving any error signs). I'm trying to click on a row from the table view to make it go to the following page but I don't think the code is recognizing the didselectrow method. Maybe one of you more experienced persons can help me out.
Here's the code:
import UIKit
import Foundation
class OnePercentersViewController: UIViewController, UITableViewDataSource
{
var copiedExecutiveArray : [String] = NSArray() as! [String]
var identities : [String] = NSArray() as! [String]
override func viewDidLoad()
{
super.viewDidLoad()
let copyExecutiveNames : ExecutiveArray = ExecutiveArray()
copiedExecutiveArray = copyExecutiveNames.executiveNames
identities = copyExecutiveNames.executiveNames
}
//how many sections in table
func numberOfSections(in tableView: UITableView) -> Int
{
return 1
}
//returns int (how many rows)
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return copiedExecutiveArray.count
}
//contents of each cell
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell")//UITableViewCell()
let personName = copiedExecutiveArray[indexPath.row]
cell?.textLabel?.text = personName
return cell!
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
let execName = identities[indexPath.row]
let viewController = storyboard?.instantiateViewController(withIdentifier: execName)
self.navigationController?.pushViewController(viewController!, animated: true)
print("button clicked")
tableView.deselectRow(at: indexPath as IndexPath, animated: true)
}
}
I haven't checked other parts of your code, but to make tableView(_:didSelectRowAt:) work, your ViewController needs to conform to UITableViewDelegate:
class OnePercentersViewController: UIViewController, UITableViewDataSource, UITableViewDelegate
Also you need to connect the delegate of the UITableView to your ViewController in your storyboard. Or you can do it in code, if you have an #IBOutlet to the UITableView. Anyway, not only dataSource, but also delegate.
And this is not a critical issue, but you can write the first two lines of the class as:
var copiedExecutiveArray : [String] = []
var identities : [String] = []
After spending a day and a half watching Youtube videos and reading comments to similar problems, tt took trial and error but I finally got it thanks to you guys!It finally clicked when I read that I had to connect the delegate to the ViewController through the storyboard, so thanks for that!
Here's the final code for those with similar issue:
import UIKit
import Foundation
class OnePercentersViewController: UIViewController,UITableViewDataSource, UITableViewDelegate
{
var copiedExecutiveArray : [String] = []
var identities : [String] = []
override func viewDidLoad()
{
super.viewDidLoad()
let copyExecutiveNames : ExecutiveArray = ExecutiveArray()
copiedExecutiveArray = copyExecutiveNames.executiveNames
identities = copyExecutiveNames.executiveNames
}
//how many sections in table
func numberOfSections(in tableView: UITableView) -> Int
{
return 1
}
//returns int (how many rows)
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return copiedExecutiveArray.count
}
//contents of each cell
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
let personName = copiedExecutiveArray[indexPath.row]
cell.textLabel?.text = personName
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
let execName = identities[indexPath.row]
let viewController = storyboard?.instantiateViewController(withIdentifier: execName)
self.navigationController?.pushViewController(viewController!, animated: true)
tableView.deselectRow(at: indexPath as IndexPath, animated: true)
}
}
Related
I use below code for get selected items of tab bar controller. My UITabbar has 7 view controllers(there are 3 items in More tab).
this code work only for 5 tabs but it don`t return selected index of items on More!
import UIKit
class CustomTabbarController: UITabBarController{
override func viewDidLoad() {
super.viewDidLoad()
self.delegate = self
}
override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
print(self.selectedIndex)
}
}
Following code worked for me. I had to redesign moreTableView to follow my app design. Function 'didSelectRowAt' returns what index is selected.
This code is added to 'UITabBarController' class.
var moreTableView: UITableView?
weak var currentTableViewDelegate: UITableViewDelegate?
func customizeMoreTableView() {
moreTableView = moreNavigationController.topViewController?.view as? UITableView
currentTableViewDelegate = moreTableView?.delegate
moreTableView?.delegate = self
moreTableView?.dataSource = self
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return (viewControllers?.count ?? 4) - 4
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let moreCell = UITableViewCell()
let item = viewControllers?[indexPath.row + 4].tabBarItem
moreCell.textLabel?.text = item?.title
moreCell.textLabel?.textColor = .white
moreCell.imageView?.image = item?.image
moreCell.imageView?.tintColor = .white
moreCell.backgroundColor = .black
return moreCell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
currentTableViewDelegate?.tableView!(tableView, didSelectRowAt: indexPath)
}
Get selected item like this :
override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
print(tabBar.items?.index(of: item))
}
I am trying to make it when the users clicks on Button in a table view cell it takes them to a new view controller related to the current cell.
Try the below code,
Do this in cellForRowAt indexPath,
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell_Identifier", for: indexPath) as! UITableViewCell
cell.myButton.isUserInteractionEnabled = true
cell.myButton.tag = indexPath.row
cell.myButton.addTarget(self, action: #selector(didTapMyButton(_:)), for: UIControlEvents.touchUpInside)
return cell
}
And here is the button action,
func didTapMyButton(_ sender : UIButton) {
let selectedIndex = sender.tag // You can get index here, so according to the index you can navigate to particular ViewController
let nextVC = self.storyboard?.instantiateViewController(withIdentifier: "UIViewController_identifier") as! UIViewController
self.present(nextVC, animated: true, completion: nil)
}
Hope it helps ..
It's been awhile since I've made a fool of myself here, so here goes again as I'm still trying to learn and feel as though I'm chasing my tail on this project.
With that said, ultimately I would like to get Jerkoch's SwipeCellKit to work, but not necessary at this point as I just need to figure out how to add more options other than just the 'delete' cell action.
This is what I've got: My Project
This is what I'd like: Jerkoch's Project
I loose my data if I set the delegate property on tableView from
let cell = tableView.dequeueReusableCell(withIdentifier: "CommentCell", for: indexPath) as! CommentTableViewCell
to
let cell = tableView.dequeueReusableCell(withIdentifier: "CommentCell", for: indexPath) as! SwipeTableViewCell
Here is my CommentViewController Code:
import UIKit
import SwipeCellKit
class CommentViewController: UIViewController {
var postId: String!
var comments = [Comment]()
var users = [User]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.tableFooterView = UIView(frame: CGRect.zero)
tableView.separatorInset = UIEdgeInsets.zero
tableView.dataSource = self
tableView.estimatedRowHeight = 100
tableView.rowHeight = UITableViewAutomaticDimension
loadComments()
}
func loadComments() {
Api.Post_Comment.REF_POST_COMMENTS.child(self.postId).observe(.childAdded, with: {
snapshot in
Api.Comment.observeComments(withPostId: snapshot.key, completion: {
comment in
self.fetchUser(uid: comment.uid!, completed: {
self.comments.append(comment)
self.tableView.reloadData()
})
})
})
}
func fetchUser(uid: String, completed: #escaping () -> Void ) {
Api.User.observeUser(withId: uid, completion: {
user in
self.users.append(user)
completed()
})
}
}
extension CommentViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return comments.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CommentCell", for: indexPath) as! CommentTableViewCell// Can't update this to SwipeTableViewCell - Will loose data
cell.selectedBackgroundView = createSelectedBackgroundView()
let comment = comments[indexPath.row]
let user = users[indexPath.row]
cell.comment = comment
cell.user = user
cell.delegate = self
return cell
}
}
extension CommentViewController: SwipeTableViewCellDelegate{
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
}
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath, for orientation: SwipeActionsOrientation) -> [SwipeAction]? {
guard orientation == .right else { return nil }
let deleteAction = SwipeAction(style: .destructive, title: "Delete") { action, indexPath in
// handle action by updating model with deletion
}
// customize the action appearance
deleteAction.image = UIImage(named: "delete")
let flagAction = SwipeAction(style: .destructive, title: "Flag") { action, indexPath in
// handle action
}
deleteAction.image = UIImage(named: "flag")
let blockAction = SwipeAction(style: .destructive, title: "Block") { action, indexPath in
// handle action
}
deleteAction.image = UIImage(named: "block")
return [deleteAction, flagAction, blockAction]
}
}
I've even tried something like the following:
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
// THIS GIVES THE DEFAULT 'DELETE' ACTION
print("Commit editingStyle")
}
func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]? {
print("editActionsForRowAtIndexPath")
let blockAction = UITableViewRowAction(style: UITableViewRowActionStyle.normal, title: "Block", handler: { (action:UITableViewRowAction, IndexPath:IndexPath) in
//self.isEditing = false
print("Block action Pressed")
})
let flagAction = UITableViewRowAction(style: UITableViewRowActionStyle.normal, title: "Flag", handler: { (action:UITableViewRowAction, IndexPath:IndexPath) in
print("Flag action Pressed")
})
let deleteAction = UITableViewRowAction(style: UITableViewRowActionStyle.destructive, title: "Delete", handler: { (action:UITableViewRowAction, IndexPath:IndexPath) in
print("Delete action Pressed")
})
return [blockAction, flagAction, deleteAction]
}
No matter what I do, I can't get more than just the generic 'Delete' action to show on a swipe action.
I don't even think the following function is being called/referenced:
func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]? {
What am I doing wrong, or what do I need to CUD to get 3 swipe actions; Delete, Flag and Block, to make Apple happy for my next submission.
Thank you all in advance!
This question is outdated but i'll write the answer which i think would have done the trick :)
You should be using UITableViewController not UIViewController for your view. SwipeCellKit only works with TableViewControllers.
I've got a simple to do list app, and I would like the items in the list to appear after the app is closed. What I have so far does not do it, not sure if everything is in the right place?
Code in my first ViewController:
var list = [String]()
class FirstViewController: UIViewController,UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var myTableView: UITableView!
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return list.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: "cell")
cell.textLabel?.text = list[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if (editingStyle == UITableViewCellEditingStyle.delete) {
list.remove(at: indexPath.row)
myTableView.reloadData()
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(_ animated: Bool) {
myTableView.reloadData()
if let x = UserDefaults.standard.object(forKey: "cell") as? [String]! {
list = x
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
Code in my second ViewController:
class SecondViewController: UIViewController {
#IBOutlet weak var input: UITextField!
#IBAction func addItemButton(_ sender: AnyObject) {
list.append(input.text!)
input.text = ""
UserDefaults.standard.set(input.text, forKey: "cell")
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
You are reloading the tableview at viewDidAppear before getting the data. Get your data from user defaults first (set list) and then reload the table view.
Hint:-
override func viewDidAppear(_ animated: Bool) {
if let x = UserDefaults.standard.object(forKey: "cell") as? [String]! {
list = x
myTableView.reloadData()
}
}
Repeated on two projects and searched in vain so I hope someone can help...
Created a basic TableViewController and one TableViewCell. Run and press the first button, scroll down and other random buttons also show the same change?
TableViewController
import UIKit
class TableViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 99
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ButtonCell", for: indexPath) as! ButtonCell
cell.rowLabel.text = "\(indexPath.row)"
cell.tapAction = { (cell) in
self.showAlertForRow(tableView.indexPath(for: cell)!.row)
}
return cell
}
// MARK: - Extracted method
func showAlertForRow(_ row: Int) {
let alert = UIAlertController(
title: "BEHOLD",
message: "Cell at row \(row) was tapped!",
preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Gotcha!", style: UIAlertActionStyle.default, handler: { (test) -> Void in
self.dismiss(animated: true, completion: nil)
}))
self.present(
alert,
animated: true,
completion: nil)
}
}
Table View Cell
// ButtonCell.swift
import UIKit
class ButtonCell: UITableViewCell {
var tapAction: ((UITableViewCell) -> Void)?
#IBOutlet weak var rowLabel: UILabel!
#IBOutlet weak var button: UIButton!
#IBAction func buttonTap(_ sender: AnyObject) {
button.setTitle("Correct", for: .normal)
tapAction?(self)
}
}
Lets begin with the basics. You don't need this:
cell.tapAction = { (cell) in
self.showAlertForRow(tableView.indexPath(for: cell)!.row)
}
You better use the apple framework:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
showAlertForRow(indexPath.row)
}
Second create a method in you cell like
import UIKit
class ButtonCell: UITableViewCell {
var tapAction: ((UITableViewCell) -> Void)?
#IBOutlet weak var rowLabel: UILabel!
#IBOutlet weak var button: UIButton!
#IBAction func buttonTap(_ sender: AnyObject) {
button.setTitle("Correct", for: .normal)
tapAction?(self)
}
func createCell() {
button.setTitle("Your button title", for: normal)
}
}
and call the createCell method in your
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
...
cell.createCell()
...
}
Hope I could help but try to start with the basics here: https://developer.apple.com/reference/uikit/uitableviewdelegate
This is happening because you are dequeuing your UITableViewCells. In order to solve the problem you should use the prepareForReuse() method in your ButtonCell. You can save the states of all your buttons and when a cell is being dequeued you can just set the title of the button in this cell in the prepareForReuse() method.