I am Using UITableView For Display some data. But I have Seperated the Datasource and Delegate Methods to another class. So my TableViewController is not having Any delegate Methods. They are in Seperate Class.
So when the tableview loads for the First Time, It loads the values. but when i use tableView.reloadData on a button click of a cell , It does not calls the cellForRawAtIndexPath Method. But it calls numberOfRawsInSection and other methods.
Here is my Controller Class
class AdvancedSearch: UITableViewController , PopOverViewDelegate{
#IBOutlet var model: AdvancedSearchDataModel!
let dataModel = AdvancedSearchDataModel()
override func viewDidLoad() {
super.viewDidLoad()
tableView.registerNib(UINib(nibName: "AgeCell", bundle: nil), forCellReuseIdentifier: "AgeCell")
tableView.registerNib(UINib(nibName: "ExperienceCell", bundle: nil), forCellReuseIdentifier: "ExperienceCell")
tableView.registerNib(UINib(nibName: "CityCell", bundle: nil), forCellReuseIdentifier: "CityCell")
tableView.registerNib(UINib(nibName: "StateCell", bundle: nil), forCellReuseIdentifier: "StateCell")
tableView.registerNib(UINib(nibName: "DateTimeCell", bundle: nil), forCellReuseIdentifier: "DateTimeCell")
tableView.registerNib(UINib(nibName: "GenderCell", bundle: nil), forCellReuseIdentifier: "GenderCell")
tableView.registerNib(UINib(nibName: "ResultButtonCell", bundle: nil), forCellReuseIdentifier: "ResultButtonCell")
//tableView.dataSource = model
//tableView.delegate = model
tableView.separatorColor = UIColor.grayColor()
tableView.allowsSelection = false
tableView.separatorStyle = UITableViewCellSeparatorStyle.None
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
tableView.reloadData()
}
// MARK: - DropDown PopOver Delegates
func valueOfTheFieldWhenSelect(tableViewCell: UITableViewCell, value: String, indexPath: NSIndexPath) {
let data = AdvancedSearchDataModel()
data.buttonTitle = value
self.tableView.delegate = data
self.tableView.dataSource = data
self.tableView.reloadData()
}
Here is my Datasource and Delegates in Seperate Class
class AdvancedSearchDataModel: NSObject , UITableViewDataSource , UITableViewDelegate , AdvanceSearchDropDownButtonDelegate , UIPopoverPresentationControllerDelegate {
let data = ["Age","Experience","City" , "State" , "Gender" , "Date and Time"]
// set this proprty in PopOverViewDelegate method
var buttonTitle : String?
// MARK: - TableView Datasource
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print("Count : \(data.count)")
return data.count + 1
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
switch indexPath.row {
case 0:
let cell = tableView.dequeueReusableCellWithIdentifier("AgeCell", forIndexPath: indexPath) as! AgeCell
applyStyleForButton(cell.selectAge)
let frame = CGRectMake(0, cell.frame.size.height - 2, cell.frame.size.width,2)
let additionalSeparator = UIView(frame: frame)
additionalSeparator.backgroundColor = UIColor.grayColor()
cell.addSubview(additionalSeparator)
if buttonTitle != nil {
cell.selectAge.setTitle(buttonTitle, forState: .Normal)
}
cell.indexPath = indexPath
cell.dropDownDelegate = self
return cell
case 1:
let cell = tableView.dequeueReusableCellWithIdentifier("ExperienceCell", forIndexPath: indexPath) as! ExperienceCell
applyStyleForButton(cell.selectExperinceBtn)
let frame = CGRectMake(0, cell.frame.size.height - 2, cell.frame.size.width,2)
let additionalSeparator = UIView(frame: frame)
additionalSeparator.backgroundColor = UIColor.grayColor()
cell.addSubview(additionalSeparator)
return cell
case 2:
let cell = tableView.dequeueReusableCellWithIdentifier("CityCell", forIndexPath: indexPath) as! CityCell
applyStyleForButton(cell.cityButton)
let frame = CGRectMake(0, cell.frame.size.height - 2, cell.frame.size.width,2)
let additionalSeparator = UIView(frame: frame)
additionalSeparator.backgroundColor = UIColor.grayColor()
cell.addSubview(additionalSeparator)
return cell
case 3:
let cell = tableView.dequeueReusableCellWithIdentifier("StateCell", forIndexPath: indexPath) as! StateCell
applyStyleForButton(cell.stateButton)
let frame = CGRectMake(0, cell.frame.size.height - 2, cell.frame.size.width,2)
let additionalSeparator = UIView(frame: frame)
additionalSeparator.backgroundColor = UIColor.grayColor()
cell.addSubview(additionalSeparator)
return cell
case 4:
let cell = tableView.dequeueReusableCellWithIdentifier("GenderCell", forIndexPath: indexPath) as! GenderCell
let frame = CGRectMake(0, cell.frame.size.height - 2, cell.frame.size.width,2)
let additionalSeparator = UIView(frame: frame)
additionalSeparator.backgroundColor = UIColor.grayColor()
cell.addSubview(additionalSeparator)
return cell
case 5:
let cell = tableView.dequeueReusableCellWithIdentifier("DateTimeCell", forIndexPath: indexPath) as! DateTimeCell
applyStyleForButton(cell.datebutton)
applyStyleForButton(cell.timeButton)
let frame = CGRectMake(0, cell.frame.size.height - 2, cell.frame.size.width,2)
let additionalSeparator = UIView(frame: frame)
additionalSeparator.backgroundColor = UIColor.grayColor()
cell.addSubview(additionalSeparator)
return cell
case 6:
let cell = tableView.dequeueReusableCellWithIdentifier("ResultButtonCell", forIndexPath: indexPath) as! ResultButtonCell
let frame = CGRectMake(0, cell.frame.size.height - 2, cell.frame.size.width,2)
let additionalSeparator = UIView(frame: frame)
additionalSeparator.backgroundColor = UIColor.grayColor()
cell.addSubview(additionalSeparator)
return cell
default:
return UITableViewCell()
}
}
// MARK: - TableView Delegates
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
if indexPath.row == 5 {
return 150
}else{
return 94
}
}
// MARK: - Styling
func applyStyleForButton(button : UIButton){
button.layer.borderColor = UIColor.grayColor().CGColor
button.layer.borderWidth = 1
button.layer.cornerRadius = 5
button.backgroundColor = UIColor.clearColor()
}
// MARK: - DropDown Delegates
func openAgeDropDown(by button: UIButton, and cell: AgeCell,indexPath : NSIndexPath)
{
print("Age opened")
let tableViewController = DropDownController(style: .Plain, menuItems: ["10","20","30"],cell: cell , index: indexPath)
tableViewController.modalPresentationStyle = UIModalPresentationStyle.Popover
tableViewController.preferredContentSize = CGSizeMake(button.frame.width, button.frame.width)
// assigning the delegate in tableView to fill the textfield
tableViewController.delegate = AdvancedSearch()
let popoverPresentationController = tableViewController.popoverPresentationController
popoverPresentationController?.permittedArrowDirections = .Any
popoverPresentationController?.delegate = self
popoverPresentationController?.sourceView = button
popoverPresentationController?.sourceRect = button.bounds
UIApplication.sharedApplication().keyWindow?.rootViewController!.presentViewController(tableViewController, animated: true, completion: nil)
}
// MARK: - PopOver Delegates
func adaptivePresentationStyleForPresentationController(controller: UIPresentationController) -> UIModalPresentationStyle {
return UIModalPresentationStyle.None
}}
Please Guide me
The methods is not calling because everytime you are creating a new object of AdvancedSearchDataModel. instead this assign delegate in viewDidLoad. don't need to create new object of AdvancedSearchDataModel
in viewDidLoad
...
tableView.separatorColor = UIColor.grayColor()
tableView.allowsSelection = false
tableView.separatorStyle = UITableViewCellSeparatorStyle.None
tableView.delegate = self.model
tableView.dataSource = self.model
and in valueOfTheFieldWhenSelect
func valueOfTheFieldWhenSelect(tableViewCell: UITableViewCell, value: String, indexPath: NSIndexPath) {
self.model.buttonTitle = value
self.tableView.reloadData()
}
Related
I programmatically add a TableView in a ViewController, then appeared an extra row. I would like to be able to manage it, but first I would have to know what it is. This line seems to come from the TabBar rather than the TableView. Do you know which object it is?
The code:
import UIKit
final class SearchViewController2: UIViewController, UITableViewDataSource, UITableViewDelegate {
private let ingredients = [
"flour",
"sugar",
"eggs",
"butter",
"baking powder",
"vanilla extract",
"milk",
"salt",
"cocoa powder",
"yeast",
"olive oil",
"cheese",
"breadcrumbs",
"onions",
"garlic",
"tomatoes",
"basil",
"oregano",
"thyme",
"parsley",
"pepper"
]
private let tableView: UITableView = {
let tableView = UITableView()
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
return tableView
}()
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
let ingredient = ingredients[indexPath.row]
var cellConfig = cell.defaultContentConfiguration()
cellConfig.text = ingredient
cell.contentConfiguration = cellConfig
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
ingredients.count
}
override func viewDidLoad() {
super.viewDidLoad()
let header = StretchyTableHeaderView(
frame: CGRect(
x: 0,
y: 0,
width: view.frame.size.width,
height: view.frame.size.width / 2
)
)
view.addSubview(tableView)
header.imageView.image = UIImage(named: "header")
tableView.dataSource = self
tableView.delegate = self
tableView.frame = view.bounds
tableView.tableHeaderView = header
}
}
extension SearchViewController2: UIScrollViewDelegate {
func scrollViewDidScroll(_ scrollView: UIScrollView) {
guard let header = tableView.tableHeaderView as? StretchyTableHeaderView else { return }
header.scrollViewDidScroll(scrollView: tableView)
}
}
I tried to add/remove a footer in the TableView... No changes.
I want my swift code to delete the tableview cell within the cell using the blue button. You can see a example of what I am trying to below in the gif. I also have a indexPath selection var. You should probably have to delete it in the deleteCell func also I assume you would use a tag. All the code is in below no need for storyboard.
import UIKit
class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource, UIImagePickerControllerDelegate & UINavigationControllerDelegate {
var arr = [1,1,3,3]
var tableview = UITableView()
var selectedIndexPath = IndexPath(row: 0, section: 0)
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 2
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 118
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! customtv
return cell
}
#objc func deleteCell(){
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
tableview.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height * 0.8)
view.addSubview(tableview)
tableview.register(customtv.self, forCellReuseIdentifier: "cell")
tableview.delegate = self
tableview.dataSource = self
}
}
class customtv: UITableViewCell {
lazy var backView : UIView = {
let view = UIView(frame: CGRect(x: 10, y: 6, width: self.frame.width , height: 110))
view.backgroundColor = .green
return view
}()
lazy var btn : UIButton = {
let btn = UIButton(frame: CGRect(x: 50, y: 6, width: 100 , height: 110))
btn.backgroundColor = .blue
return btn
}()
override func layoutSubviews() {
backView.clipsToBounds = true
backView.frame = CGRect(x: 0, y: 6, width: bounds.maxX , height: 110)
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(animated, animated: true)
addSubview(backView)
backView.addSubview(btn)
}
}
Here's my solution:
import UIKit
class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource, CustomTvCellDelegate, UIImagePickerControllerDelegate & UINavigationControllerDelegate {
var cellCount = 2
var tableview = UITableView()
var selectedIndexPath = IndexPath(row: 0, section: 0)
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return cellCount // use a variable here so you can change it as you delete cells, else it will crash
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 118
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CustomTv
cell.delegate = self
return cell
}
func deleteCell(_ customTV: CustomTv, location: CGPoint) {
// put the button location in an index path array
var deleteArray = [IndexPath]()
if let indexPath = tableview.indexPathForRow(at: location) {
deleteArray.append(indexPath)
}
cellCount -= 1 // update the row count as you delete a cell
// delete the row using the delete array with a fade animation
tableview.deleteRows(at: deleteArray, with: .fade)
}
override func viewDidLoad() {
super.viewDidLoad()
tableview.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height * 0.8)
view.addSubview(tableview)
tableview.register(CustomTv.self, forCellReuseIdentifier: "cell")
tableview.delegate = self
tableview.dataSource = self
}
}
// you need to declare a cell delegate that will let your tableview know when the button was tapped on the cell
protocol CustomTvCellDelegate: AnyObject {
func deleteCell(_ customTV: CustomTv, location: CGPoint)
}
class CustomTv: UITableViewCell { // it's good form to Pascal case your class name ;)
weak var delegate: CustomTvCellDelegate? // make that delegate a property of your cell
lazy var backView : UIView = {
let view = UIView(frame: CGRect(x: 10, y: 6, width: self.frame.width , height: 110))
view.backgroundColor = .green
return view
}()
lazy var btn : UIButton = {
let btn = UIButton(frame: CGRect(x: 50, y: 6, width: 100 , height: 110))
btn.backgroundColor = .blue
return btn
}()
override func layoutSubviews() {
backView.clipsToBounds = true
backView.frame = CGRect(x: 0, y: 6, width: bounds.maxX , height: 110)
// moved these calls here instead of on setSelected(_selected:animated:)
addSubview(backView)
backView.addSubview(btn)
btn.addTarget(self, action:#selector(self.deleteCell), for: .touchUpInside)
}
#objc func deleteCell(sender: UIButton){
// let your cell delegate (tableview) know what the button got tapped, you need to pass the button here)
let buttonLocation = sender.superview?.convert(sender.frame.origin, to: nil) ?? CGPoint.zero
delegate?.deleteCell(self, location: buttonLocation)
}
}
i want my swift code to add together all of the tableview cells together and convert it from a string to a int. The code should be called from the view did load func. The total should be 3 when all of the labels are added together. Look at my comment in view did load for more info. The code does not use storyboards.
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var numberOfRows = 3
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { numberOfRows }
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { 118 }
var tableView = UITableView()
var selectedIndexPath = IndexPath(row: 0, section: 0)
override func viewDidLoad() {
super.viewDidLoad()
setTableVIew()
//print the sum of the labels added togther on the tableview cells
}
func setTableVIew(){
let VCframe = view.frame
let height = VCframe.height * 0.8
let widthx = VCframe.width
tableView.frame = CGRect(x: 10, y: 0, width: widthx - 20, height: height)
tableView.delegate = self
tableView.dataSource = self
view.addSubview(tableView)
tableView.register(customtv.self, forCellReuseIdentifier: "cell")
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! customtv
cell.lbl.text = "\(indexPath.row)"
return cell
}
}
class customtv: UITableViewCell {
lazy var backView : UIView = {
let view = UIView(frame: CGRect(x: 10, y: 6, width: self.frame.width , height: 110))
view.backgroundColor = .green
print(self.frame.width)
return view
}()
override func layoutSubviews() {
backView.clipsToBounds = true
backView.frame = CGRect(x: 0, y: 6, width: bounds.maxX , height: 110)
}
lazy var lbl : UILabel = {
let press = UILabel(frame: CGRect(x: 0, y: 3, width: 120 , height: 50))
press.backgroundColor = .yellow
press.text = String("1")
return press
}()
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(animated, animated: true)
addSubview(backView)
backView.addSubview(lbl)
}
}
Here's how you do this:
override func viewDidLoad() {
super.viewDidLoad()
setTableView()
calculateSum()
}
func calculateSum() {
var sum = 0
for row in 0..<numberOfRows {
let indexPath = IndexPath(row: row, section: 0)
let cell = tableView.cellForRow(at: indexPath) as! CustomTableViewCell
sum += Int(cell.label.text ?? "") ?? 0
}
print(sum)
}
Note: Make the class and object names consistent eg: lbl -> label and customtv -> CustomTableViewCell as I've given above. Even the method names setTableVIew -> setTableView. It would be best if you use SwiftLint.
My tableview isn't loading once I press build, can anyone see what's wrong with the code as to why it's not showing up? In the console, it's printing the data from Firestore, but I can't see anything on the simulator but a white screen.
struct Posts {
var caption:String
}
class CoursesVC: UIViewController, UITableViewDelegate {
let tableView = UITableView()
var posts = [Posts]()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
self.tableView.dataSource = self
self.tableView.delegate = self
setupViews()
loadPosts()
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
func loadPosts() {
let dbUsers = Firestore.firestore().collection("Payouts")
dbUsers.addSnapshotListener { (querySnapshot, error) in
if let error = error {
print("\(error.localizedDescription)")
} else {
for document in (querySnapshot?.documents)! {
if let Caption = document.data()["amount"] as? String {
print(Caption)
var post = Posts(caption: "")
post.caption = Caption
self.posts.append(post)
}
}
DispatchQueue.main.async
{
self.tableView.reloadData()
}
print(self.posts)
}
}
}
private func setupViews() {
let stackView: UIStackView = {
let sv = UIStackView()
sv.translatesAutoresizingMaskIntoConstraints = false
sv.spacing = 28
sv.axis = .vertical
sv.distribution = .fill
sv.alignment = .fill
return sv
}()
view.addSubview(stackView)
view.addSubview(tableView)
}
}
extension CoursesVC: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return posts.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
let post = posts[indexPath.row]
cell.textLabel?.text = post.caption
return cell
}
}
You forgot to assign frame to your tableView. As you are adding your tableView programatically so, you have to set frame for your tableView. Write below code in your setupViews() method.
E.g. tableView.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 450.0)
Change tableView frame as per your requirement.
I want to change the View of my ViewController based on 2 tableVIews with segmentedControl. I have reached it with programmatic approach. I created two TableViews and One SegmentedControl. But When I change the segmentedControl it stays on the same Index but changing the View. I have to tap twice on each Segment to reach it. Why it is happening?
Here is my code:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
configureFirstTableView()
}
var firstTableView = UITableView()
var secondTableView = UITableView()
func configureFirstTableView() {
firstTableView.frame = self.view.frame
firstTableView.delegate = self
firstTableView.dataSource = self
firstTableView.register(UITableViewCell.self, forCellReuseIdentifier: "FirstCell")
view.addSubview(firstTableView)
}
func configureSecondTableView() {
secondTableView.frame = self.view.frame
secondTableView.delegate = self
secondTableView.dataSource = self
secondTableView.register(UITableViewCell.self, forCellReuseIdentifier: "SecondCell")
view.addSubview(secondTableView)
}
func configureSegmentedControl() -> UISegmentedControl {
let segmentedControl = UISegmentedControl(frame: CGRect(x: 10, y: 5, width: view.frame.width - 10, height: 30))
segmentedControl.insertSegment(withTitle: "First", at: 0, animated: false)
segmentedControl.insertSegment(withTitle: "Second", at: 1, animated: false)
segmentedControl.selectedSegmentIndex = 0
segmentedControl.addTarget(self, action: #selector(changeSegmentedControlValue(_:)), for: .valueChanged)
return segmentedControl
}
#objc func changeSegmentedControlValue(_ sender: UISegmentedControl) {
switch sender.selectedSegmentIndex {
case 0:
print("1")
configureFirstTableView()
case 1:
print("2")
configureSecondTableView()
default:
break
}
}
}
extension ViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
var count: Int?
if tableView == firstTableView {
count = 3
return count!
} else if tableView == secondTableView {
count = 4
return count!
}
return count!
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if tableView == firstTableView {
let cell = tableView.dequeueReusableCell(withIdentifier: "FirstCell", for: indexPath)
cell.textLabel?.text = "First"
return cell
} else if tableView == secondTableView {
let cell = tableView.dequeueReusableCell(withIdentifier: "SecondCell", for: indexPath)
cell.textLabel?.text = "Second"
return cell
}
return UITableViewCell()
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let v = UIView()
v.backgroundColor = .white
v.addSubview(configureSegmentedControl())
return v
}
}