I would like to preface this by saying I am new to iOS.
I am currently trying to create a side push menu that when clicked on has icons beside each menu item. I currently have the side push menu working with several menu items listed, however, I am really struggling trying to get the images beside each item.
I have written the side push menu and list items programmatically with the code below.
import UIKit
class SideMenuTable: UITableViewController {
let sideMenuImages = [UIImage(named: "Main"), UIImage(named: "Departments"), UIImage(named: "Deliveries"), UIImage(named: "Warehouse"), UIImage(named: "Help")]
var menu = [Menu]()
#IBOutlet weak var test: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
self.title = "Change Menu View"
menu = [
Menu(title: "Main"),
Menu(title: "Departments"),
Menu(title: "Deliveries"),
Menu(title: "Warehouse"),
Menu(title: "Help")
]
}
override func viewWillAppear(_ animated: Bool) {
if tableView.isHidden {
if let selectionIndexPath = tableView.indexPathForSelectedRow {
tableView.deselectRow(at: selectionIndexPath, animated: animated)
}
} else if tableView.isFocused {
if let selectionIndexPaths = tableView.indexPathForSelectedRow {
tableView.deselectRow(at: selectionIndexPaths, animated: animated)
}
}
super.viewWillAppear(animated)
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return menu.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "sideCell", for: indexPath)
let menuSide: Menu
// var image: UIImage = UIImage(named: ".png")
menuSide = menu[indexPath.row]
cell.textLabel!.text = menuSide.title
cell.textLabel?.textAlignment = .center
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if(indexPath.section == 1) {
if(indexPath.row == 3) {
dismiss(animated: true, completion: nil)
performSegue(withIdentifier: "Warehouse", sender: self)
} else {
NSLog("NO SELECTION AVAILABLE")
}
}
}
}
As you can see from the picture below.
]1
I have started to attempt to solve my problem by inserting a UIImage into the prototype cells.
However, when I connect the UIImage as an outlet into the code above I receive this error. (NOTE: in the code above the outlet is named test)
It is here where I am getting stuck.
I need to connect this outlet in order to add icons for the various menu items I have.
What am I missing?
Is there a different solution to this problem of creating icons for menu items?
Do I need to create a separate subclass?
You need to create a custom class for UITableviewcell where you need to create IBOutlet to imageview and label.
Now you can access it in your cellForRowAtIndexPath method.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "sideCell", for: indexPath) as YourCustomCell
let menuSide: Menu
var image: UIImage = UIImage(named: ".png")
menuSide = menu[indexPath.row]
cell.customLabel!.text = menuSide.title
cell.customLabel?.textAlignment = .center
Cell.imgViewName.image = image
return cell
}
Here customLabel and imgViewName is the name of your IBOutlets which you need to drag in you custom cell from storyboard also provide the name of custom cell in your storyboard by selecting that particular cell.
if your not want to create custom class then please set any tag on your uiimageview and uilabel and use as below
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let lblmenu : UILabel = cell.contentView.viewWithTag(12) as! UILabel
lblmenu.text = ArrMenuoption[indexPath.row] as? String
let img : UIImageView = cell.contentView.viewWithTag(11) as! UIImageView
img.image = UIImage.init(named: ArrMenuoptionimg[indexPath.row] as! String )
return cell }
Related
I am having a problem with my navigation title and setting it with code.
Here is the structure of my code:
Navigation Controller -> TableView -> UIScreen where i want to set the title.
Here is my code:
TableViewController:
import UIKit
class ProductsTableViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UserCell.self, forCellReuseIdentifier: cellId)
}
let cellId = "cellId"
let products = [
"Happy Face",
"Sad Face",
"High Five",
"Angry Face",
"The Earth"
]
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return products.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as! UserCell
let product = products[indexPath.row]
cell.textLabel?.text = product
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let buyProductViewController = BuyProductViewController()
let product = products[indexPath.row]
buyProductViewController.nameOfItem = product
buyProductViewController.navigationItem.title = product
performSegue(withIdentifier: "segue", sender: self)
}
}
class UserCell: UITableViewCell {
}
Setting my title View Controller:
import UIKit
class BuyProductViewController: UIViewController {
var nameOfItem: String? {
didSet {
print(nameOfItem)
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
I would very much appreciate if any1 could help me because I am very upset and have been working on this over a week and only just came across stack overflow.
Thanks.
This will work for you if:
1. ProductsTableViewController is embedded in UINavigationController;
2. Segue with identifier "segue" is push. Note the difference is directly setting the title of your pushed controller. NavigationBar automatically uses the displayed VC's title as navigation bar title.
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let buyProductViewController = BuyProductViewController()
let product = products[indexPath.row]
buyProductViewController.nameOfItem = product
buyProductViewController.title = product
performSegue(withIdentifier: "segue", sender: self)
}
Please check you have to set title in BuyProductViewController:
import UIKit
class BuyProductViewController: UIViewController {
var nameOfItem: String? {
didSet {
print(nameOfItem)
}
}
override func viewDidLoad() {
super.viewDidLoad()
self.title = nameOfItem
}
}
I'm working on a project coded in swift 3 and I have a UIButton inside a UITableViewCell where the image changes once the button is tapped. Though the selected buttons get selected as intended, once the UITableview scrolls the selected images gets disappear since the cells are been reused. As I'm new to programming having troubles of writing the logic. Help would much appreciate the code as bellow.
CellFoRow
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
//Button_Action
addSongButtonIdentifier(cell: cell, indexPath.row)
}
This is where the cell is been created.
func addSongButtonIdentifier(cell: UITableViewCell, _ index: Int) {
let addButton = cell.viewWithTag(TABLE_CELL_TAGS.addButton) as! UIButton
//accessibilityIdentifier is used to identify a particular element which takes an input parameter of a string
//assigning the indexpath button
addButton.accessibilityIdentifier = String (index)
// print("visible Index:",index)
print("Index when scrolling :",addButton.accessibilityIdentifier!)
addButton.setImage(UIImage(named: "correct"), for: UIControlState.selected)
addButton.setImage(UIImage(named: "add_btn"), for: UIControlState.normal)
addButton.isSelected = false
addButton.addTarget(self, action: #selector(AddToPlaylistViewController.tapFunction), for:.touchUpInside)
}
the tap function
func tapFunction(sender: UIButton) {
print("IndexOfRow :",sender.accessibilityIdentifier!)
// if let seporated by a comma defines, if let inside a if let. So if the first fails it wont come to second if let
if let rowIndexString = sender.accessibilityIdentifier, let rowIndex = Int(rowIndexString) {
self.sateOfNewSongArray[rowIndex] = !self.sateOfNewSongArray[rowIndex]//toggle the state when tapped multiple times
}
sender.isSelected = !sender.isSelected //image toggle
print(" Array Data: ", self.sateOfNewSongArray)
selectedSongList.removeAll()
for (index, element) in self.sateOfNewSongArray.enumerated() {
if element{
print("true:", index)
selectedSongList.append(songDetailsArray[index])
print("selectedSongList :",selectedSongList)
}
}
}
You need to maintain the button selection status at the controller level. You need to make changes to the model that you are using to configure your tableview.
I have created a similar scenario. I have used an array selectionStatusArray to maintain the button's selection status.
Example:
1. UIViewController containing UITableView
class ViewController: UIViewController, UITableViewDataSource
{
#IBOutlet weak var tableView: UITableView!
var selectionStatusArray = [false, false, false, false, false] //Array that maintains the button selection status
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return selectionStatusArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! TableViewCell
addSongButtonIdentifier(cell: cell, indexPath.row)
return cell
}
func addSongButtonIdentifier(cell: TableViewCell, _ index: Int)
{
cell.addButton.tag = index
cell.addButton.isSelected = selectionStatusArray[index]
cell.tapHandler = {
self.selectionStatusArray[$0] = cell.addButton.isSelected
}
}
}
2. Custom UITableViewCell
class TableViewCell: UITableViewCell
{
#IBOutlet weak var addButton: UIButton!
var tapHandler: ((Int)->())?
#IBAction func tapFunction(_ sender: UIButton)
{
sender.isSelected = !sender.isSelected
tapHandler?(sender.tag)
}
}
You can configure the UITableViewCell according to your requirements.
You have this code addButton.isSelected = false which is causing the problem because I believe you are calling the function addSongButtonIdentifier inside tableView delegate method, you should not set all those property inside tableView delegate.
Instead you should do it initially and only once for each of your cell like either in storyboard itself or by providing a model to cell class.
I tried to use this solution but is not working.
what I want i s a button in my customized cell that knows data from the array that is used from the tableview (later I'll apply it to CoreData), for example, print the value of the array that generated the tableview.
but I cannot understand how to do it
I have a customized cell class, where I tried to use both a button action or a outlet button (with tags):
import UIKit
class MyTableViewCell: UITableViewCell {
#IBOutlet weak var myCellImage: UIImageView!
#IBOutlet weak var myCellLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
and a ViewController where is my tableview with an extension
extension ViewController {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return comicsArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = myTableView.dequeueReusableCell(withIdentifier: "myCell", for: indexPath) as! MyTableViewCell
cell.myCellLabel.text = String(indexPath.row)
cell.myCellButton.tag = indexPath.row
cell.myCellButton.addTarget(self, action: Selector("logAction:"), for: .touchUpInside)
return cell
}
func logAction(sender: UIButton) {
let titleString = self.comicsArray[sender.tag]
let firstActivityItem = "\(titleString)"
let activityVC = UIActivityViewController(activityItems: [firstActivityItem], applicationActivities: nil)
self.present(activityVC, animated: true, completion: nil)
}
}
EDIT:
solved with help of abdullahselek by adding in subclasses cell:
public var dataFromTableView : String!
and implementing:
#IBAction func myCellButtonTapped(_ sender: UIButton) {
guard dataFromTableView != nil else {return}
print("pushed \(dataFromTableView!)")
}
and in cellForRowAt :
cell.data = comicsArray[indexPath.row]
Add a dictionary or object model property to your custom tableviewcell like
public var data: Dictionary!
And set this data property
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
...
cell.data = comicsArray[indexPath.row]
}
Then you button can reach data with in your tableviewcell
I have a tableView with custom cell. in my custom cell I have a like button. for like Button I wrote a function to change state from .normal to .selected like this:
FeedViewCell
class FeedViewCell: UITableViewCell {
#IBOutlet weak var likeButton: UIButton!
var likes : Bool {
get {
return UserDefaults.standard.bool(forKey: "likes")
}
set {
UserDefaults.standard.set(newValue, forKey: "likes")
}
}
override func awakeFromNib() {
super.awakeFromNib()
self.likeButton.setImage(UIImage(named: "like-btn-active"), for: .selected)
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
#IBAction func likeBtnTouch(_ sender: AnyObject) {
print("press")
// toggle the likes state
self.likes = !self.likeButton.isSelected
// set the likes button accordingly
self.likeButton.isSelected = self.likes
}
}
FeedViewController :
class FeedViewController: UIViewController {
#IBOutlet var feedTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Register Cell Identifier
let feedNib = UINib(nibName: "FeedViewCell", bundle: nil)
self.feedTableView.register(feedNib, forCellReuseIdentifier: "FeedCell")
}
func numberOfSectionsInTableView(_ tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.feeds.count
}
func tableView(_ tableView: UITableView, heightForRowAtIndexPath indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, cellForRowAtIndexPath indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "FeedCell", for: indexPath) as! FeedViewCell
return cell
}
}
But my problem is when I tap like button in cell with indexPath.row 0 the state of button in cell with indexPath.row 3 change state too.
where is my mistake?
thanks
You didn't post all your code, but I can tell you that for this to work the #IBAction func likeBtnTouch(_ sender: AnyObject) { } definition must be inside the FeedViewCell class definition to make it unique to a particular instance of the cell.
As a rule of thumb, I normally ensure that all the UI elements inside my cell are populated in cellForRowAtIndexPath when using dequeued cells. Also it should be set from an external source. I.o.w not from a property inside the cell. Dequeuing cells reuse them, and if not setup properly, it might have some leftovers from another cell.
For example, inside cellForRowAtIndexPath:
self.likeButton.isSelected = likeData[indexPath.row]
I've been writing a small Swift app.
I'm now using a tableview and try to select a row, change an image and deselect the row.
My custom UITableViewCell class looks like this:
class SelectFriendTableViewCell: UITableViewCell {
#IBOutlet weak var friendNameLabel: UILabel!
#IBOutlet weak var friendSelectedImage: UIImageView!
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
And my TableViewController has these functions:
Building the cells:
//Build the cell
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("SelectFriend", forIndexPath: indexPath) as! SelectFriendTableViewCell
//Default image is unselected
cell.friendSelectedImage.image = UIImage(named: "unselected")
//Get the label text
cell.friendNameLabel.text = friendList[indexPath.row]
return cell
}
Do stuff when cell is selected (didSelectRowAtIndexPath)
//Cell was selected
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let cell = tableView.dequeueReusableCellWithIdentifier("SelectFriend", forIndexPath: indexPath) as! SelectFriendTableViewCell
//Check wheter the cell is or not selected
if(cell.friendSelectedImage.image == UIImage(named: "unselected"))
{
//if it's unselected, select it and add the user to the invited list
cell.friendSelectedImage.image = UIImage(named: "selected")
//Add to the invited list, the label can't be null
invitedList += [cell.friendNameLabel.text!]
}
else if(cell.friendSelectedImage.image == UIImage(named: "selected"))
{
//if it's selected, unselect it and remove the user from the invited list
cell.friendSelectedImage.image = UIImage(named: "unselected")
//Find the invited in the array and remove it
for(var i=0; i < invitedList.count; i++)
{
if(invitedList[i] == cell.friendNameLabel.text!)
{
invitedList.removeAtIndex(i)
break
}
}
}
else
{
print("error geting image")
}
//Trying to deselect the row, doesn't seem to be working
tableView.deselectRowAtIndexPath(indexPath, animated: false)
}
What I'm seeing:
There's also the problem that the label is disappearing.
dequeueReusableCellWithIdentifier did not get the previous cell, you should use cellForRowAtIndexPath
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
//get the cell,
let cell = tableView.cellForRowAtIndexPath(indexPath) as! SelectFriendTableViewCell
//do some work
}