Writing Questions and answers to a table view cell - ios

I am attempting to setup and write a question and its corresponding answers to a table view with each cell representing one of the answers from a dictionary and a question.
The dictionary is setup as follows:
struct Quest {
question: String,
ans1: String,
ans2: String,
ans3: String,
ans4: String,
cor: String
}
The struct can hold anywhere from 1 questions [0] through [100]
I was attempting to call the reloadata() function but that loads up a different question in each cell, whereas I need to load the question first and then the four answers. Just not sure how to accomplish this.
Here is my cellFor code:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "ItemCell", for: indexPath)
let label1 = cell.viewWithTag(1) as? UILabel
let myView = cell.viewWithTag(3)
let myItem = items[indexPath.row]
print(indexPath.row)
label1?.text = "Question"
return cell
I tried having it return the cell and then added the code below that to load the next one but it keeps telling me that once I return the rest of the code won't execute, which I understand.
Any help would be appreciated.

It sounds like you need a sectioned table view, with each section containing the question in the section header in the cells in that section containing the answers.

Related

update UITableViewCell from content of another UITableViewCell in same table [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 2 years ago.
Improve this question
i have a UITableViewController configured with a static table made up of 5 custom cells (this is meant to be a form).
cell 0 captures a date
cell 1 is a UICollectionView filled with icons representing activities. depending on which activity is selected, one of many custom UITableViewCell are loaded on the fly in cell 2 .
cell 2 can be simple (just a slider), a textfield or more complex (a UITableView)
cell 3 has a textfield to capture a description.
cell 4 is for additional notes
so far everything is working as expected. I select an activity in cell 1, the matching XIB is loaded in cell 2, data is captured, comment added etc and form is saved. Where i am challenged is in the case where based on the the input in cell 2, i would like to update cell 3 automatically. i got it working but i feel it isn't elegant or clean so would appreciate others input. in
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// main table cells pseudo code
switch indexPath.row {
case 0:
<#code#>
case 1:
// dequeue collectionviewcell
case 2:
// dequeue the relevant uitableviewcell based on selected cell in the uicollectionview
switch selectedIndexPath.row {
case 2:
<#code#>
default:
<#code#>
}
case 3:
// handle the description field
default:
<#code#>
}
a specific activity will load "eventFlushMedTableViewCell" which is meant to display a list of meds in a uitableview. based on which meds I select, i would like to take the name of the meds and put them in cell 3.
case 2:
let cell = tableView.dequeueReusableCell(withIdentifier: "eventFlushMedTableViewCell", for: indexPath) as! eventFlushMedTableViewCell
// fill the meds table with the list of Rx meds
cell.medsArray = medListArray.filter { $0.medRx == 1}.map {return $0.medName}
// return the selected values from the table
cell.returnValue = { selectedIndexPaths in
let indexList = selectedIndexPaths.map { $0.row }
self.selectedMedsName = indexList.map {cell.medsArray[$0]}
// force a reload of cell 3
let myIndexPath = IndexPath.init(row: 3, section: 0)
tableView.reloadRows(at: [myIndexPath], with: .none)
}
return cell
and cell 3 in the main table is dequeued and configured
case 3:
let cell = tableView.dequeueReusableCell(withIdentifier: "eventDescriptionCell", for: indexPath) as! eventDescriptionCell
if !selectedMedsName.isEmpty {
cell.eventDescriptionTextField.text = selectedMedsName.joined(separator: ", ")
}
something tells me the closure around (cell.returnValue {...}) in case 2:, even though it is working, isn't the right way of doing this... any advice ?
thanks
I think a good way of approaching this would be to create a custom delegate.
Let's name it ActivityCellDelegate. You can create it like this:
protocol ActivityCellDelegate: class {
func activitySelected(_ activity: Activity)
}
We use 'class' so we can make the delegate 'weak' reference. Otherwise XCode will cause trouble :).
Using an enum to represent different activities is a nice touch. You could also use a String as an identifier or an Int as an id.
enum Activity {
case activity1
case activity2
...
}
Add a delegate property to the TableViewCell:
weak var cellDelegate: ActivityCellDelegate?
Then, when dequeuing a cell, you set it's delegate to self cell.cellDelegate = self, and make the controller that has tableView as a subview conform to the delegate protocol.
extension TableViewController: ActivityCellDelegate {
func activitySelected(_ activity: Activity) {
//...in here you would probably reload the third cell in the table view. You could add an additional property in the ViewController in order to know which activity is currently selected.
}
}
In the end, when user selects a CollectionViewCell to choose an activity in collectionView:didSelectItemAtIndexPath: you should call the delegate method:
delegate?.activitySelected(.activity1)

Can’t deselect previously selected cell when a new one is selected in a tableview where each cell contains tableview

I have a tableview, where each cell is a custom tableview cell. That custom tableview cell contains a tableview and a label.
Lets say, the outer tableview is called MainTableView. Each cell of MainTableView consists another tableview. The problem is , when I select
inner tableview cell one by one the previously selected cell is not get deselected.In first image I have selected cell contains text “Two”. Then In the second image I have selected cell contains text “Five” but perviously selected cell “Two” still in selection mode. I want to deselect the previous cell when select a new one.
I have tried
tableView.deselectRow(at: IndexPath, animated: Bool)
this method inside didSelectRowAt in custom tableviewcell class but it didn’t serve the purpose because the previous indexPath is from seperate tableview. So, how can I deselect the previous one?
to get the correct inner tableView,
Firstly , you should record the outside tableView's cell indexPath, which cell the inner tableView is in.
So your should record two indexPathes
var selectionRowInfo: (lastOutsideIP: IndexPath?, lastInnerIP: IndexPath?)
Secondly, you get the correct tableView, via the outsideTableView.
if the inner table is visible, you shall handle it immediately. through outTableView.indexPathsForVisibleRows
the else condition, you need not handle it. The tableView reuse mechanism will refresh its state.
// pseudo code.
if let lastOut = lastOutsideIP, let visibleRows = outTableView.indexPathsForVisibleRows, visibleRows.contains(lastOut){
let cell = tableView.cellForRow(at: lastOut) as! YourCell
// get the correct inner tableView via the cell
}
Because the inner tableViews are not related to each other. Select the cell of table one, will not affect the selection of cell of table two.
So your should build the connection manually.
Use a property to store the state var lastIndexPath: IndexPath?,
then every time select a indexPath,
// pseudo code.
if let last = lastIndexPath{
tableView.deselectRow(at: last, animated: true)
}
Please notice that, you should find the correct inner tableView, which has the lastIndexPath
The previous answer is along the right lines but has a flaw - it cannot distinguish between tableViews, which is the most important part. Also if the tableViews have different numbers of rows, it risks trying to access a row that doesn't exist and causing a crash.
To track the selected row in two tableViews (tv1 & tv2) you'll need to hold the selected row in each:
var tv1, tv2: UITableView!
var lastRowForTV1, lastRowForTV2: IndexPath?
and then respond to selections by identifying the tableView being used and adjusting the other (this assumes the two tableViews use the same datasource/delegate)
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if tableView === tv1 {
lastRowForTV1 = indexPath
if let last = lastRowForTV2 {
tv2.deselectRow(at: last, animated: true)
lastRowForTV2 = nil
}
} else if tableView === tv2 {
lastRowForTV2 = indexPath
if let last = lastRowForTV1 {
tv1.deselectRow(at: last, animated: true)
lastRowForTV1 = nil
}
}
}
I have solved the problem by using the idea of first answer given by dengApro . The idea was to find the correct inner table which contains the previously selected cell.
I have two files one is ViewController.swift that contains the outer tableview MainTableView. Another one is CustomTableViewCell.swift with CustomTableViewCell.xib that contains the custom cell with tableview.
fileprivate var lastSelectedInnerTableView : Int = -1
fileprivate var lastSelectedRow: Int = -1
fileprivate var tableViewList :[UITableView] = []
I have added these 3 variables in CustomTableViewCell.swift file outside the class CustomTableViewCell. lastSelectedSection , lastSelectedRow these 2 variable are used to keep
track of the last selected inner tableview (lastSelectedInnerTableView) and the last selected cell of that inner tableView (lastSelectedRow). tableViewList variable is used to keep the
Inner tableView. Inside awakeFromNib() I have append the created inner tableviews.
override func awakeFromNib() {
super.awakeFromNib()
self.tableView.delegate = self
self.tableView.dataSource = self
self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
tableViewList.append(self.tableView) // append the created inner tableviews
}
Then inside didSelectRowAt I have deselect the previous one:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if lastSelectedInnerTableView != -1 && lastSelectedRow != -1{
self.oldIndexPath.section = 0
self.oldIndexPath.row = lastSelectedRow
tableViewList[lastSelectedInnerTableView].deselectRow(at: self.oldIndexPath, animated: true)
}
lastSelectedInnerTableView = self.innerTableId
lastSelectedRow = indexPath.row
}
In ViewController.swift I have set innerTableId inside cellForRowAt
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let customCell: CustomTableViewCell = self.tableView.dequeueReusableCell(withIdentifier: "customCell") as! CustomTableViewCell
customCell.innerTableId = indexPath.row
customCell.customCellActionDelegate = self
return customCell
}

UITableview with 2 cells

I am trying to build an app with 2 cell on a tableview
the header that will have the Headlines and the second that will have the normal feeds.
My question is how to connect this two cells
The code for the raw feeds are working
Example:
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return self.posts.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! TableViewCell
// Configure the cell...
let post = self.posts[indexPath.row]
cell.title.text = post.title?.utf8Data?.attributedString?.string
if let imageUrl = post.imageUrl {
cell.imgView?.downloadImage(from: imageUrl)
}
let myFormatter = DateFormatter()
myFormatter.dateStyle = .none
myFormatter.timeStyle = .short
cell.pubDate.text = myFormatter.string(from: post.pubDate!) // What gives?
return cell
}
}
You can do this by filling a solid color, like white, for both the cells and set Table View separator to none.
tableView.separatorStyle = .none
And if you want to create a serious of such combined cells, then add a view to the bottom of the second cell, i.e. Feed Row, and fill that view with other color, like grey. This view will work as a separator for serious.
I suggest you let your tableview empty in storyboard. (delete all cells)
What I usually do, and what I feel is more flexible and cleaner in terms of code and files, is always use custom cells.
Create a subclass of UITableViewCell for each cell type you need (here, 2). One could be HeaderCell, and the other could be FeedCell.
If you use the "Create UITableViewCell class" I think you can find in Xcode (haven't used it in a long time), it should create the class for you, as well as a .xib file. If you don't have the corresponding .xib just create it and link it manually.
The .xib file is where you will put your labels, connect the outlets and maange everything you need. That's where you'll remake the cells you deleted ealier on. I think you can actually cut and paste in the xib and it might work.
Now you have a custom class, with its corresponding xib, which you can use as a cell.
Make sure your tableview is connected as delegate and datasource in storyboard (it should already be done in your setup).
In ViewDidLoad you will need to register all your cell classes to the tableview.
That is done using this method call on your tableview property (outlet)
I'm not sure how to write it in swift, but it's
MyTableView.Register(nib, key) in pseudo code.
Both the parameters come from your custom cell class (it's the .Nib and the class name, which you could hardcode). I usually do MyHeaderCell.Nib and MyHeaderCell.Key that are put in static, but that you can do however you want.
Now that your tableview is aware of the cells it will have to display, you just have to manage it in your cellForRow method.
Simply do it by index :
var cell;
if (indexPath.Row == 0)
{
cell = tableView.dequeueReusableCell(withIdentifier: "HeaderCell", for: indexPath) as! HeaderCell
}
else
{
cell = tableView.dequeueReusableCell(withIdentifier: "FeedCell", for: indexPath) as! FeedCell
}
let post = self.posts[indexPath.row]
cell.title.text = post.title
return cell
And there you go :)
I've never done swift so there are certainly syntax mistakes but the idea is how you should do it.

Two TableViews One Data Source?

I have setup a segue that will show a view controller with a small TableView. I want a different segue to show a bigger TableView but I want the bigger table to have the same exact info as the smaller table. Got the smaller tableView working perfect on its own, but once I give the bigger table a Data source, reset and try it out.....crashes.
// IndexPath or First Cell in TableView
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = UITableViewCell()
if self.TaskTableViews.hidden == false {
cell = tableView.dequeueReusableCellWithIdentifier( "FirstTask" , forIndexPath: indexPath) as UITableViewCell!
let list = frc.objectAtIndexPath(indexPath) as! List
cell.textLabel?.text = list.taskName
cell.textLabel?.textColor = UIColor.whiteColor()
TaskTableViews.backgroundColor = UIColor.lightGrayColor().colorWithAlphaComponent(0.55)
TaskTableViews.layer.cornerRadius = 8
TaskTableViews.separatorColor?.colorWithAlphaComponent(2.0) }
if self.TaskTable2.hidden == false {
cell = tableView.dequeueReusableCellWithIdentifier( "Second Task" , forIndexPath: indexPath) as UITableViewCell!
let list = frc.objectAtIndexPath(indexPath) as! List
cell.textLabel?.text = list.taskName
cell.textLabel?.textColor = UIColor.whiteColor()
TaskTable2.backgroundColor = UIColor.lightGrayColor().colorWithAlphaComponent(0.55)
TaskTable2.layer.cornerRadius = 8
TaskTable2.separatorColor?.colorWithAlphaComponent(2.0) }
return cell as UITableViewCell
}
The problem is that the code for your two tables is slamming into each other. To fix this, rejigger your logic. Do not make your logic depend on what is hidden. You can handle only one table at a time; just one table is calling here. That table comes in as the tableView parameter. Make your logic depend on that. Depending what table view that tableView parameter is, configure the cell and return it for that table view.
I think that you should consider changing your approach by just resizing the table view dynamically when you go from one scene to the other instead of having two table views if the information is exactly the same.
If you're still pushing for this approach then don't make the condition be that the table view is hidden and instead implement your own logic or boolean to determine this. But again, I'd rather resize a single table view as needed.
You have many problems in your code
1.
var cell = UITableViewCell()
What's the point of this line?
2.
cell = tableView.dequeueReusableCellWithIdentifier( "FirstTask" , forIndexPath: indexPath) as UITableViewCell!
What's the point of casting? This function returns UITableViewCell (not even optional)
3.
cell.textLabel?.text = list.taskName
Should not compile, cause UITableViewCell doesn't have textLabel
4.
TaskTableViews.backgroundColor = UIColor.lightGrayColor().colorWithAlphaComponent(0.55)
What's the point of doing this every cell request? Move this to viewDidLoad or other appropriate place
Your if { } parts are identical except of reuse identifier
Use tableView argument when needed
Use if { } else
8.
return cell as UITableViewCell
Why cast? Just return
I'm sure I haven't found all of them))

How to add three tableview cells in a tableview as Subview?

I want to add 2 cells one as header the segue form the previous tableview and the the second cell for details like this prototype .
First Cell class "courseCell"
Second Cell Class "DetailsTVC"
I found many way but it doesn't work I hope someone help
I couldn't follow with this instruction
Initialize your custom tableviewcell - CustomCell1 and CustomCell2
Since tableviewcell is a subclass of UIView you can add it as a subview.
[TableCell addSubview:CustomCell1];
[TableCell addSubview:CustomCell2];
cell?.addSubview(<#view: UIView>)
[cell ?.addSubview(<#view: UIView>)]
override func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!, object: PFObject!) -> PFTableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("cell" , forIndexPath : indexPath) as? courseCell
if cell == nil
{
cell = courseCell(style: UITableViewCellStyle.Default, reuseIdentifier: "cell")
}
cell?.name.text = object["title"] as! String!
cell?.location.text = object["Location"] as! String!
return cell!
}
To accomplish it:
TableViewController
- Tableview
- TableViewHeader (create a UIView subclass for this view)
- TableViewContent (datasource)
- TableViewCell1 (virgin american fligth ...)
- TableViewCell1 (departs los angeles)
- TableViewCell1 (arrives new york)
Note that you dont need XIB file to your tableviewController
I am not sure why your question title mentions 3 and your question only mentions 2 but from what I can understand based on the image, it appears you want the header to be the title of the course and the rest of the cells to be the details of the course.
To create a header for your TableView you can create a custom "HeaderCell" as you would create a custom cell and then use it in the method which specifies the Header:
override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView?{
//set the title, image or whatever you want for your custom header cell
}
Now you can use another custom TableView cell as you normally do to show the details.
Tutorial:
http://www.ioscreator.com/tutorials/customizing-header-footer-table-view-ios8-swift

Resources