I have a main menu in my app with 15 item and each item has a sub of 20 items which i also added them as images array (15 image array , some thing like a restaurant menu ) so when ever the user clicks on 1 of the main menu items the app will take him to the sub menu , i have created the main menu table view the issue is with the sub menus do i have to create 15 table view for each sub menu !!??
is there is any way to create 1 table view for the sub menus and change its data according to user click
note : i don't want to use the sections in my table view
any ideas will be much appreciated
Need two viewControllers and a navigationController. One for main menu and other for sub menu. Let them be mainMenuViewController and subMenuViewController. Each controllers contains a tableView.
Create an menuArray containing 15 submenu data.Each submenu is an array.
In didSelectRowAtIndexPath of mainMenuViewController, if user selects a row in the tableView, then pass that data in the menuArray corresponding to the selected row.
For example, if user selects third row,
then pass menuArray[3] to subMenuViewController. Here indexPath.row = 3.
Sample Project Code:
MenuViewController.swift:
import UIKit
class MenuViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var menuTableView: UITableView!
var imagesArray: NSArray = []
var menuArray: NSArray = []
var subMenuDataArray: NSArray = []
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
menuTableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell")
imagesArray = ["soups.jpg","salads.jpg","starters.jpg","pizzas.jpg","burgers.jpeg"]
menuArray = ["Soups","Salads","Starters","Pizzas","Burgers"]
subMenuDataArray = [["Cream of broccoli","Cream of celery","Cream of tomato","Etrog","Gazpacho"],
["Tuna salad","Urnebes","Waldorf salad"],
["Kakori Kebabs","Stir Fried Chilli Chicken"," Microwave Paneer Tikkas","Aloo and Dal ki Tikki","Cheese Balls","Bhuna Masala Chicken Wings"],
["Cheese Pizzas","Chicken Pizzas","Masala Pizzas","Double Cheese Pizzas","Herbal Pizzas"],
["Luger Burger","Le Pigeon Burger","The Company Burger","Dyer’s Deep-Fried Burger","The Lola Burger","Cheeseburger","Raw Steak Tartare Burger","Buckhorn Burger"]]
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return imagesArray.count
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat{
return 70
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{
let menuTableViewCell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath)
let cellImageView: UIImageView = UIImageView.init()
cellImageView.frame = CGRectMake(10, 10, 50, 50)
cellImageView.image = UIImage(named: imagesArray.objectAtIndex(indexPath.row) as! String)
menuTableViewCell.contentView.addSubview(cellImageView)
let menuLabel: UILabel = UILabel.init(frame: CGRectMake(70, 10, 200, 25))
menuLabel.text = menuArray.objectAtIndex(indexPath.row) as? String
menuTableViewCell.contentView.addSubview(menuLabel)
return menuTableViewCell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath){
let subMenuViewController: SubMenuViewController = storyboard!.instantiateViewControllerWithIdentifier("SubMenuViewControllerID") as! SubMenuViewController
subMenuViewController.currentSubMenuArray = subMenuDataArray.objectAtIndex(indexPath.row) as! NSArray
navigationController?.pushViewController(subMenuViewController, animated: true)
}
}
SubMenuViewController.swift:
import UIKit
class SubMenuViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var subMenuTableView: UITableView!
var currentSubMenuArray: NSArray = []
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
subMenuTableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "subCell")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return currentSubMenuArray.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{
let subMenuTableViewCell = tableView.dequeueReusableCellWithIdentifier("subCell", forIndexPath: indexPath)
let subMenuLabel: UILabel = UILabel.init(frame: CGRectMake(10, 10, 250, 25))
subMenuLabel.text = currentSubMenuArray.objectAtIndex(indexPath.row) as? String
subMenuTableViewCell.contentView.addSubview(subMenuLabel)
return subMenuTableViewCell
}
}
Storyboard:
Output:
To test the sample project, use the following link of my GitHub account:
https://github.com/k-sathireddy/MenuTableViewSample
Declare one array for displaying and change the content of the array according to the selection and screen state like for menu, submenu etc. and reload the table to display the data in the main array. And if you want to display different kind of cell for different selection you can achieve it by taking an enum for whats the current screen state like i said and return required cell initialized in cellForRowAtIndexPath. Its all about how much you can think and implement the logic. Comment below if you need real technical solution with codes you already have used.
Related
I'm stuck with a very specific problem while using a Table View (XCode 9, Swift 4). What I want to do is, make an array named foodDetailInfoArray with text values of the foodName label in the table cells which have been selected manually by the user. Currently, while the .setSelected method works for changing the UI for a cell as I want, it isn't helping me record the foodName.text value properly. The problem is that the text values get recorded even while scrolling the table view and the array values get replaced as well. Below is the code and a sample of the printed output.
var foodDetailInfoArray: [String] = []
#IBOutlet var unselectedCell: UIView!
#IBOutlet var foodName: UILabel!
#IBOutlet var carbonValue: UILabel!
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
if selected == true {
self.unselectedCell.backgroundColor = UIColor.init(red: 4/255, green: 206/255, blue: 132/255, alpha: 1)
self.foodName.textColor = UIColor.white
self.carbonValue.textColor = UIColor.white
foodDetailInfoArray.append(foodName.text!)
} else {
self.unselectedCell.backgroundColor = UIColor.clear
self.foodName.textColor = UIColor.black
self.carbonValue.textColor = UIColor.black
}
print(foodDetailInfoArray)
}
The print statement gives me this sort of result:
(This is when the cells are not even selected and I'm just scrolling the table view.)
["pepper"]
["pasta"]
["pasta", "pepper"]
["pepper"]
["pepper", "pasta"]
["stir-fry"]
["stir-fry", "stir-fry"]
["vegetable"]
["vegetable", "vegetable"]
Whereas, what I ideally want would be (in the order of clicking the cell that contains given foodName):
["pasta"]
["pasta", "pepper"]
["pasta", "pepper", "tomato"]
["pasta", "pepper", "tomato", "stir-fry"]
and if a certain cell is deselected then the name has to be dropped, ie if tomato is deselected, then array would be
["pasta", "pepper", "stir-fry"]
... and so on
PS: I'm not a programmer by profession and altogether self taught recently, so please let me know if the question is unclear in any way.
I would handle the selection and deselection of the cell via the view controller, so you can also use your foodDetailInfoArray better. With the help of this answer you could do it like that way:
import UIKit
class ViewController: UITableViewController {
// example data
let names = [ "pepper", "pasta", "stir-fry", "vegetable"]
var foodDetailInfoArray: [String] = []
override func viewDidLoad() {
super.viewDidLoad()
// allow multiselection
tableView.allowsMultipleSelection = true
}
// MARK: UITableViewDataSource
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 4
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: .default, reuseIdentifier: "cell")
cell.textLabel?.text = names[indexPath.row]
// Don't show highlighted state
cell.selectionStyle = .none
return cell
}
// MARK: UITableViewDelegate
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// also do your UI changing for the cell here for selecting
// Add your food detail to the array
foodDetailInfoArray.append(names[indexPath.row])
}
override func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
// also do your UI changing for the cell here for deselecting
// Remove your food detail from the array if it exists
if let index = foodDetailInfoArray.index(of: names[indexPath.row]) {
foodDetailInfoArray.remove(at: index)
}
}
}
Result
I would try the delegate method didSelectRowAtIndexPath for tableViews. Have your view controller adopt the UITableViewDelegate protocol and implement the following.
Suppose you have a foods array, and a foodsSelected array that's initially empty.
let foods:[String] = ["Apples","Avocado","Bananas"]
var foodsSelected:[String] = []
Now whenever a cell is selected, this delegate method is called and add or remove the selected food from the foodsSelected array.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
//Check if the selected food is in the foodsSelect array
if(!foodsSelected.contains(foods[indexPath.row])){
//If it's not, append it to the array
foodsSelected.append(foods[indexPath.row])
}else{
//If it is, remove it from the array.
//Note there are many ways to remove an element from an array; I decided to use filter.
foodsSelected = foodsSelected.filter({$0 != foods[indexPath.row]})
}
print(foodsSelected)
}
Here is the output when I select these items in order: Apples, Avocado,Bananas,Avocado
["Apples"]
["Apples", "Avocado"]
["Apples", "Avocado", "Bananas"]
["Apples", "Bananas"]
My goal is to make a grouped tableView, but for somehow the data is not added to the table View
Here's the story board picture
I added a table View on top of view controller which is
and the code that I wrote seems like it don't work
import UIKit
import Alamofire
import SwiftyJSON
import KeychainAccess
class SettingsViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
let keychain = Keychain(server: "https://genietesting.herokuapp.com", protocolType: .HTTPS)
var profile: [String]?
let aboutGenie = [
"How it works",
"About",
"Contact"
]
override func viewDidLoad() {
super.viewDidLoad()
let firstName = keychain[string: "first_name"]
profile = [
firstName!
]
tableView.dataSource = self
tableView.delegate = self
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 2
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0 {
return profile!.count
} else {
return aboutGenie.count
}
}
func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
if section == 0 {
return "Profile"
} else {
return "About Genie"
}
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let tableCell = tableView.dequeueReusableCellWithIdentifier("myCell")
return tableCell!
}
}
and of course, I want to make it clickable so that it would go to its own viewController
After some suggestion, I changed most of my codes above and the result is still the same but this time it shows the header
The result is
airsoftFreak,
There are multiple mistakes I can figure out
There is no IBOutlet for your tableView which is added on top of your ViewController.
So you must be having something like
#IBOutlet var tableView: UITableView!
Your SettingsViewController only confirms to UITableViewDataSource and not to UITableViewDelegate. If you wamt to get didSelectRowAtIndexPath to be triggerred you have to confirm to UITableViewDelegate
class SettingsViewController: UIViewController,UITableViewDelegate,UITableViewDataSource {
As many have noticed and mentioned in their answer you will have to set your viewController as delegate for both UITableViewDelegate,UITableViewDataSource so
self.tableView.dataSource = self
self.tableView.delegate = self
The way you are instantiating cell is wrong as well :) Yopu should not create tableViewCell everytime for each cell :) Go to your TableView in storyBoard add a prototype cell, decorate it the way you want and the set the reusableIndentifier for it. Lets say reusableIndentifier you set is 'myCell'
your cellForRowAtIndexPath will change to
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
//assuming you have different cells for each section
switch indexPath.section {
case 0: let tableCell = tableView.dequeueReusableCellWithIdentifier("myCell")
tableCell.textLabel.text = profile[indexPath.row]
return tableCell
//in swift switch has to be exhaustive so default
default: let secondSectionCell = tableView.dequeueReusableCellWithIdentifier("second_section_cell_identifier")
secondSectionCell.textLabel.text =aboutGenie[indexPath.row]
return secondSectionCell
}
}
Try to drag (ctrl+drag) the tableview to the yellow button at the top of the viewcontroller. You will now see to options: datasource and delegate. Choose one of these to and perform the action again for the other. Now the tableview should be linked to your code.
If the option to make it clickable was a question as well:
With the function didSelectRowAtIndexpath, you can achieve this. There should be a lot of stacks about this issue available.
You probably have not wired the UITableView delegate and dataSource methods to the viewController. You can do this in two ways.
1. programatically
create a tableViewOutlet
override fun viewDidLoad() {
super.viewDidLoad()
yourTableViewOutlet.delegate = self
yourTableViewOutlet.dataSource = self
}
in interfaceBuilder
a) open the document outline in the storyboard.
b) control drag from your tableView to your ViewController.
c) connect delegate and dataSource one by one.
click on the cell will fire the delegate method didSelectRowAtIndexPath
self.tableView.delegate and self.tableView.datasource
override func viewDidLoad() {
super.viewDidLoad()
let firstName = keychain[string: "first_name"]
profile = [
firstName!
]
self.tableView.delegate = self
self.tableView.datasource = self
}
I'm using Xcode 7.0, Swift 2
I'm basically trying to create a custom class that will build a UITable, then in the ViewController I make a new object of the table and load it into self.view;
The problem I'm having is that the function func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell isn't being called at all from within the custom class. I've been looking for a solution for 3 days now and I've tried rebuilding the App and code several times with no luck.
Please note, if I use the same code (that is everything required to build the table; excluding init functions, etc) in the ViewController.swift file, it works fine.
I know the problem is with the cellForRowAtIndexPath function because it will not print out the statement I set in that block of code when it runs. All other functions are called, but for some reason this isn't being called. Not sure if I overlooked something here. Any help would be appreciated. Thanks in advance.
class sideTest: NSObject, UITableViewDelegate, UITableViewDataSource {
let tesTable: UITableView = UITableView()
var items: [String]?
var mView: UIView = UIView()
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print("The number of rows is: \(self.items!.count)")
return self.items!.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
print("\nLets create some cells.")
let sCell: UITableViewCell = tableView.dequeueReusableCellWithIdentifier("cell") as UITableViewCell!
sCell.textLabel?.text = self.items![indexPath.row]
sCell.textLabel?.textColor = UIColor.darkTextColor()
return sCell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
print("You selected cell #\(indexPath.row)!")
}
func tblSetup() {
self.tesTable.frame = CGRectMake(0, 0, 320, mView.bounds.height)
self.tesTable.delegate = self
self.tesTable.dataSource = self
self.tesTable.backgroundColor = UIColor.cyanColor()
// load cells
self.tesTable.registerClass(UITableViewCell.self, forCellReuseIdentifier: "Cell")
self.tesTable.reloadData()
print("Currenlty in tblSetup.\nCurrent rows is: \(self.items!.count)")
}
//Init
override init() {
super.init()
self.items = nil
self.tblSetup()
}
init(sourceView: UIView , itemListAsArrayString: [String]) {
super.init()
self.items = itemListAsArrayString
self.mView = sourceView
self.tblSetup()
}
}
Here is the code from ViewController.swift; Please do note that the table gets built, but the cells do not populate, even if I manually enter cell info by doing: sCell.textLabel?.text = "test cell"
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let myTable: sideTest = sideTest(sourceView: self.view, itemListAsArrayString: ["Cell 1", "Cell 2", "Cell 3"])
self.view.addSubview(myTable.tesTable)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Again, any help is greatly appreciated. Thanks.
Your view controller don't have a strong reference to your sideTest var.
Once your view did load finished,your sideTest is nil.Although you have a tableview(by add subview), but you no longer have a data source.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {}
is called after view did load. That cause the problem.
change your view controller to:
var tb :sideTest?
override func viewDidLoad() {
super.viewDidLoad()
let myTable: sideTest = sideTest(sourceView: self.view, itemListAsArrayString: ["Cell 1", "Cell 2", "Cell 3"])
print(myTable.tesTable.frame)
tb=myTable
self.view.addSubview(myTable.tesTable)
}
change your cellforrowatindexpath to:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
print("create cells")
var cell :UITableViewCell?
if let sCell: UITableViewCell = tableView.dequeueReusableCellWithIdentifier("cell"){
cell=sCell
}else{
cell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "cell")
}
cell!.textLabel?.text = self.items![indexPath.row]
cell!.textLabel?.textColor = UIColor.darkTextColor()
return cell!
}
this will fix most of the problems.
Your code:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let myTable: sideTest = sideTest(sourceView: self.view, itemListAsArrayString: ["Cell 1", "Cell 2", "Cell 3"])
self.view.addSubview(myTable.tesTable)
}
I would think that the myTable variable goes out of scope and is released when viewDidLoad finishes, so there is no data source or delegate after that. Did you verify that the self.view.addSubview(myTable.tesTable) retains it? Try moving declaration of myTable outside of the function level (to property level) or add a diagnostic print to deinit..
Pardon me but I'm new to code & Swift.
Can't post an image but I need to link my custom UITableViewController 7 dynamic prototype cells to 7 different UItableviewcontrollers. So far I tried to segue the cell to another UITableViewController, but the rest of the cells are linking to the same place as well. Lets say if i want to link a fast food category to a list of fast food restaurants in a UITableViewController, every other category is also linking to the same UITableViewController.
I'm not quite sure what to do.
My main controller code is as follows:
class CategoriesTableViewController: UITableViewController {
var category: [Categories] = categoriesData
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 numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return category.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath)
-> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("CategoriesCell", forIndexPath: indexPath)as CategoriesCell
let categories = category[indexPath.row] as Categories
cell.textLabel?.text = categories.category
if let categoryLabel = cell.viewWithTag(100) as? UILabel {
categoryLabel.text = categories.category
}
return cell
}
This is my categories.swift file:
class Categories: NSObject {
var category: String
init(category: String) {
self.category = category
super.init()
}
}
and categories data.swift:
let categoriesData = [Categories(category:"Restaurants/Cafe"), Categories(category:"Fine Dining"), Categories(category:"Catering"),Categories(category:"Buffet"), Categories(category:"Food Court/Hawker Centre"), Categories(category:"Fast Food"), Categories(category:"Others")]
my categories cell.swift shows the following:
class CategoriesCell: UITableViewCell {
#IBOutlet weak var nameLabel: UILabel!
}
Maybe can post pictures so we can see as to why you are going that route.
I think you want the sections of the tableview to display different content?
I would suggest:
split the table view into the number of sections you want (each section can have a given number of rows)
create one UITableViewController class
in your
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
}
Set your content based on section & row number
Try this:
Create 7 different prototype cells.
Change the reuse identifier of each prototype cell to match one of your categories.
Link each prototype cell to a different ViewController with a segue.
In cellForRowAtIndexPath, use the category for that row to fetch the correct prototype cell:
let categories = category[indexPath.row] as Categories
let cell = tableView.dequeueReusableCellWithIdentifier(categories.category, forIndexPath: indexPath) as CategoriesCell
My UITableView data source and delegate are not connected to any file. If this is the problem, would someone tell me how to connect them. If not, here is my code.
My File containing the struct info:
struct PreviousApps {
var name : String
var description : String
var filename : String
}
And this is my code in my TableViewController:
import UIKit
class PreviousProjectsVC: UIViewController, UITableViewDelegate, UITableViewDataSource{
var apps = [PreviousApps]()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
var PreviousApp = PreviousApps(name: "Gecko Catch", description: "DESCRIPTION", filename: "geckocatch.png")
apps.append(PreviousApp)
PreviousApp = PreviousApps(name: "Flappy Timothy", description: "DESCRIPTION", filename: "flappytimothy.png")
apps.append(PreviousApp)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! UITableViewCell
var currentApp = apps[indexPath.row]
cell.textLabel!.text = currentApp.name
return cell
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return apps.count
}
}
I am new to Swift and any help would be appreciated. If i'm not being specific enough, tell me and I will try to provide you with more info.
Thanks,
Beck
Assuming that you are using storyboard to set up your tableviewcontroller:
Set PreviousProjectsVC as the class for the table view controller using identity inspector (at right panel in Xcode)
Click on the "Show document outline" at the bottom-left corner in storyboard
Select the TableView from the outline and control + drag from there to the yellow icon at the top of the table view controller scene in storyboard
Select delegate and datasource from the menu displayed
To set the delegate and datasource from the code, create an outlet for the TableView and set tableView.delegate = self and tableView.dataSource = self