I'm using following code to display an UIImageView in textFieldDidEndEditing:
let indexPath = IndexPath(row: 0, section: 0)
let cell = tableViewBodydata.cellForRow(at: indexPath) as! tvcell_Logbook
cell.imageViewArrow.isHidden = false
cell.imageViewArrow.image = UIImage(named: "same.png")
The code works perfectly on the iPhone X Simulator. But if im testing it on my iPhone X Device, the imageView isn't shown. The function is called correctly, I debuged it, but nothing happens. I reinstalled the App several times and also restarted the Device but nothing changed. Can anybody help me please?
Edit 1
I'm using this code in cellForRow:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell: tvcell_Logbook!
if indexPath.row == 0 {
cell = tableView.dequeueReusableCell(withIdentifier: "CellWeight", for: indexPath) as! tvcell_Logbook
cell.imageViewArrow.isHidden = false
cell.imageViewArrow.image = UIImage(named: "same.png")
}
...
return cell }
And this code in textFieldDidEndEditing:
func textFieldDidEndEditing(_ textField: UITextField) {
let indexPath = IndexPath(row: 0, section: 0)
let cell = tableViewBodydata.cellForRow(at: indexPath) as! tvcell_Logbook
cell.imageViewArrow.isHidden = false
cell.imageViewArrow.image = UIImage(named: "same.png") }
If your filename is Same.png:
UIImage(named: "Same.png")
How is your picture named at filesystem?
Related
This question already has answers here:
Issue Detecting Button cellForRowAt
(3 answers)
Closed 2 years ago.
Using this code i only get tag which has indexpath.row how to make a button event from it.
TaskPlayButton is my button on that i am passing indexpath.row
for single section this would have worked by now how to do on multiple section.
Is there any other way of knowing which button is clicked?
func numberOfSections(in tableView: UITableView) -> Int {
return mobileBrand.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return mobileBrand[section].modelName?.count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TaskCell", for: indexPath) as! TaskCell
cell.TaskName.text = mobileBrand[indexPath.section].modelName?[indexPath.row]
cell.TaskPlayButton.tag = indexPath.row
cell.TaskPlayButton.addTarget(self, action: #selector(PlayBtnClicked( _:)), for: UIButton.Event.touchUpInside)
return cell
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let view = UIView(frame: CGRect(x: 0, y: 0, width: tableView.frame.width, height: 40))
view.backgroundColor = UIColor.rgb(red: 245, green: 245, blue: 245)
let lbl = UILabel(frame: CGRect(x: 15, y: 0, width: view.frame.width - 15, height: 40))
lbl.font = UIFont.systemFont(ofSize: 20)
lbl.text = mobileBrand[section].brandName
view.addSubview(lbl)
return view
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 40
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if selectedIndex == indexPath.row && isCollapse == true && selectedSection == indexPath.section{
return 240
}else{
return 60
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
if selectedIndex == indexPath.row && selectedSection == indexPath.section{
if self.isCollapse == false
{
self.isCollapse = true
}else{
self.isCollapse = false
}
}else{
self.isCollapse = true
}
self.selectedIndex = indexPath.row
self.selectedSection = indexPath.section
TaskTableView.beginUpdates()
TaskTableView.endUpdates()
}
#objc func PlayBtnClicked(_ sender : UIButton)
{
print(sender.tag)
}
you can use another method like pass tag to button like this
cell.button.tag = (indexpath.section * 1000) + indexpath.row
now on your button action you can get like
let row = sender.tag%1000
let section = sender/1000
you can use closure, please look to my codes :
class YourTableViewCell: UITableViewCell {
var button: UIButton!
var buttonAction: ((UIButton) -> Void)?
#objc func buttonPressed(_ sender : UIButton)) {
self.buttonAction?(sender)
}
}
Implement it to your table view delegate :
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TaskCell", for: indexPath) as! TaskCell
cell.TaskName.text = mobileBrand[indexPath.section].modelName?[indexPath.row]
cell.TaskPlayButton.tag = indexPath.row
cell.buttonAction = { sender in
// do your action
// in here, you can get indexPath.row and indexPath.section
}
cell.TaskPlayButton.addTarget(self, action: #selector(PlayBtnClicked( _:)), for: UIButton.Event.touchUpInside)
return cell
}
Hope this answer can help you :)
Pass indexPath to cell, when click the button in this cell, you could get the current indexPath
Custom a button hold a property: indexPath. Pass indexPath to the button in the method cellForRowAt. When you click the button, you could use button.indexPath to get what you want.
I just give you quick tip. It just help you on all table view in your project.
You can follow my answer here - https://stackoverflow.com/a/62481414/8135121
Here it's for you.
You can grab it by position of your button.
I explain it to you.
Make a common table view extension on your class. Just use this.
extension UITableView {
func getCellFrom(sender : UIView,completion : #escaping (UITableViewCell,IndexPath)->()){
var superview = sender.superview
while let view = superview, !(view is UITableViewCell) {
superview = view.superview
}
guard let cell = superview as? UITableViewCell else {
return
}
guard let indexPath = self.indexPath(for: cell) else {
return
}
completion(cell,indexPath)
}
}
Set target from cell in your cell for row at IndexPath function.
cell.TaskPlayButton.addTarget(self, action: #selector(PlayBtnClicked( _:)), for: UIButton.Event.touchUpInside)
Call this in PlayBtnClicked action method.
tableView.getCellFrom(sender: sender) { [weak self] (cell, indexPath) in
// Just use indexPath in here
//This closure return your cell and your button's indexPath also
}
I am having a strange issue with displaying a switch in a dynamic tableview: one of the UISwitch instances is aligned to the left. As soon as it is switched, it goes back to normal...for a while.
Reproduction of the issue
I can reproduce the issue on a physical devices and simulators for all types of devices. The row where the problem occurs depends on the screen size of the device: it seems to be the first row that is invisible at the start. On small devices row 8, on larger iPhones row 10 or 11. When I scroll, the same row is affected.
Screen shot:
My code:
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return woordeninlijst.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let CellIdentifier = "Cell"
let cell = tableView.dequeueReusableCell(withIdentifier: CellIdentifier, for: indexPath) as! WoordTableViewCell
cell.woordLabel.text = woordeninlijst[indexPath.row].naam
cell.hulpWoordLabel.text = woordeninlijst[indexPath.row].hulpWoord
var scoreImage = [0: #imageLiteral(resourceName: "score grijs"), 1: #imageLiteral(resourceName: "score oranje"), 2: #imageLiteral(resourceName: "score geel"), 3: #imageLiteral(resourceName: "score groen")]
cell.score1.image = scoreImage[Int(woordeninlijst[indexPath.row].score1)]
cell.score2.image = scoreImage[Int(woordeninlijst[indexPath.row].score2)]
cell.score3.image = scoreImage[Int(woordeninlijst[indexPath.row].score3)]
cell.score4.image = scoreImage[Int(woordeninlijst[indexPath.row].score4)]
cell.score5.image = scoreImage[Int(woordeninlijst[indexPath.row].score5)]
let activeSwitch = UISwitch()
cell.accessoryView = activeSwitch
activeSwitch.addTarget(self, action: #selector(WoordTableViewController.switchChanged(sender:)), for: UIControlEvents.valueChanged)
activeSwitch.tag = indexPath.row
activeSwitch.isOn = woordeninlijst[indexPath.row].isActive
return cell
}
#objc func switchChanged(sender: UISwitch!) {
print("Switch value is \(sender.isOn)")
print("Switch item is \(sender.tag)")
let changeWoord: WoordMO = woordeninlijst[sender.tag]
if changeWoord.isActive == true {
changeWoord.isActive = false}
else {
changeWoord.isActive = true
}
}
Any help is incredibly appreciated!
I'm working on a project in swift 3.0 where I have a UIView inside a UITableViewCell. For some reason once a row is been selected the view gets disappear, and once a a new row is been selected the view of the previous cell shows up and the view of the newly selected one gets disappear.Name of the view that gets disappear is redView(reference of the code bellow). My code and UITableView delegates as follow.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
let backgroundView = UIView()
backgroundView.backgroundColor = UIColor.clear
cell.selectedBackgroundView = backgroundView
let data = self.mediaList[indexPath.row] as! NSDictionary
let redView = cell.viewWithTag(TABLE_CELL_TAGS.redView)!
let reducedPriceLabel = cell.viewWithTag(TABLE_CELL_TAGS.reducedpricelable) as! UILabel
Utils.setTableCellLabelText(cell: cell, labelTag: TABLE_CELL_TAGS.title, text: data["title"] ?? "title...")
if let reducedPrice = data["mediaValue"] as? Int{
reducedPriceText = "$\(String(reducedPrice))"
redView.isHidden = false
reducedPriceLabel.isHidden = false
}else{
redView.isHidden = true
reducedPriceLabel.isHidden = true
}
Utils.setTableCellLabelText(cell: cell, labelTag: TABLE_CELL_TAGS.reducedpricelable, text: reducedPriceText)
return cell;
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let mP3ViewController = self.storyboard?.instantiateViewController(withIdentifier:"MP3ViewController") as! MP3ViewController
mP3ViewController.mediaDetails = mediaList[indexPath.row] as? NSDictionary
self.navigationController?.pushViewController(mP3ViewController, animated:true)
}
Go to the storyboard setting of tableViewcell set selection to None. then I think it will work for you.
Try this and let me know.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let mP3ViewController = self.storyboard?.instantiateViewController(withIdentifier:"MP3ViewController") as! MP3ViewController
mP3ViewController.mediaDetails = mediaList[indexPath.row] as? NSDictionary
self.navigationController?.pushViewController(mP3ViewController, animated:true)
}
This code was from a now inactive tutorial that helped me load in data to a table view. Since the tutorial was written in Swift 2.0, I believe that this was changed in Swift 3. I know that the override function itself was changed, which I handled. But now, it brings me a Thread 1: EXC_BAD_INSTRUCTION(code=EXC_1386_INVOP, subcode=0x0) error.
Update: I have tried multiple things including creating a custom class for the cell. I still either get the same error I listed above, or a Thread 1: Signal SIGABRT error on the first line of my App Delegate file. Creating a breakpoint hasn't helped me because I know where the error is coming from.
import UIKit
import Firebase
import FirebaseDatabase
struct postStruct {
let title : String!
let message : String!
}
class LoggedInController: UITableViewController {
var posts = [postStruct]()
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.delegate = self
self.tableView.dataSource = self
let databaseRef = FIRDatabase.database().reference()
databaseRef.child("Posts").queryOrderedByKey().observe(.childAdded, with: {
snapshot in
let snapshotValue = snapshot.value as? NSDictionary
let title = snapshotValue!["title"] as? String
let message = snapshotValue!["message"] as? String
self.posts.insert(postStruct(title: title, message: message), at: 0)
self.tableView.reloadData()
})
post()
}
func post(){
let title = "Title"
let message = "Message"
let post : [String : AnyObject] = ["title" : title as AnyObject,
"message": message as AnyObject]
let databaseRef = FIRDatabase.database().reference()
databaseRef.child("Posts").childByAutoId().setValue(post)
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return posts.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "PostCell")
let label1 = cell?.viewWithTag(1) as! UILabel
label1.text = posts[indexPath.row].message
let label2 = cell?.viewWithTag(2) as! UILabel
label2.text = posts[indexPath.row].message
return cell!
}
}
Update 2: Here is the new code I used. It's not pretty and only gets the title.
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return posts.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "Cell")
if cell == nil {
cell = UITableViewCell(style: .default, reuseIdentifier: "Cell")
cell?.textLabel?.text = posts[indexPath.row].title
cell?.detailTextLabel?.text = posts[indexPath.row].message
return cell!
} else {
let label1 = cell?.viewWithTag(1) as? UILabel
label1?.text = posts[indexPath.row].title
let label2 = cell?.viewWithTag(2) as? UILabel
label2?.text = posts[indexPath.row].message
return cell!
}
}
Using dequeueReusableCell, you are accessing cell which doesn't exists. To make your code work change the below line:
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell")
To
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
Ok this code let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") produces an optional called cell that may or may not contain a a valid instance of UITableViewCell. Optionals in Swift are a way to safeguard against nil values, you can read more about optionals here: Optionals
On the first run when your table view wants to load its data it calls all the required methods of your UITableViewDataSource. The first run is a critical one because there aren't any instances of the UITableViewCell the table view can dequeue yet. To solve your problem you have to do something similar to the code below:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return posts.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "cell")
if cell == nil {
cell = UITableViewCell(style: .default, reuseIdentifier: "cell")
cell?.textLabel?.text = "New value"
cell?.detailTextLabel?.text = "New value"
return cell!
} else {
cell?.textLabel?.text = "" //reset value
cell?.detailTextLabel?.text = "" // resetValue
cell?.textLabel?.text = "New value"
cell?.detailTextLabel?.text = "New value"
return cell!
}
}
Code similar to the one above are usually used to programmatically add an instance of UITableViewCell. However, if you used interface builder to add a prototype cell use the let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) method to dequeue your cells in which case it does not return an optional and you do not need to do all the if / else blocks.
Something else I wanted to mention about your code is finding sub views buy their ID will not produce a very object oriented code and that maybe the source of your errors where the compiler can not find the sub views. The better way would be to use one of the built in instances of UITableViewCell such as .default or alliteratively you could subclass the said class and make your very own custom cells.
Hope this helped!
Try this
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell:UITableViewCell = self.tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier) as UITableViewCell!
let label1 = cell.viewWithTag(1) as! UILabel
label1.text = posts[indexPath.row].message
let label2 = cell.viewWithTag(2) as! UILabel
label2.text = posts[indexPath.row].message
return cell
}
Edited
Make Sure you did these things
UITableViewController
In viewDidLoad()
self.tableView.register(UITableViewCell.self, forCellReuseIdentifier:"catCell" )
let catNib : UINib = UINib.init(nibName: "TableViewCategoryCell", bundle: nil)
self.tableView.register(catNib, forCellReuseIdentifier: "TableViewCategoryCell")
In cellForRowAt indexPath
let cell : OPM_AlarmTableViewCategoryCell = tableView.dequeueReusableCell(withIdentifier:"OPM_AlarmTableViewCategoryCell" ) as! OPM_AlarmTableViewCategoryCell!
cell.categoryLabel?.text = "Some Text"
return cell
UITableviewCell.XIB
Hope u did these things
UITableviewCell
Make sure the dot appears so that the #IBOutlet is connected with the
xib label
I have a case in which I have to reload only height of a UITableViewCell.
but if I call the function
tableView.reloadRowsAtIndexPaths([NSIndexPath(forRow: webView.tag, inSection: 0)], withRowAnimation: .Automatic)
it reloads the height as well as the data of the cell.
How can i just control the height of cell in Swift?
This is my cellForRow block :
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if indexPath.row == 0 {
let cell = tableView.dequeueReusableCellWithIdentifier("cell1", forIndexPath: indexPath) as! CustomTableViewCell1
cell.heading.text = headerText
return cell
}
else if indexPath.row == 1 {
let cell = tableView.dequeueReusableCellWithIdentifier("cell2", forIndexPath: indexPath) as! CustomTableViewCell2
ImageLoader.sharedLoader.imageForUrl(self.headerImage , completionHandler:{(image: UIImage?, url: String) in
cell.mainImage.image = image
})
return cell
}
else if indexPath.row == 2 {
let cell = tableView.dequeueReusableCellWithIdentifier("cell3", forIndexPath: indexPath) as! CustomTableViewCell3
//cell.aurthorImage.image = UIImage(named : "obama")
ImageLoader.sharedLoader.imageForUrl(self.headerImage , completionHandler:{(image: UIImage?, url: String) in
cell.aurthorImage.image = image
})
cell.aurthorImage.tag = aurthorID
cell.aurthorImage.layer.cornerRadius = cell.aurthorImage.frame.height/2
cell.aurthorImage.clipsToBounds = true
cell.aurthorImage.userInteractionEnabled = true
cell.aurthorImage.addGestureRecognizer(aurthorImageTapRecignizer)
cell.aurthorName.text = self.authorName
cell.time.text = self.time
self.followButton = cell.followButton
return cell
}
else if indexPath.row == 3 {
let cell = tableView.dequeueReusableCellWithIdentifier("cell4", forIndexPath: indexPath) as! CustomTableViewCell4
let htmlHeight = contentHeights[indexPath.row]
cell.webElement.tag = indexPath.row
cell.webElement.delegate = self
cell.webElement.loadHTMLString(HTMLContent, baseURL: nil)
cell.webElement.frame = CGRectMake(0, 0, cell.frame.size.width, htmlHeight)
return cell
}
else if indexPath.row == 4 {
let cell = tableView.dequeueReusableCellWithIdentifier("cell1", forIndexPath: indexPath) as! CustomTableViewCell1
cell.heading.text = "Related Posts"
return cell
}
else if indexPath.row == 5{
let cell = tableView.dequeueReusableCellWithIdentifier("cell6", forIndexPath: indexPath) as! CustomTableViewCell6
return cell
}
else if indexPath.row == 6 {
let cell = tableView.dequeueReusableCellWithIdentifier("cell1", forIndexPath: indexPath) as! CustomTableViewCell1
cell.heading.text = "Comments"
return cell
}
else if indexPath.row == 7 {
let cell = tableView.dequeueReusableCellWithIdentifier("cell5", forIndexPath: indexPath) as! CustomTableViewCell5
let htmlHeight = contentHeights[indexPath.row]
self.commentSection = cell.commentsView
self.commentSection.tag = indexPath.row
self.commentSection.delegate = self
let url = NSURL(string: commentsURL)
let requestObj = NSURLRequest(URL: url! )
self.commentSection.loadRequest(requestObj)
self.commentSection.frame = CGRectMake(0, 0, cell.frame.size.width, htmlHeight)
commentSectionDidNotLoad = false
return cell
}
else {
let cell = tableView.dequeueReusableCellWithIdentifier("cell1", forIndexPath: indexPath) as! CustomTableViewCell1
cell.heading.text = headerText
return cell
}
You can use this code to update the cell's height without reloading their data:
tableView.beginUpdates()
tableView.endUpdates()
You can also use this method followed by the endUpdates method to animate the change in the row heights without reloading the cell.
UITableView Class Reference
start an update of the tableview and then end it without changing anything.
tableView.beginUpdates()
tableView.endUpdates()
This should make the tableview set the new height
You can regulate the height by either implementing the (a)heightForRowAtIndexPath with logic setting the heights or (b)with auto layout and automatic tableview row height
A.
override func tableView(tableView: UITableView!, heightForRowAtIndexPath indexPath: NSIndexPath!) -> CGFloat {
if [your condition, row == 5 in your comment] {
return 100
} else {
return 40
}
}
Whenever you want to change the height you would just call these two rows
tableView.beginUpdates()
tableView.endUpdates()
B.
in viewDidLoad
tableView.estimatedRowHeight = 40.0
tableView.rowHeight = UITableViewAutomaticDimension
and then you can just expose the layout constraint that set's the cells height and access it to set the height when you want
cell.heightConstraint.constant = 100
tableView.beginUpdates()
tableView.endUpdates()
About your question for example, to give a specific height dimension :
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
if indexPath.row == 3 {
return 50.0
}
return 72.0
}
But I think you have a webView inside a cell so, generally, to calculate the dynamic height of a UITableViewCell with a UIWebView:
(this example have two webViews)
class MyTableViewController: UITableViewController, UIWebViewDelegate
{
var content : [String] = ["<!DOCTYPE html><html><head><title>Page Title</title></head><body><h1>My First Heading</h1><p>My first paragraph</p></body></html>", "<HTML><HEAD><TITLE>Coca-Cola</TITLE></HEAD><BODY>In Chinese, Coca-Cola means Bite the Wax Tadpole</BODY></HTML>"]
var contentHeights : [CGFloat] = [0.0, 0.0]
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCellWithIdentifier("myCustomCell", forIndexPath: indexPath) as! MyCustomCell
let htmlString = content[indexPath.row]
let htmlHeight = contentHeights[indexPath.row]
cell.webView.tag = indexPath.row
cell.webView.delegate = self
cell.webView.loadHTMLString(htmlString, baseURL: nil)
cell.webView.frame = CGRectMake(0, 0, cell.frame.size.width, htmlHeight)
return cell
}
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat
{
return contentHeights[indexPath.row]
}
func webViewDidFinishLoad(webView: UIWebView)
{
if (contentHeights[webView.tag] != 0.0)
{
// height knowed, no need to reload cell
return
}
contentHeights[webView.tag] = webView.scrollView.contentSize.height
tableView.reloadRowsAtIndexPaths([NSIndexPath(forRow: webView.tag, inSection: 0)], withRowAnimation: .Automatic)
}
}
You can use the view height constraint in the cell, by updating the view in cell height you can update the specific cell height.
let height = cell.Height_constraint.constant
cell.Height_constraint.constant = height + 200 //200 you can use any number
Height_constraint: is the height constraint of subView in my cell.