Here is how I use my custom UITableViewCell RunningTableViewCell inside UIViewController:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("myCell", forIndexPath: indexPath) as! RunningTableViewCell
//.......
cell.isTop = false
if(indexPath.row == 0){
cell.isTop = true
}
cell.isBottom = false
if(indexPath.row == myArray.count-1){
cell.isBottom = true
}
return cell
}
And here is my RunningTableViewCell class: (Cell's GUI is made inside storyboard)
class RunningTableViewCell: UITableViewCell {
//#IBOutlet ...
#IBOutlet weak var myButton: SomeButton!
var isTop: Bool?
var isBottom: Bool?
override func awakeFromNib() {
super.awakeFromNib()
print("result: \(self.isTop) \(self.isBottom)")
myButton.isTop = self.isTop
myButton.isBottom = self.isBottom
}
}
It returns result: nil nil
The usage of the result is: (SomeButton is a subview inside RunningTableViewCell)
class SomeButton: UIButton {
var isTop = false
var isBottom = false
override func drawRect(rect: CGRect) {
if(isTop){
// DO SOMETHING...
}
if(isBottom){
// DO SOMETHING...
}
}
}
So how can I pass data to RunningTableViewCell?
awakeFromNib is called right after the view and its subviews were allocated and initialized.
So your code from awakeFromNib in RunningTableViewCell for each cell is called before delegate method func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell. That is why isTop and isBottom are nil in awakeFromNib.
You can define method in RunningTableViewCell, which will load cell with this variables.
func load(isTop: Bool, isBottom: Bool) {
self.isTop = isTop
self.isBottom = isBottom
// Update cell UI as you wish
}
And finally rewrite delegate method func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell in your view controller.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("myCell", forIndexPath: indexPath) as! RunningTableViewCell
let isTop = indexPath.row == 0
let isBottom = indexPath.row == myArray.count-1
cell.load(isTop, isBottom: isBottom)
return cell
}
You need to override prepareForReuse in the cell. And remove it from tableView:indexPath:. So when you scroll the cell is going to be reused but the isBotton and isTop vars will be reseted.
override func prepareForReuse() {
self.isBottom = false
self.isTop = false
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("myCell", forIndexPath: indexPath) as! RunningTableViewCell
//.......
cell.isTop = false
if(indexPath.row == 0){
cell.isTop = true
cell.tag=100
}
cell.isBottom = false
if(indexPath.row == myArray.count-1){
cell.isBottom = true
cell.tag=200
}
return cell
}
and also get this like ...
class RunningTableViewCell: UITableViewCell {
//#IBOutlet ...
var isTop: Bool?
var isBottom: Bool?
override func awakeFromNib() {
super.awakeFromNib()
if (self.tag==100)
{
isTop=true
}
else if (self.tag==200) {
isBottom=true
}
else{
isTop=false
isBottom=false
}
print("result: \(self.isTop) \(self.isBottom)")
}
}
And also do using singleton methods...
You can resolve this issue by call custom method in your cell like,
inside UIViewController:
//.......
cell.isTop = false
if(indexPath.row == 0){
cell.isTop = true
}
cell.isBottom = false
if(indexPath.row == myArray.count-1){
cell.isBottom = true
}
cell.UpdateViews()
return cell
}
inside TableViewCell:
//#IBOutlet ...
var isTop: Bool?
var isBottom: Bool?
func updateViews() {
print("result: \(self.isTop) \(self.isBottom)")
}
Good luck!
Related
I set a UIButton on CustomTableViewCells.
I would like to switch the image of UIButton when selected, but the default image does not change after I select again.
class CustomCell: UITableViewCell {
#IBOutlet weak var myButton: UIButton!
override func awakeFromNib() {
super.awakeFromNib()
self.setup()
}
private func setup() {
self.myButton.setImage(UIImage(named: "checked"), for:.normal)
self.myButton.setImage(UIImage(named: "unchecked"), for:.highlighted)
}
You can use the property highlight and you can change this property when called didSelectItemAtIndexPath in the TableView
For Example:
func tableView(tableView: UITableView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
print("This is your Answer... \(indexPath.row)")
let newSelectedView = tableView.cellForItemAtIndexPath(indexPath) as! ChoiceCell
//important
newSelectedView.highlight.hidden = false
if self.selectedIndex != -1 && self.selectedIndex != indexPath.row {
let indexPathSelected = NSIndexPath(forRow: self.selectedIndex, inSection: 0)
let prevSelected = tableView.cellForItemAtIndexPath(indexPathSelected) as! ChoiceCell
//important
prevSelected.highlight.hidden = true
}
self.selectedIndex = indexPath.row
}
I use a custom cell to show the placeholder but scrolling the table repeats the placeholder
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell") as! AddTableViewCell
cell.textInfo.delegate = self
if textPlaceHolders![indexPath.row].containsString("Category") == true {
cell.selected = true
cell.textInfo.text = textPlaceHolders![indexPath.row]
cell.accessoryType = .DisclosureIndicator
} else {
cell.textInfo.placeholder = textPlaceHolders![indexPath.row]
}
return cell
}
I tried some solution like this the problem resolved but when user end edit the text disappear
class AddTableViewCell: UITableViewCell {
#IBOutlet weak var textInfo: UITextField!
override func prepareForReuse() {
textInfo.text= ""
}
}
In your case you assign text property for cell's textInfo outlet in one case and placeholder in another. Because of UITableView's reuse policy your textInfo contains placeholder/text even if you haven't specified it for concrete indexPath. So you need to clean it up for every indexPath if you don't want them. Like this:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell") as! AddTableViewCell
cell.textInfo.delegate = self
if textPlaceHolders![indexPath.row].containsString("Category") == true {
cell.selected = true
cell.textInfo.text = textPlaceHolders![indexPath.row]
cell.textInfo.placeholder = nil
cell.accessoryType = .DisclosureIndicator
} else {
cell.textInfo.placeholder = textPlaceHolders![indexPath.row]
cell.textInfo.text = nil
}
return cell
}
I'm trying to add a search bar to a simple table view consisting of 7 cells of names and small description for each name.
As in the image here:
I made a class in swift file called Business, that has two attributes: Name and Des.
Here's the code in the view controller:
class FirstViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var TableView: UITableView!
var B = [Business]() //candies
var filteredNames = [Business]()
let searchController = UISearchController(searchResultsController: nil)
func filterContentForSearchText(searchText: String, scope: String = "All") {
filteredNames = B.filter { Bu in
return Bu.Name.lowercaseString.containsString(searchText.lowercaseString)
}
TableView.reloadData()
}
override func viewDidLoad() {
super.viewDidLoad()
B = [
Business(Name:"Mariah", Des:"I'm Here to help"),
Business(Name:"Nada", Des:"Hi"),
Business(Name:"Atheer", Des:"Hello"),
Business(Name:"Lojian", Des:"I can Help you"),
Business(Name:"Nadya", Des:"Hayat"),
Business(Name:"Omnia", Des:"Yahoo"),
Business(Name:"Eman", Des:"I have amazing stuff"),
Business(Name:"Amani", Des:"Yess")
]
searchController.searchResultsUpdater = self
searchController.dimsBackgroundDuringPresentation = false
definesPresentationContext = true
TableView.tableHeaderView = searchController.searchBar
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if searchController.active && searchController.searchBar.text != "" {
return filteredNames.count
}
return B.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = self.TableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! CellTableViewCell
cell.NameLabel.text = B[indexPath.row].Name
cell.DescriptionLabel.text = B[indexPath.row].Des
let Bu: Business
if searchController.active && searchController.searchBar.text != "" {
Bu = filteredNames[indexPath.row]
} else {
Bu = B[indexPath.row]
}
cell.accessoryType = UITableViewCellAccessoryType.DisclosureIndicator
return cell
}
}
extension FirstViewController: UISearchResultsUpdating {
func updateSearchResultsForSearchController(searchController:
(UISearchController) {
filterContentForSearchText(searchController.searchBar.text!)
}
}
I followed this tutorial to do that:
https://www.raywenderlich.com/113772/uisearchcontroller-tutorial
I don't know whay when I tried to search in simulator the result is always the first cell: Mariah
What's wrong with the code?
You don't use the search result to populate the cells. Replace you cellForRowAtIndexPath with this:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = self.TableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! CellTableViewCell
let Bu: Business
if searchController.active && searchController.searchBar.text != "" {
Bu = filteredNames[indexPath.row]
} else {
Bu = B[indexPath.row]
}
cell.NameLabel.text = Bu.Name
cell.DescriptionLabel.text = Bu.Des
cell.accessoryType = UITableViewCellAccessoryType.DisclosureIndicator
return cell
}
And, don't use capital first letters for properties.
I want to hide/unhide an UIView in the UITableViewCell, but many times it unhides it for the wrong UITableViewCell. Any suggestions?
cellForRowAtIndexPath function
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("locationCell", forIndexPath: indexPath) as? UITableViewCell
var viewWithImage = cell?.viewWithTag(22) as UIView!
var cellHiddenGemView = viewWithImage?.viewWithTag(23) as UIView!
var locationObject : PFObject = locationObjects[indexPath.row] as! PFObject
var isSecret = locationObject["isSecret"] as! Bool
cellHiddenGemView?.hidden = true;
if isSecret == true
{
cellHiddenGemView?.hidden = false;
//this view is unhides for the wrong indexes also
}
return cell;
}
Its definitely not the best solution to use tags instead of subclassing UITableViewCell and use IBOutlets.
If you would subclass UITableViewCell you could override prepareForReuse()
and reset the hidden property to true
func prepareForReuse()
{
self.HiddenGemView?.hidden = true
}
Try defining else block too. Once this worked for me.
if isSecret == true
{
cellHiddenGemView?.hidden = false;
}
else
{
cellHiddenGemView?.hidden = true;
}
I have a tableView with drop down custom cells and I have some views in this cell that when the cell is selected they have to turn to visible, I tried some implementations but nothing is working. Can you help me?
My custom cell class:
class daysWorkPointsCell: UITableViewCell {
#IBOutlet var dayOfMonth: UILabel
#IBOutlet var hourAndMinute: UILabel
#IBOutlet var greenBar: UIView
#IBOutlet var scroll: UIScrollView
#IBOutlet var hourView: UIView
// greenBar,scroll and hourView are invisible and I need to turn to visible when selected
init(style: UITableViewCellStyle, reuseIdentifier: String!) {
super.init(style: UITableViewCellStyle.Value1, reuseIdentifier: reuseIdentifier)
}
}
My view Controller:
class DayViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet var daysWorkPointTable: UITableView
var selectedCellIndexPath: NSIndexPath?
let SelectedCellHeight: CGFloat = 150.0
let UnselectedCellHeight: CGFloat = 75.0
override func viewDidLoad() {
super.viewDidLoad()
var nipName = UINib(nibName: "daysWorkPointsCell", bundle: nil)
self.daysWorkPointTable.registerNib(nipName, forCellReuseIdentifier: "daysWorkCell")
}
func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!){
if let selectedCellIndexPath = selectedCellIndexPath {
if selectedCellIndexPath == indexPath {
self.selectedCellIndexPath = nil
} else {
self.selectedCellIndexPath = indexPath
}
} else {
selectedCellIndexPath = indexPath
}
tableView.beginUpdates()
tableView.endUpdates()
}
func tableView(tableView:UITableView!, heightForRowAtIndexPath indexPath:NSIndexPath)->CGFloat {
if let selectedCellIndexPath = selectedCellIndexPath {
if selectedCellIndexPath == indexPath {
return SelectedCellHeight
}
}
return UnselectedCellHeight
}
// here I tried to change the visibility but don't work
func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell!{
var cell = tableView.dequeueReusableCellWithIdentifier("daysWorkCell", forIndexPath: indexPath) as daysWorkPointsCell
if let selectedCellIndexPath = selectedCellIndexPath {
if selectedCellIndexPath == indexPath {
cell.greenBar.hidden = false
cell.scroll.hidden = false
cell.hourView.hidden = false
}else{
cell.greenBar.hidden = true
cell.scroll.hidden = true
cell.hourView.hidden = true
}
}
return cell
}
}
No need to selectedIndexPath Use instead below code it is much cleaner
override func tableView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!)
{
for cell in tableView.visibleCells(){
var hidden:Bool = cell.greenBar.hidden
cell.greenBar.hidden = !hidden
hidden = cell.scroll.hidden
cell.scroll.hidden = !hidden
hidden = cell.hourView.hidden
cell.hourView.hidden = !hidden
}
var cell = tableView.cellForRowAtIndexPath(indexPath)
var hidden:Bool = cell.greenBar.hidden
cell.greenBar.hidden = !hidden
hidden = cell.scroll.hidden
cell.scroll.hidden = !hidden
hidden = cell.hourView.hidden
cell.hourView.hidden = !hidden
}
I have used hidden variable here instead of cell.greenBar.hidden = !cell.greenBar.hidden because in swift ! is also used for unwrapping so it creates some problems when used with optionals