Moving cells to new sections in a tableview - ios

How would I move cells from my first section in my tableview to the second section after the users selects the button?
This establishes my tableview.
#IBOutlet weak var goalTableView: UITableView!
let sections: [String] = ["Today:", "History:"]
var goals: [[String]] = [["Goal 1", "Goal 2", "Goal 3"], [""]]
override func viewDidLoad() {
super.viewDidLoad()
In my viewdidload I would add a connection from my button to my view controller, but would I have to develop a function here to move the selected cell to the new section?
let headerView = UIView()
goalTableView.tableHeaderView = headerView
headerView.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: 5)
}
}
extension ViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return goals[section].count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TodayGoalViewCell_1", for: indexPath) as? GoalTableViewCell
cell?.goalLabel.text = goals[indexPath.section][indexPath.row]
cell?.cellDelegate = self
cell?.index = indexPath
return cell!
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return sections[section]
}
func numberOfSections(in tableView: UITableView) -> Int {
return goals.count
}
}
extension ViewController: GoalTableView {
func selectGoalButton(index: Int) {
}
}

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// Only move cell from the 1st section
if indexPath.section == 0 {
// Append the selected element to the second array
goals[1].append(goals[0][indexPath.row])
// Remove the selected element from the first array
goals[0].remove(at: indexPath.row)
tableView.reloadData()
}
}

Related

How to add header to each row in a table view

I'm building an iOS app with a collection view inside the table view. I'm having three rows each row having a collection view inside it. I am planning to have three sections each section for each row. For example row, one should be in a separate section with a header and similarly for rows 2 and 3.
Whenever I create three sections I'm getting all the three rows in all three sections. I want to have a separate section with a header for each row.
import UIKit
class StoreVC: UIViewController,UITableViewDelegate,UITableViewDataSource {
#IBOutlet weak var CourseTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
CourseTableView.tableFooterView = UIView()
CourseTableView.delegate = self
CourseTableView.dataSource = self
}
func numberOfSections(in tableView: UITableView) -> Int {
return 3
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
if section == 0
{
return "Courses"
}
else if section == 1
{
return "Tests"
}
return "Bundles"
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0
{
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CourseRow
return cell
}
else if indexPath.row == 1
{
let cell = tableView.dequeueReusableCell(withIdentifier: "testcell", for: indexPath) as! TestRow
return cell
}
else if indexPath.row == 2
{
let cell = tableView.dequeueReusableCell(withIdentifier: "bundlecell", for: indexPath) as! BundleRow
return cell
}
return UITableViewCell()
}
}
Try this code on your Xcode-playground and customize as you need.
import UIKit
import PlaygroundSupport
class ViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func numberOfSections(in tableView: UITableView) -> Int {
3
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
1
}
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = UILabel()
headerView.text = "Header: \(section)"
return headerView
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
cell.textLabel?.text = "Cell: \(indexPath)"
return cell
}
}
PlaygroundPage.current.liveView = ViewController()

Issues displaying a table view cell from one view controller to another

Right now I am trying to move information from my goal cell into a new table view cell, and am having difficulty getting the cell to display.
Here is the code for my goal cell.
import UIKit
class GoalsViewController: UIViewController {
#IBOutlet weak var tableView: UITableView!
var Goals: [String] = ["goal 1", "goal 2", "goal 3"]
let theEmptyModel: [String] = ["No data in this section."]
var valueToPass = ""
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
}
func showGoalSelected() {
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now()) {
let popUp = GoalSelectedPopUp()
self.view.addSubview(popUp)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "GoalConversationsCell_1") {
let viewController = segue.destination as! ActiveGoalsViewController
viewController.Goals.append([valueToPass])
}
}
}
extension GoalsViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return Goals.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "GoalCell_1", for: indexPath)
cell.textLabel?.text = Goals[indexPath.row]
cell.textLabel?.lineBreakMode = NSLineBreakMode.byWordWrapping
cell.textLabel?.numberOfLines = 3
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.section == 0 {
valueToPass = Goals[indexPath.row]
performSegue(withIdentifier: "activeGoalsSegue", sender: self)
Goals.remove(at: indexPath.row)
if Goals.count != 0 {
showGoalSelected()
} else {
Goals.append(contentsOf: theEmptyModel)
}
tableView.reloadData()
}
}
Here is the goal cells storyboard with the push segue connecting it to the other table view.
That other table view is shown below.
Here is the code for this new tableview.
import UIKit
class ActiveGoalsViewController: UIViewController {
#IBOutlet weak var goalTableView: UITableView!
let sections: [String] = ["Mark as Complete:", "History:"]
var goals: [[String]] = [[], []]
let theEmptyModel: [String] = ["No data in this section."]
extension ActiveGoalsViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return Goals[section].count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TodayGoalViewCell_1", for: indexPath) as? GoalTableViewCell
cell?.goalLabel.text = Goals[indexPath.section][indexPath.row]
cell?.cellDelegate = self
cell?.index = indexPath
return cell!
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return sections[section]
}
func numberOfSections(in tableView: UITableView) -> Int {
return Goals.count
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.section == 0 {
if Goals[0] != theEmptyModel {
Goals[1].append(Goals[0][indexPath.row])
if Goals[1].first!.contains("No data in this section.") {
Goals[1].removeFirst()
}
Goals[0].remove(at: indexPath.row)
if Goals[0].count == 0 {
Goals[0].append(contentsOf: theEmptyModel)
}
tableView.reloadData()
}
}
}
Once the goal is selected, it sends me to the new storyboard, but this new view does not display the goal that was just added. Can someone help me figure out why this isn't working? Thanks.
I think in the second view controller you need to access the "goals" variable with a lower case g rather then the "Goals" variable with an upper case G.

How to separate cells into sections with custom header?

What I'm trying to do is separate my cells into sections by their Brand
what Ive been able to do so far is pass data of selected items from HomeVC to populate the cells of the CartVC
I am trying to separate the sections by brand, the brand data is a part of the model Items Class (name, brand, imageUrl, price, & weight) and the Items class retrieves data from CloudFirestore to populate the cells of the HomeVC
How would I be able to to separate the cells into sections by their brand, when passed into the CartVC.
So far what I've done seems to fail, because once I pass an item from the HomeVC to the CartVC I only get one header cell, with the brand name of the first item I passed into the CartVC. When I pass more data into the the CartVC all the cells stay in the section of the first item passed when im trying to section off all my CartCells by their brand
extension HomeViewController: UITableViewDelegate, UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return itemSetup.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "HomeCell") as? HomeCell else { return UITableViewCell() }
let item = itemSetup[indexPath.row]
cell.configure(withItems: item)
cell.addActionHandler = { (option: Int) in
print("Option selected = \(option)")
self.tray.append(Tray(cart: item))
item.selectedOption = option
}
return cell
}
}
class CartViewController: UIViewController {
var items: ProductList!
var sectionModel: [SectionModel] = []
var tray: [Tray] = []
var groupedItems: [String: [Tray]] = [:]
var brandNames: [String] = []
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
groupedItems = Dictionary(grouping: tray, by: {$0.cart.brand})
brandNames = groupedItems.map{$0.key}.sorted()
}
}
extension CartViewController: UITableViewDataSource, UITableViewDelegate {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CartCell", for: indexPath) as! CartCell
let cart = tray[indexPath.row]
cell.configure(withItems: cart.cart)
return cell
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let cartHeader = tableView.dequeueReusableCell(withIdentifier: "CartHeader") as! CartHeader
cartHeader.storeName.text = "Brand: \(tray[section].cart.brand)"
return cartHeader
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 45
}
}
class Tray {
var cart: ProductList!
init(cart: ProductList) {
self.cart = cart
}
}
just set your your tableview functions like and you'll have no problem setting things up by section
func numberOfSections(in tableView: UITableView) -> Int {
return brandNames.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let brand = brandNames[section]
return groupedItems[brand]!.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cartCell = tableView.dequeueReusableCell(withIdentifier: "CartCell") as! CartCell
let brand = brandNames[indexPath.section]
let itemsToDisplay = groupedItems[brand]![indexPath.row]
cartCell.configure(withItems: itemsToDisplay.cart)
return cartCell
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let cartHeader = tableView.dequeueReusableCell(withIdentifier: "CartHeader") as! CartHeader
let headerTitle = brandNames[section]
cartHeader.brandName.text = "Brand: \(headerTitle)"
return cartHeader
}

how to set cell row height in table view if it exceed its indexpath.row?

I am trying to make a FAQ view controller using table view, I need little bit fix in the UI. here is the display of my FAQ VC right now
(please ignore the red line)
as we can see, basically there are 2 row height, 80 & 160. if the row is tapped (selected) the row height will expand from 80 (yellow line) to 160 (purple line).
I want to make the row height under the last question is still 80 not 160. I have tried but I can't set the row below the last question. here is my code I use
class FAQVC: UIViewController {
#IBOutlet weak var retryButton: DesignableButton!
#IBOutlet weak var tableView: UITableView!
var FAQs = [FAQ]()
var selectedIndexs: [IndexPath: Bool] = [:]
override func viewDidLoad() {
super.viewDidLoad()
getFAQData()
}
}
extension FAQVC : UITableViewDelegate, UITableViewDataSource {
// MARK: - Table View Delegate and Datasource
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return FAQs.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "FAQCell") as! FAQCell
cell.FAQData = FAQs[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if self.cellIsSelected(indexPath: indexPath) {
return 160
} else {
return 80
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let isSelected = !self.cellIsSelected(indexPath: indexPath)
selectedIndexs[indexPath] = isSelected
tableView.beginUpdates()
tableView.endUpdates()
}
func cellIsSelected(indexPath: IndexPath) -> Bool {
if let number = selectedIndexs[indexPath] {
return number
} else {
return false
}
}
}
Please put this code in your viewDidLoad() method of your controller.
YOUR_TABLE_VIEW.tableFooterView = UIView(frame: .zero)
this will remove extra separators.
Quickest way to do this would be to add an extra empty cell at the end with row height 80
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return FAQs.count + 1
}
Also, make sure you make a change to cellForRowAt method to accommodate this :
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row < FAQs.count {
let cell = tableView.dequeueReusableCell(withIdentifier: "FAQCell") as! FAQCell
cell.FAQData = FAQs[indexPath.row]
return cell
}
return UITableViewCell()
}
EDIT :
I just read that you don't really require separators after the last cell. In that case look here https://spin.atomicobject.com/2017/01/02/remove-extra-separator-lines-uitableview/

Use segmentcontroller to change tableview

I want to use XMSegmentController(https://cocoapods.org/?q=segmen) to change the different tableview,I do not know what is missing in my program, which leads to a black situation when I run. Does anyone know what to add to my program? Thank you.
Here is mt code:
import UIKit
import XMSegmentedControl
class ViewController: UIViewController, XMSegmentedControlDelegate,UITableViewDelegate,UITableViewDataSource {
#IBOutlet weak var segmentedControl1: XMSegmentedControl!
#IBOutlet weak var tableview1: UITableView!
#IBOutlet weak var tableview2: UITableView!
let one = ["1","2","3"]
let two = ["4","5","6"]
override func viewDidLoad() {
super.viewDidLoad()
segmentedControl1.delegate = self
segmentedControl1.segmentTitle = ["One", "Two"]
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "left", for: indexPath)
cell.textLabel?.text = one[indexPath.row]
return cell
}else {
let cell = tableView.dequeueReusableCell(withIdentifier: "right", for: indexPath)
cell.textLabel?.text = two[indexPath.row]
return cell
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if tableView == self.tableview1 {
return one.count
}
return two.count
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func xmSegmentedControl(_ xmSegmentedControl: XMSegmentedControl, selectedSegment: Int) {
if xmSegmentedControl == segmentedControl1 {
print("SegmentedControl1 Selected Segment: \(selectedSegment)")
}
}
}
Set your controller as initial ViewController to show your Controller. Now use selectedSegment argument from delegate method and hide/show the tableView according to it.
func xmSegmentedControl(_ xmSegmentedControl: XMSegmentedControl, selectedSegment: Int) {
if xmSegmentedControl == segmentedControl1 {
tableview1.isHidden = selectedSegment != 0
tableview2.isHidden = selectedSegment != 1
}
}
Also instead of using two tableView you can use single tableView like this.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if segmentedControl1.selectedSegment == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "left", for: indexPath)
cell.textLabel?.text = one[indexPath.row]
return cell
}else {
let cell = tableView.dequeueReusableCell(withIdentifier: "right", for: indexPath)
cell.textLabel?.text = two[indexPath.row]
return cell
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if segmentedControl1.selectedSegment == 0 {
return one.count
}
return two.count
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
And in delegate method of xmSegmentedControl simply reload the tableView.
func xmSegmentedControl(_ xmSegmentedControl: XMSegmentedControl, selectedSegment: Int) {
if xmSegmentedControl == segmentedControl1 {
tableView.reloadData()
}
}
what is your initial ViewController?can you please check in your storyboard?
set an initial viewcontroller.
func xmSegmentedControl(_ xmSegmentedControl: XMSegmentedControl, selectedSegment: Int) {
if xmSegmentedControl == segmentedControl1 {
tableviewOne.isHidden = selectedSegment != 0
tableviewSecond.isHidden = selectedSegment != 1
}
}

Resources