Sorry if this kind of question isn't welcome here but I'd appreciate the help. I have a fully functioning table now set up but I did it using the TableViewController in storyboard. I now realize I cannot change the size of the view using that item and it doesn't fit well on the screen as is. I understand I need to use a regular view controller and add the table view manually. I can do that but I spent hours getting the table to work properly and I'm afraid to break it. Can someone walk me through transitioning between the two?
Here is the storyboard
Here is the view controller code
import UIKit
class CharacterTableViewController: UITableViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet var characterTableView: UITableView!
var characterArray: [Character] = [Character]()
override func viewDidLoad() {
super.viewDidLoad()
self.characterSetup()
}
func characterSetup() {
var admiralSwiggins = Character(name: "Admiral Swiggins", abilities: "Stun, Blind, Shield, Damage Over Time, Area of Effect", characterImage: "admiral.png")
var ayla = Character(name: "Ayla", abilities: "Area of Effect, Damage Over Time, Fly, Lifesteal, Shield, Slow", characterImage: "ayla.png")
var clunk = Character(name: "Clunk", abilities: "Lifesteal, Area of effect, Ensnare, Slow, Launch String", characterImage: "clunk.png")
characterArray.append(admiralSwiggins)
characterArray.append(ayla)
characterArray.append(clunk)
}
override func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {
var cell:CharacterTableViewCell = self.tableView.dequeueReusableCellWithIdentifier("Cell") as CharacterTableViewCell
if indexPath.row % 2 == 0 {
cell.backgroundColor = UIColor.redColor()
}
let character = characterArray[indexPath.row]
cell.nameLabel.text = character.name
cell.abilityLabel.text = character.abilities
cell.characterImage.image = UIImage(named: character.characterImage)
return cell
}
override func tableView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!) {
}
}
And here is the cell
import UIKit
class CharacterTableViewCell: UITableViewCell {
#IBOutlet var nameLabel: UILabel!
#IBOutlet var abilityLabel: UILabel!
#IBOutlet var characterImage: UIImageView!
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
}
}
Related
I'm trying to get the selected row in a table in Swift 4. The code presented for completeness, is as follows:
import UIKit
import WebKit
class FactorDetailsViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var goalTitle: UILabel!
#IBOutlet weak var goalCopy: UITextView!
#IBOutlet weak var goalBenefit: UILabel!
#IBOutlet weak var goalName: UILabel!
#IBOutlet weak var graph: SimpleChart!
#IBOutlet weak var measurement: UILabel!
#IBOutlet weak var measurementRange: UILabel!
#IBOutlet weak var updated: UILabel!
#IBOutlet weak var factorCopy: UITextView!
#IBOutlet weak var impact: UILabel!
#IBOutlet weak var actionsTable: UITableView!
#IBOutlet weak var researchTable: UITableView!
#IBOutlet weak var scrollView: UIScrollView!
#IBOutlet weak var stackView: UIStackView!
var factorData : Factor?
var currentCategory : FactorCategory?
var recommendedActions : [Action] = []
var relatedResearch : [Research] = []
var goal : Goal?
var reading:Double?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.title = factorData?.factorName
measurement.text = String(reading!)
self.actionsTable.delegate = self
self.actionsTable.dataSource = self
self.actionsTable.isEditing = false
self.researchTable.delegate = self
self.researchTable.dataSource = self
self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Update", style: .done, target: self, action: #selector(addStuff))
goalCopy.text = goal?.copy
goalBenefit.text = "BIG BENEFIT"
goalTitle.text = goal?.title
for cat in (factorData?.categories)! {
let s = SimpleChartData(min : Double(cat.min), max : Double(cat.max), label : cat.label, label2 : String(cat.max))
if( graph.canLoad ) {
graph.data!.append(s)
}
}
graph.reading = reading!
// Pin the edges of the stack view to the edges of the scroll view that contains it
stackView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor).isActive = true
stackView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor).isActive = true
stackView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor).isActive = true
stackView.widthAnchor.constraint(equalTo: scrollView.widthAnchor).isActive = true
}
#objc func addStuff() {
// how does this work? Just takes you to the quiz again
let storyboard = UIStoryboard(name: "12Factor", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "AllQuestionViewController") as UIViewController
present(vc, animated: true, completion: nil)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func configure( factor : Factor )
{
factorData = factor
let mirrored_object = Mirror(reflecting: HRResponses.shared)
reading = 1.0
for (_, attr) in mirrored_object.children.enumerated() {
if let property_name = attr.label as String? {
if factorData?.responseField == property_name {
if let a = attr.value as? String, let aDouble = Double(a) {
reading = aDouble
}
}
}
}
currentCategory = factor.categories.first( where: {$0.min < reading! && $0.max > reading! })
for aind in (currentCategory?.actions)! {
let act = SignalModel.model.actions.first( where: {$0.id == aind})
recommendedActions.append(act!)
}
for rind in (currentCategory?.research)! {
let act = SignalModel.model.research.first( where: {$0.id == rind})
relatedResearch.append(act!)
}
goal = SignalModel.model.goals.first( where: {$0.id == currentCategory?.goals[0]})
}
func tableView(_ tableView: UITableView,
willSelectRowAt indexPath: IndexPath) -> IndexPath? {
print("works?")
return nil
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
if tableView == self.actionsTable {
let vc : ActionViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ActionViewController") as! ActionViewController
navigationController?.pushViewController(vc, animated: true)
}
if tableView == self.researchTable {
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// Return the number of items in the sample data structure.
var count:Int?
if tableView == self.actionsTable {
count = currentCategory?.actions.count
}
if tableView == self.researchTable {
count = currentCategory?.research.count
}
return count!
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell:UITableViewCell?
if tableView == self.actionsTable {
cell = tableView.dequeueReusableCell(withIdentifier: "ActionCell", for: indexPath as IndexPath)
let action = recommendedActions[indexPath.row]
(cell as! ActionCell).configure(a:action)
}
if tableView == self.researchTable {
cell = tableView.dequeueReusableCell(withIdentifier: "ResearchCell", for: indexPath as IndexPath)
let research = relatedResearch[indexPath.row]
(cell as! ResearchCell).configure(r:research)
}
return cell!
}
}
Now, that's too much code. The relevant parts are here:
self.actionsTable.delegate = self // yes, this is the delegate
self.actionsTable.dataSource = self
self.actionsTable.isEditing = false // no, we're not editing
As I understand it, this should be enough to have selections in the actionsTable trigger the
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
method. However, nothing happens. The other UITableViewDelegate methods are called, so this controller is the delegate for this table, however this one method is not ever triggered. Reading through the Apple documentation here I see that the method isn’t called when the table view is in editing mode (that is, the isEditing property of the table view is set to true), but my table isn't in editing mode. Is there something else that could be going wrong with my table that wouldn't allow it to send an event to a UITableViewDelegate? I suspect that this has something to do with the table being inside a UIScrollView, which I've read isn't best practice, but with the design I've been given, is non-negotiable sadly.
Your problem is not the delegate, all of that code is good. Your problem is that the parent scroll view is consuming the taps, not the table view. Remember, UITableView is a direct subclass of UIScrollView so placing a table view inside a scroll view is no different than placing a scroll view within a scroll view. UITableView has all of the default scroll view delegates built into it so just use those.
You should not embed UIWebView or UITableView objects in UIScrollView
objects. If you do so, unexpected behavior can result because touch
events for the two objects can be mixed up and wrongly handled.
Apple dox
I know it's not the answer you wanted because this wasn't your doing but I personally would not proceed with a hack. I would restructure the code and trim the controller down to one scroll view.
My storyboard looks like this
and my code is the following
UIViewController
class DownLoadSoundsViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
// MARK: View Controller Properties
let viewName = "DownLoadSoundsViewController"
#IBOutlet weak var visualEffectView: UIVisualEffectView!
#IBOutlet weak var dismissButton: UIButton!
#IBOutlet weak var downloadTableView: UITableView!
// MARK: Properties
var soundPacks = [SoundPack?]() // structure for downloadable sounds
override func viewDidLoad() {
super.viewDidLoad()
downloadTableView.dataSource = self
downloadTableView.delegate = self
downloadTableView.register(DownLoadTableViewCell.self, forCellReuseIdentifier: "cell")
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return numberOfSoundPacks
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let method = "tableView.cellForRowAt"
//if (indexPath as NSIndexPath).section == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "downloadTableViewCell", for: indexPath) as! DownLoadTableViewCell
cell.backgroundColor = UIColor.green
if soundPacks[(indexPath as NSIndexPath).row]?.price == 0 {
cell.soundPackPriceUILabel.text = "FREE"
} else {
cell.soundPackPriceUILabel.text = String(format: "%.2", (soundPacks[(indexPath as NSIndexPath).row]?.price)!)
}
//cell.textLabel?.text = soundPacks[(indexPath as NSIndexPath).row]?.soundPackTitle
cell.soundPackTitleUILabel.text = soundPacks[(indexPath as NSIndexPath).row]?.soundPackTitle
cell.soundPackAuthorUILabel.text = soundPacks[(indexPath as NSIndexPath).row]?.author
cell.soundPackShortDescription.text = soundPacks[(indexPath as NSIndexPath).row]?.shortDescription
cell.soundPackImage.image = UIImage(named: "Placeholder Icon")
DDLogDebug("\(viewName).\(method): table section \((indexPath as NSIndexPath).section) row \((indexPath as NSIndexPath).row))")
return cell
//}
}
UItableViewCell
class DownLoadTableViewCell: UITableViewCell {
#IBOutlet weak var soundPackImage: UIImageView!
#IBOutlet weak var soundPackTitleUILabel: UILabel!
#IBOutlet weak var soundPackAuthorUILabel: UILabel!
#IBOutlet weak var soundPackShortDescription: UILabel!
#IBOutlet weak var soundPackPriceUILabel: UILabel!
let gradientLayer = CAGradientLayer()
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
}
}
But I get the following;
I am sure I am doing something small incorrectly, but as of yet can't figure it out. Looked through many examples included my own code where I have gotten this working before.
Not a single one of my settings for the tableview are getting invoked except the number of cells. But everything in;
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{...}
is not working.
Help is appreciated.
I think you need to reload the tableView after getting data from Firebase
self.saveMixesTableView.reloadData()
I am trying to pass data from the selected cell of an "Events" table view, to a "Details" View Controller. I have looked at various questions similar to mine, but I can't seem to properly apply it to my code. I also used labels, instead of a Subtitle style. There is also an image that needs to be passed.
my view controller looks like this:
import UIKit
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var names = ["Brown Diner", "Kirkland", "Choco", "Lil Wayne", "Annie", "Social"]
var details = ["Free drink with meal after 12 AM", "LADIES drink free", "10% off all ice cream!", "concert", "a Theater Production", "Bring your Squad to the Social"]
var images = [UIImage(named: "brown"), UIImage(named: "kirk"), UIImage(named: "choco"), UIImage(named: "lilwayne"), UIImage(named: "default"), UIImage(named: "default")]
override func viewDidLoad() {
super.viewDidLoad()
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! CustomCell
cell.name.text = names[indexPath.row]
cell.detail.text = details[indexPath.row]
cell.photo.image = images[indexPath.row]
return cell
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "detailsSegue" {
guard let eventVC = segue.destinationViewController as? DetailsViewController,
let eventIndex = tableView.indexPathForSelectedRow?.row else {
return
}
eventVC.eventName = names[eventIndex]
eventVC.eventDetail = details[eventIndex]
eventVC.eventPhoto = images[eventIndex]
}
}
}
my customCell.swift file:
import UIKit
class CustomCell: UITableViewCell {
#IBOutlet var photo: UIImageView!
#IBOutlet var name: UILabel!
#IBOutlet var detail: 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
}
}
my detailsViewController
import Foundation
import UIKit
class DetailsViewController : UIViewController {
#IBOutlet var detailsLabel: UILabel!
#IBOutlet var detailsImage: UIImageView!
#IBOutlet var detailsDesc: UILabel!
override func viewDidLoad() {
}
}
I am very new to Swift, and it has proven to be very challenging for me. I'm really not a coder, however a project demands that I complete some of the coding for an application that I am the UI/UIX designer of. Thank you for your help in advance!
EDIT::
Project: https://github.com/vpags1/events.git.
When the user clicks on a cell in the TableView, it takes you to the Details View which displays the same data as the cell (image, name, details) just larger; and longer descriptions can be see at full length. I am pulling several errors in my View Controller, and thats pretty much all I know.. My cells formatting is also kind of messed up but I was going to try and figure that out after this unless there is a quick fix for that. cheers.
It doesn't look like your prepareForSegue function is being called when you tap on the cell. If not, you can add a didSelectRow function. Try this:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.performSegueWithIdentifier("detailsSegue", sender: self)
}
Then when you select your cell it will call your prepareForSegue function.
On my storyboard is a Tab Bar Controller with two view controllers. The first view controller has a UITableView, and the second view controller is used to collect data which will be displayed in table view format on the first view controller.
For this, I have created four swift files:
TARISKTREATMENT.swift - contains the class TARISKTREATMENT that's linked to the first view controller (the one with the UITableView)
TAADDRISKTREATMENT.swift - contains the class TAADDRISKTREATMENT that's linked to the second view controller.
TREATMENTS.swift - Struct that's used to collect data entered on second view controller.
CUSTOMTREATMENTCELL.swift - UITableViewCell class for the custom cell.
The second view controller collects the data from the user perfectly, and when I run print commands, I can see that the data is actually in the struct.
For some reason, the code from TARISKTREATMENT.swift does not populate the custom cell.
What am I doing wrong here?
CODE: TARISKTREATMENT.swift (View controller 1 with UITableView - the one that's not working...)
import UIKit
class TARISKTREATMENT: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var TreatmentsTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
TreatmentsTableView.dataSource = self
TreatmentsTableView.delegate = self
TreatmentsTableView.reloadData()
}//END - viewDidLoad
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return TreatmentsManager.newTreatments.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let IndividualCell = TreatmentsTableView.dequeueReusableCellWithIdentifier("TreatmentCell", forIndexPath: indexPath) as! CUSTOMTREATMENTCELL
IndividualCell.outletLabel_TreatmentPackageName.text = TreatmentsManager.newTreatments[indexPath.row].varTreatmentPackageName
IndividualCell.outletLabel_TreatmentDescription.text = TreatmentsManager.newTreatments[indexPath.row].varTreatmentPackageDetail
IndividualCell.outletLabel_TreatmentResponsiblePerson.text = TreatmentsManager.newTreatments[indexPath.row].varTreatmentResponsiblePerson
IndividualCell.outletLabel_TreatmentDTGCompleted.text = String(TreatmentsManager.newTreatments[indexPath.row].varTreatmentDTGCompleted)
let varSelectPriorityPic = TreatmentsManager.newTreatments[indexPath.row].varTreatmentPriority
switch varSelectPriorityPic {
case "HIGH":
IndividualCell.outletImage_TreatmentPriority.image = imageTreatmentPriorityHigh
case "MEDIUM":
IndividualCell.outletImage_TreatmentPriority.image = imageTreatmentPriorityMedium
case "LOW":
IndividualCell.outletImage_TreatmentPriority.image = imageTreatmentPriorityLow
default:
break
}
return IndividualCell
}
func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath){
if (editingStyle == UITableViewCellEditingStyle.Delete){
TreatmentsManager.newTreatments.removeAtIndex(indexPath.row)
TreatmentsTableView.reloadData()
}
}
}
CODE: TREATMENTS.swift
import UIKit
var TreatmentsManager: classTreatmentsManager = classTreatmentsManager()
struct structTreatment {
var varTreatmentPackageName : String
var varTreatmentPackageDetail : String
var varTreatmentResponsiblePerson : String
var varTreatmentPriority : String
var varTreatmentDTGCompleted : NSDate
}
class classTreatmentsManager: NSObject {
var newTreatments = [structTreatment]()
func funcAddTreatment(varTreatmentPackageName: String, varTreatmentPackageDetail: String, varTreatmentResponsiblePerson: String, varTreatmentPriority: String, varTreatmentDTGCompleted: NSDate){
newTreatments.append(structTreatment(varTreatmentPackageName: varTreatmentPackageName, varTreatmentPackageDetail: varTreatmentPackageDetail, varTreatmentResponsiblePerson: varTreatmentResponsiblePerson, varTreatmentPriority: varTreatmentPriority, varTreatmentDTGCompleted: varTreatmentDTGCompleted))
}
}
CODE: CUSTOMTREATMENTCELL.swift
import UIKit
class CUSTOMTREATMENTCELL: UITableViewCell {
#IBOutlet weak var outletImage_TreatmentPriority: UIImageView!
#IBOutlet weak var outletLabel_TreatmentPackageName: UILabel!
#IBOutlet weak var outletLabel_TreatmentDescription: UILabel!
#IBOutlet weak var outletLabel_TreatmentResponsiblePerson: UILabel!
#IBOutlet weak var outletLabel_TreatmentDTGCompleted: 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
}
}
I've uploaded a small video to show what's (not) happening here.
Your assistance is appreciated - thanks!
Everything is fine in your code. What you miss is reloading the data :
override func viewWillAppear() {
super.viewWillAppear()
TreatmentsTableView.reloadData()
}
I'm trying to create an app that displays some data on labels on the top of a screen, and then the lower half or so is a table which will allow selection of an item in the table to pop up another segue for editing a value. I'm struggling though to get the didSelectRowAtIndexPath to be called when an item on the list is selected by the user. I've put the code for the View controller below.
I've searched quite a bit and haven't found anything so far that explains the issue I'm seeing.
I think I've connected everything up correctly as far as delegates and datasource, and I'm not using any gesture captures so it's not those. Does anyone have any ideas?
I've attached screen grabs of the view controller connections and attributes inspector settings as well.
Connections screengrab
Attributes screengrab
import UIKit
class TemperatureViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var CurrentTemp: UILabel!
#IBOutlet weak var HeaterStatus: UILabel!
#IBOutlet weak var ChillerStatus: UILabel!
#IBOutlet weak var TempTableView: UITableView!
var settings = [TemperatureSettings] ()
var HeaterTemp:Float = 0.0
var ChillerTemp:Float = 0.0
var ThresholdTemp:Float = 0.0
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.loadTempSettings()
TempTableView.delegate = self
TempTableView.dataSource = self
TempTableView.allowsSelection = true
TempTableView.editing = false
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
self.loadTempSettings()
}
func loadTempSettings() {
let TempSetting1 = TemperatureSettings(name: "Heater On at", CurrentSetting: HeaterTemp)!
let TempSetting2 = TemperatureSettings(name: "Chiller On at", CurrentSetting: ChillerTemp)!
let TempSetting3 = TemperatureSettings(name: "Threshold", CurrentSetting: ThresholdTemp)!
settings = [TempSetting1, TempSetting2, TempSetting3]
TempTableView.reloadData()
//refreshControl?.endRefreshing()
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return settings.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// Stop spoof separators after the table entries for blank entries
tableView.tableFooterView = UIView(frame: CGRect.zeroRect)
// Turn off the separator for each cell.
tableView.separatorStyle = UITableViewCellSeparatorStyle.None
let cellIdentifier = "TemperatureSettingsTableViewCell"
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! TemperatureSettingsTableViewCell
let setting = settings[indexPath.row]
cell.SettingNameLabel.text = setting.name
cell.SettingCurrentLabel.text = String(format: "%.1f C", setting.CurrentSetting)
cell.SettingCurrentLabel.textAlignment = .Left
// Configure the cell...
//useTimer = true
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
print("Setting Row \(indexPath.row) clicked")
performSegueWithIdentifier("Settings", sender: self)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
This works for me:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
print("works");
}
Add override before func maybe?