UITableViewCell not hiding UIView properly - ios

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;
}

Related

tableview data repeat when scrolling

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
}

didSelectRowAtIndexPath called after long press

I have a uitableview right below a uitextfield that populates similar strings in a uitableview cell.
The items get populated. However the didSelectRowAtIndexPath gets called after long press
My UITableView (is embedded in UIScrollView)
- didSelectRowAtIndexPath: only being called after long press on custom cell
My view hierarchy:
UIScrollView (outerscroll)
Some other views and buttons
UITexfield
UITableView (tableView)
My Code
class MyViewController: BaseViewController , UITextFieldDelegate , UITableViewDelegate , UITableViewDataSource , UIGestureRecognizerDelegate {
#IBOutlet weak var autocompleteTableView: UITableView!
var pastUrls = ["Men", "Women", "Cats", "Dogs", "Children","aaaaaaaaa","aaaaaaaaaaaaaaaaaaa","aaaaaaaaa","a","aa","aaa"]
var autocompleteUrls = [String]()
#IBOutlet weak var image_view_seacrh_ifsc: UIImageView!
#IBOutlet weak var scrollView: UIScrollView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.scrollView.panGestureRecognizer.delaysTouchesBegan = true
autocompleteTableView.delegate = self
autocompleteTableView.dataSource = self
autocompleteTableView.scrollEnabled = true
autocompleteTableView.alwaysBounceVertical = false
autocompleteTableView.allowsSelection = true
autocompleteTableView.allowsSelectionDuringEditing = true
autocompleteTableView.hidden = true
super.hideKeyboard()
super.showNavigationBarBackButton()
let gesture_search_ifsc = UITapGestureRecognizer(target: self, action: "action_Search_Ifsc:")
gesture_search_ifsc.delegate = self
gesture_search_ifsc.numberOfTapsRequired = 1
image_view_seacrh_ifsc.userInteractionEnabled = true
image_view_seacrh_ifsc.addGestureRecognizer(gesture_search_ifsc)
}
func searchAutocompleteEntriesWithSubstring(substring: String)
{
autocompleteUrls.removeAll(keepCapacity: false)
for curString in pastUrls
{
var myString:NSString! = curString as NSString
var substringRange :NSRange! = myString.rangeOfString(substring)
if (substringRange.location == 0)
{
autocompleteUrls.append(curString)
}
}
autocompleteTableView.reloadData()
//autocompleteTableView.hidden = false
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return autocompleteUrls.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell: AutoBankCell = tableView.dequeueReusableCellWithIdentifier("AutoBankCell") as! AutoBankCell
cell.label.text = self.autocompleteUrls[indexPath.row]
//cell.lbl.text = self.autocompleteUrls[indexPath.row]
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let selectedCell : UITableViewCell = tableView.cellForRowAtIndexPath(indexPath)!
self.bank_name.text = self.autocompleteUrls[indexPath.row]
self.autocompleteTableView.scrollEnabled = true
self.autocompleteTableView.hidden = true
}
}
My UItableView gets populated and works properly when not embedded in UIScrollView.
Try to add uiview in your scroll view and add every elements in that uiview like your tableView,textfield,views and buttons etc.
So, that view works as container view.
Make sure that you are setting proper constraints if you are using autolayout.
Second thing remove unnecessary gesture recognizer implicitly which is not required.
Tableview have scroll enable by default so not need to set it true again. (it's not affect your issue btw!!)
So remove unnecessary configuration and make proper setup and your issue will be solved i think.

TableView animation on selection

I got this code - I want to animate change in width of a UIView of custom table view cell - here is what I implemented in the CustomTableViewCell class:
var expanded: Bool = false
override func layoutSubviews() {
super.layoutSubviews()
if !expanded {
horizontalProgressView.hidden = true
} else {
horizontalProgressView.hidden = false
horizontalProgressView.frame.size.width = 100.0
}
}
Then in my viewController which has tableView and a delegate/datasource implemented I try:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let cell = tableView.cellForRowAtIndexPath(indexPath) as! CustomTableViewCell
cell.expanded = true
}
When I select the cell the the horizontalProgressView is visible (so the .hidden part is working) but the width is still the same I set in my storyboard. What am I missing?

Pass variable to custom UITableViewCell from UIViewController

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!

How to make UITableview with Textfield in swift?

I want to make a table view with textfields in each cell,
I have a custom class in a swift file:
import UIKit
public class TextInputTableViewCell: UITableViewCell{
#IBOutlet weak var textField: UITextField!
public func configure(#text: String?, placeholder: String) {
textField.text = text
textField.placeholder = placeholder
textField.accessibilityValue = text
textField.accessibilityLabel = placeholder
}
}
Then in my ViewController I have
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{
let cell = tableView.dequeueReusableCellWithIdentifier("TextInputCell") as! TextInputTableViewCell
cell.configure(text: "", placeholder: "Enter some text!")
text = cell.textField.text
return cell
}
That works well:
But when the user enters text in the textfield and press the button I want to store the strings of each textfield in an array.
I have tried with
text = cell.textField.text
println(text)
But it prints nothing like if it was empty
How can I make it work?
In your view controller become a UITextFieldDelegate
View Controller
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, UITextFieldDelegate {
var allCellsText = [String]()
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! CustomTableViewCell
cell.theField.delegate = self // theField is your IBOutlet UITextfield in your custom cell
cell.theField.text = "Test"
return cell
}
func textFieldDidEndEditing(textField: UITextField) {
allCellsText.append(textField.text!)
println(allCellsText)
}
}
This will always append the data from the textField to the allCellsText array.
this method is init the cell,u have not model to save this datas,so
text = cell.textfield.text
is nothing!
you can init var textString in viewcontroller,an inherit UITextFieldDelegate
optional func textFieldDidEndEditing(_ textField: UITextField)
{
textString = _textField.text
}
optional func textFieldShouldReturn(_ textField: UITextField) -> Bool{
return true
}
and cell.textField.text = textString
create a variable
var arrayTextField = [UITextField]()
after this in your func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{}
add
self.arrayTextField.append(textfield)
before returning cell, after this to display the values using
for textvalue in arrayTextField{
println(textvalue.text)
}
So here is a way to do it using the suggestion of having a textfield array. It uses the tag of the textfield to ensure it does not get added multiple times when you scroll.
// Assumes that you have a label and a textfield as a part of you tableViewCell
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as? BodyStatsTableViewCell else {
return UITableViewCell()
}
cell.rowLabel.text = bodyTableArray[indexPath.row].rowTitle
let tagValue = indexPath.row + 100
var newRow = true
for textvalue in arrayTextField{
if textvalue.tag == tagValue {
newRow = false
}
}
if newRow {
cell.rowTextField.tag = tagValue
self.arrayTextField.append(cell.rowTextField)
cell.rowTextField.text = bodyTableArray[indexPath.row].rowValue
}
return cell
}
// And then you cam get the values when you want to save with where tag - 100 will be the array index value to update
for textvalue in arrayTextField{
print(textvalue.text)
}

Resources