iOS UITableView is not selectable when it is scrolled - ios

I am facing this issue and I am not getting any clear answer. I have a UITableView which works fine when it loads for the first time but when it scrolls, it is not selectable, didSelectRowAtIndexPath never gets a call. Also I've button in my cell, it's not clickable either. But I can still scroll tableview. This is my code :
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell : ContactTableViewCell = tableView.dequeueReusableCell(withIdentifier: "ContactCell") as! ContactTableViewCell
cell.selectionStyle = .none
cell.backgroundColor = UIColor.clear
cell.delegate = self
let randomNumber = Int(arc4random_uniform(UInt32(colorsArray!.count)))
if(!shouldUseFilteredResults) {
cell.setFilteredContents(_with: addressBookArray![indexPath.row], theme: themeStyle!, randomColor: colorsArray![randomNumber])
}
else {
cell.setFilteredContents(_with: filteredAddressBook[indexPath.row], theme: themeStyle!, randomColor: colorsArray![randomNumber])
cell.contactNameLabel.attributedText = self.highlightSearchResult(resultString: cell.contactNameLabel.text!)
}
return cell
}
In cell :
public func setFilteredContents (_with contact : [String : Any], theme : Theme, randomColor : UIColor)
{
contactDictionary = contact;
contactNameLabel.text = String(describing: contact["FullName"]!)
self.setTheme(theme: theme, randomColor: randomColor)
if (contact["ImageDataString"] != nil)
{
let imageData = Data(base64Encoded: contact["ImageDataString"] as! String)
let image = UIImage(data: imageData!)
let imageView = UIImageView(frame: thumbnailView.bounds)
imageView.contentMode = .scaleAspectFill
imageView.layer.masksToBounds = true
imageView.layer.cornerRadius = CGFloat(imageView.height()/2)
imageView.image = image
thumbnailView.addSubview(imageView)
}
else {
self.setThumbnail(fullName: contactNameLabel.text!)
}
}
private func setThumbnail(fullName : String)
{
let vibrancy = UIVibrancyEffect(blurEffect: UIBlurEffect(style: .light))
let backgroundView = UIVisualEffectView(effect: vibrancy)
backgroundView.frame = thumbnailView.bounds
thumbnailView.addSubview(backgroundView)
let thumbNailLabel = UILabel(frame: thumbnailView.bounds)
thumbNailLabel.font = UIFont.systemFont(ofSize: 13)
thumbNailLabel.textColor = UIColor.white
thumbNailLabel.textAlignment = .center
var initialLettersString = String()
let wordsArray = fullName.components(separatedBy: NSCharacterSet.whitespaces)
for word in wordsArray
{
if(word != "")
{
initialLettersString.append(String(describing: word.characters.first!))
}
}
if(initialLettersString.characters.count == 1)
{
initialLettersString = String(initialLettersString[..<initialLettersString.index(initialLettersString.startIndex, offsetBy: 1)]).uppercased()
}
if(initialLettersString.characters.count > 1)
{
initialLettersString = String(initialLettersString[..<initialLettersString.index(initialLettersString.startIndex, offsetBy: 2)]).uppercased()
}
thumbNailLabel.text = initialLettersString as String
backgroundView.contentView.addSubview(thumbNailLabel)
}
private func setTheme(theme : Theme, randomColor : UIColor)
{
let isContactFavorite = contactDictionary?[Constants.TTCIsContactFavoriteKey] as? Bool
thumbnailView.backgroundColor = randomColor
if(theme == Theme.Light)
{
contactNameLabel.textColor = UIColor.black
lineView.backgroundColor = UIColor.lightGray
if(!isContactFavorite!)
{
favoritesButton.setImage(UIImage(named: "favorite_dark.png"), for: .normal)
}
else
{
favoritesButton.setImage(UIImage(named: "favorite.png"), for: .normal)
}
}
else if(theme == Theme.Dark)
{
contactNameLabel.textColor = UIColor.white
lineView.backgroundColor = UIColor.gray
if(!isContactFavorite!)
{
favoritesButton.setImage(UIImage(named: "favorite_white.png"), for: .normal)
}
else
{
favoritesButton.setImage(UIImage(named: "favorite.png"), for: .normal)
}
}
for view in thumbnailView.subviews
{
view.removeFromSuperview()
}
}
Custom Cell :
What could be the issue?

This may also because of overriding default touch events with UITapRecognizers in the View Hierarchy
Remove any tap recognizers set to to UITableview Parent View

Thanks everyone for help. Issue was with SwipeCellKit which I was using for CustomCell. Removing it solved it!

You are doing everything right.
Just check your button frame does lies inside your cell.
Some times your cell height is less and button is outside the bounds of cell.

Related

ProgressView progress in TableViewCell is altered when table view is scrolled

In my app I have to show multiple progress views in a single tableViewCell, the progress as per actual to goal and it showing correctly when cell is loaded for the first time as per image1
but after scrolling the table the cell is visible like image2.
The progress of the progress views is altered after scrolling the tableview. I have printed the progress values in cellForRowAt method and they are correct but the progress in progress view is being altered. I am setting the progressview progress in cellForRowAt method.
Can anybody help me to resolve this issue?
#Bhavin Kansagara here is my code in cellForRowAt method.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0 {
let cellIdentifier = "myIdentifier"
var cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier) as? MyTableViewCell
if cell == nil {
tableView.register(UINib.init(nibName: "MyTableViewCell", bundle: nil), forCellReuseIdentifier: cellIdentifier)
cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier) as? MyTableViewCell
}
let myDict = self.myArray[indexPath.row]
let goalDict = myDict["goal"]!
let actualDict = myDict["actual"]!
for label in cell!.actualValueLabels {
switch label.tag {
case 0:
label.text = String(actualDict["value1"]!)
case 1:
label.text = String(actualDict["value2"]!)
case 2:
label.text = String(actualDict["value3"]!)
case 3:
label.text = String(actualDict["value4"]!)
case 4:
label.text = String(actualDict["value5"]!)
case 5:
label.text = String(actualDict["total"]!)
default:
break
}
}
for label in cell!.goalValueLabels {
switch label.tag {
case 0:
label.text = String(goalDict["value1"]!)
case 1:
label.text = String(goalDict["value2"]!)
case 2:
label.text = String(goalDict["value3"]!)
case 3:
label.text = String(goalDict["value4"]!)
case 4:
label.text = String(goalDict["value5"]!)
case 5:
label.text = String(goalDict["total"]!)
default:
break
}
}
let greenColor = UIColor(red: 146/255, green: 209/255, blue: 78/255, alpha: 1)
let yellowColor = UIColor(red: 1, green: 122/255, blue: 0, alpha: 1)
let value1Goal = goalDict["value1"]!
let value1Actual = actualDict["value1"]!
cell?.value1ProgressView.progressTintColor = value1Actual >= value1Goal ? greenColor : yellowColor
if value1Goal == 0 {
DispatchQueue.main.async {
cell?.value1ProgressView.setProgress(Float(value1Actual), animated: true)
}
} else {
DispatchQueue.main.async {
cell?.value1ProgressView.setProgress(Float(value1Actual)/Float(value1Goal), animated: true)
}
}
let value2Goal = goalDict["value2"]!
let value2Actual = actualDict["value2"]!
cell?.value2ProgressView.progressTintColor = value2Actual >= value2Goal ? greenColor : yellowColor
if value2Goal == 0 {
DispatchQueue.main.async {
cell?.value2ProgressView.setProgress(Float(value2Actual), animated: true)
}
} else {
DispatchQueue.main.async {
cell?.value2ProgressView.setProgress(Float(value2Actual)/Float(value2Goal), animated: true)
}
}
let value3Goal = goalDict["value3"]!
let value3Actual = actualDict["value3"]!
cell?.value3ProgressView.progressTintColor = value3Actual >= value3Goal ? greenColor : yellowColor
if value3Goal == 0 {
DispatchQueue.main.async {
cell?.value3ProgressView.setProgress(Float(value3Actual), animated: true)
}
} else {
DispatchQueue.main.async {
cell?.value3ProgressView.setProgress(Float(value3Actual)/Float(value3Goal), animated: true)
}
}
let value4Goal = goalDict["value4"]!
let value4Actual = actualDict["value4"]!
cell?.value4ProgressView.progressTintColor = value4Actual >= value4Goal ? greenColor : yellowColor
if value4Goal == 0 {
DispatchQueue.main.async {
cell?.value4ProgressView.setProgress(Float(value4Actual), animated: true)
}
} else {
DispatchQueue.main.async {
cell?.value4ProgressView.setProgress(Float(value4Actual)/Float(value4Goal), animated: true)
}
}
let value5Goal = goalDict["value5"]!
let value5Actual = actualDict["value5"]!
cell?.value5ProgressView.progressTintColor = value5Actual >= value5Goal ? greenColor : yellowColor
if value5Goal == 0 {
DispatchQueue.main.async {
cell?.value5ProgressView.setProgress(Float(value5Actual), animated: true)
}
} else {
DispatchQueue.main.async {
cell?.value5ProgressView.setProgress(Float(value5Actual)/Float(value5Goal), animated: true)
}
}
let totalGoal = goalDict["total"] as! Int
let totalActual = actualDict["count"]!
cell?.totalProgressView.progressTintColor = totalActual >= totalGoal ? greenColor : yellowColor
if totalGoal == 0 {
DispatchQueue.main.async {
cell?.totalProgressView.setProgress(Float(totalActual), animated: true)
}
} else {
DispatchQueue.main.async {
cell?.totalProgressView.setProgress(Float(totalActual)/Float(totalGoal), animated: true)
}
}
return cell!
}
else {
//another cells are used in other sections
}
}
here myArray = [[String: [String: Int]]]
Thanks in advance.
There is one way to handle this situations, You should try setting the different identifier for the cell's but that will affect your performance. after setting this approach, you should check for the performance of scrolling on your device.
let cellIdentifier = "myIdentifier_\(indexPath.section)_\(indexPath.row)"
var cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier) as? MyTableViewCell
if cell == nil {
tableView.register(UINib.init(nibName: "MyTableViewCell", bundle: nil), forCellReuseIdentifier: cellIdentifier)
cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier) as? MyTableViewCell
}
This is not the best approach, but can help avoid the repeating process issue.
Try and share results.

how to prevent cell reuse of uicollectionview

I use UICollectionView and refer to this link implement scroll table view Fixed single column and row like below image.
but when I want to add shadow property, it display messy.
I think the reason is that I reuse cell when render visual view, but I don't know how to fix it :(
provide my code below, thanks for your time!
import Foundation
import SwiftyJSON
#objc(RNCollection)
class RNCollection : UICollectionView, UICollectionViewDataSource, UICollectionViewDelegate {
var contentCellIdentifier = "CellIdentifier"
var collectionView: UICollectionView!
static var dataSource = []
static var sections = 0
static var rows = 0
override init(frame: CGRect, collectionViewLayout layout: UICollectionViewLayout) {
super.init(frame: CGRectZero, collectionViewLayout: RNCollectionLayout())
self.registerClass(RNCollectionCell.self, forCellWithReuseIdentifier: contentCellIdentifier)
self.directionalLockEnabled = false
self.backgroundColor = UIColor.whiteColor()
self.delegate = self
self.dataSource = self
self.frame = frame
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setConfig(config: String!) {
var json: JSON = nil;
if let data = config.dataUsingEncoding(NSUTF8StringEncoding) {
json = JSON(data: data);
};
RNCollection.dataSource = json["dataSource"].arrayObject!
RNCollection.sections = json["sections"].intValue
RNCollection.rows = json["rows"].intValue
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let contentCell: RNCollectionCell = collectionView.dequeueReusableCellWithReuseIdentifier(contentCellIdentifier, forIndexPath: indexPath) as! RNCollectionCell
contentCell.textLabel.textColor = UIColor.blackColor()
if indexPath.section == 0 {
contentCell.backgroundColor = UIColor(red: 232/255.0, green: 232/255.0, blue: 232/255.0, alpha: 1.0)
if indexPath.row == 0 {
contentCell.textLabel.font = UIFont.systemFontOfSize(16)
contentCell.textLabel.text = (RNCollection.dataSource[0] as! NSArray)[0] as? String
} else {
contentCell.textLabel.font = UIFont.systemFontOfSize(14)
contentCell.textLabel.text = (RNCollection.dataSource[0] as! NSArray)[indexPath.row] as? String
}
} else {
contentCell.textLabel.font = UIFont.systemFontOfSize(12)
contentCell.backgroundColor = UIColor.whiteColor()
if(indexPath.section % 2 == 0) {
contentCell.backgroundColor = UIColor(red: 234/255.0, green: 234/255.0, blue: 236/255.0, alpha: 1.0)
}
if indexPath.row == 0 {
contentCell.textLabel.text = (RNCollection.dataSource[indexPath.section] as! NSArray)[0] as? String
contentCell.layer.shadowOffset = CGSize(width: 3, height: 3)
contentCell.layer.shadowOpacity = 0.7
contentCell.layer.shadowRadius = 2
} else {
contentCell.textLabel.text = (RNCollection.dataSource[indexPath.section] as! NSArray)[indexPath.row] as? String
}
}
return contentCell
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return RNCollection.rows
}
// MARK - UICollectionViewDataSource
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return RNCollection.sections
}
}
You are specifying your customizations for a certain section/row and in your else condition you just set the text. You should specify your required/default customization in your else condition. Consider this part of your code
if indexPath.row == 0 {
contentCell.textLabel.text = (RNCollection.dataSource[indexPath.section] as! NSArray)[0] as? String
contentCell.layer.shadowOffset = CGSize(width: 3, height: 3)
contentCell.layer.shadowOpacity = 0.7
contentCell.layer.shadowRadius = 2
} else {
contentCell.textLabel.text = (RNCollection.dataSource[indexPath.section] as! NSArray)[indexPath.row] as? String
}
You have specified your shadowOffset,shadowOpacity and shadowRadius in your if condition, but you ignored them in your else condition. If you specify the appearance in the else condition you won't have the problem you are facing now. It should look something like this
if indexPath.row == 0 {
contentCell.textLabel.text = (RNCollection.dataSource[indexPath.section] as! NSArray)[0] as? String
contentCell.layer.shadowOffset = CGSize(width: 3, height: 3)
contentCell.layer.shadowOpacity = 0.7
contentCell.layer.shadowRadius = 2
} else {
contentCell.textLabel.text = (RNCollection.dataSource[indexPath.section] as! NSArray)[indexPath.row] as? String
contentCell.layer.shadowOffset = 0
contentCell.layer.shadowOpacity = 0
contentCell.layer.shadowRadius = 0
}
If you reset everything properly in all your condition checks, this problem won't occur.
You set up shadow when your row is equal to 0:
if indexPath.row == 0 {...}
but if the row is not equal to zero collection view can reuse the cell when the shadow was already set. The solution is reset the shadow when row is not 0, in your code you can do something like this (see todo):
if indexPath.row == 0 { // Set up shadow here
contentCell.textLabel.text = (RNCollection.dataSource[indexPath.section] as! NSArray)[0] as? String
contentCell.layer.shadowOffset = CGSize(width: 3, height: 3)
contentCell.layer.shadowOpacity = 0.7
contentCell.layer.shadowRadius = 2
} else {
contentCell.textLabel.text = (RNCollection.dataSource[indexPath.section] as! NSArray)[indexPath.row] as? String
//TODO: Remove the shadow here
}
If you wanna save the cell setting everytime when your cell appears,you should set every possible condition of the method "func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell".Do not prevent the reuse of collectionView only if your data or items is few.
In Objective-C, but in Swift, the logic should be the same and not that hard to translate.
In RNCollectionCell.
//These enums may have a better nam, I agree
typedef enum : NSUInteger {
RNCollectionCellStyleColumnTitle,
RNCollectionCellStyleColumnValue,
RNCollectionCellStyleRowTitle,
RNCollectionCellStyleUpperLeftCorner,
} RNCollectionCellStyle;
-(void)titleIt:(NSString *)title forStyle:(RNCollectionCellStyle)style forSection:(NSUInteger)section
{
self.textLabel.textColor = [UIColor blackColor]; //Since it's always the same could be done elsewhere once for all.
//Note I didn't check completely if the case were good, and I didn't add the background color logic, but it should be done here too.
switch (style)
{
case RNCollectionCellStyleColumnTitle:
{
self.textLabel.font = [UIFont systemFontOfSize:12];
self.layer.shadowOffset = CGSizeMake(3, 3);
self.layer.shadowOpacity = 0.7;
self.layer.shadowRadius = 2;
}
break;
case RNCollectionCellStyleColumnValue:
{
self.textLabel.font = [UIFont systemFontOfSize:12];
self.layer.shadowOffset = CGSizeZero;
self.layer.shadowOpacity = 0;
self.layer.shadowRadius = 0;
}
break;
case RNCollectionCellStyleRowTitle:
{
self.textLabel.font = [UIFont systemFontOfSize:14];
self.layer.shadowOffset = CGSizeZero;
self.layer.shadowOpacity = 0;
self.layer.shadowRadius = 0;
}
break;
case RNCollectionCellStyleUpperLeftCorner:
{
self.textLabel.font = [UIFont systemFontOfSize:16];
self.layer.shadowOffset = CGSizeZero;
self.layer.shadowOpacity = 0;
self.layer.shadowRadius = 0;
}
break;
default:
break;
}
self.textLabel.text = title;
}
-(void)prepareForReuse
{
[super prepareForReuse];
self.layer.shadowOffset = CGSizeZero;
self.layer.shadowOpacity = 0;
self.layer.shadowRadius = 0;
}
In RNCollection:
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(nonnull NSIndexPath *)indexPath
{
RNCollectionCell *contentCell = [collectionView dequeueReusableCellWithReuseIdentifier: contentCellIdentifier forIndexPath:indexPath];
//Here check what style you need to do
//Also, you seems to always do dataSource[indexPath.section][indexPath.row], you just use the "if test values".
[contentCell titleIt:dataSource[indexPath.section][indexPath.row]
forStyle:RNCollectionCellStyleColumnTitle
forSection:[indexPath section]];
return contentCell;
}
As said, I didn't check if all the cases were correct according to your needs.
But, you don't "prevent reuse of cell", it's optimized.
You need to "reset" values before reused or when you set the values. In theory the thing done in prepareForReuse should be enough and you shouldn't have to "reset" the layer effect in the switch, but I honestly didn't check it.

Adding line to Customview each time when i am scroll tableView in Swift

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! StackingCell
let data = stack[indexPath.row]
cell.stackDeatils = data
cell.floorNumber_Label.text = data.floorNo
let floorDetails = data.floorDetails!
if floorDetails == "NA"{
cell.floor_View.backgroundColor = UIColor.lightGrayColor()
}
else {
for items in floorDetails
{
let floorArr = items.1
cell.floor_View.backgroundColor = UIColor.orangeColor()
//Number of Units passing value to cell
cell.secitons = floorArr.count
for units in floorArr {
let unit = units.1
let compName = unit["companyName"].string!
if compName == "Vacant" {
cell.floor_View.backgroundColor = UIColor(red: 94/255, green: 198/255, blue: 162/255, alpha: 1.0)
}
}
}
}
}
let shadowPath = UIBezierPath(rect: cell.floor_View.bounds)
cell.floor_View.layer.masksToBounds = false
cell.floor_View.layer.shadowColor = UIColor.blackColor().CGColor
cell.floor_View.layer.shadowOffset = CGSize(width: 1, height: 0.5)
cell.floor_View.layer.shadowOpacity = 0.2
cell.floor_View.layer.shadowPath = shadowPath.CGPath
return cell
}
CustomTableCell method for adding vertical line to TableViewCell
var stackDeatils:StackingModel!{
didSet
{
dispatch_async(dispatch_get_main_queue()) {
self.updateData()
}
}
}
func updateData(){
let unit = self.stackDeatils.isUnitsDrawn
if unit == true {
self.stackDeatils.isUnitsDrawn = false
let stack_width = self.floor_View.frame.width
let stack_height = self.floor_View.frame.height
xCor = stack_width/CGFloat(self.secitons)
var x = xCor
for var i = 1;i < self.secitons; i++ {
let line = UIView(frame: CGRectMake(x, 0, 2,stack_height))
line.backgroundColor = UIColor.whiteColor()
//print(xCor)
self.floor_View.addSubview(line)
x += xCor
}
}
else {
print(self.stackDeatils.isUnitsDrawn)
}
}

Jerking motion after table view is reloaded

I'm getting a weird jerking motion whenever I reload my row and scroll up. It's fine if it's scrolling down, but scrolling back up is causing a horrible jerking effect, rendering the app useless.
I've attached the code for not only the cellforrowatindex path, but the buttons as well.
cell for row:
override func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!, object: PFObject!) -> PFTableViewCell! {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! TableViewCell
cell.nopebutton.tag = indexPath.row
cell.nicebutton.tag = indexPath.row
cell.killText.text = object.valueForKey("text") as! String
cell.layoutMargins = UIEdgeInsetsZero
cell.killText.numberOfLines = 0
let score = object.valueForKey("count") as! Int
cell.count.text = "\(score)"
if cell.count.text == "\(0)"
{
cell.count.textColor = UIColor.grayColor()
}
if cell.count.text > "\(0)"
{
cell.count.textColor = UIColor(red: 42.0/255, green: 204.0/255, blue: 113.0/255, alpha: 1)
}
if cell.count.text < "\(0)"
{
cell.count.textColor = UIColor(red: 231.0/255, green: 76.0/255, blue: 50.0/255, alpha: 1)
}
if cell.count.text == "\(50)"
{
cell.count.textColor = UIColor(red: 249.0/255, green: 191.0/255, blue: 59.0/255, alpha: 1)
}
if let dict : NSDictionary = NSUserDefaults.standardUserDefaults().objectForKey("userNiceNopeDictionary") as? NSDictionary {
cell.nicebutton.enabled = true
cell.nopebutton.enabled = true
if let nice = dict[object.objectId] as? Bool{
if nice {
cell.nicebutton.enabled = false
}
else {
cell.nopebutton.enabled = false
}
}
}
let dateUpdated = object.createdAt as NSDate
let dateFormat = NSDateFormatter()
dateFormat.dateFormat = "h:mm a"
cell.time.text = (NSString(format: "%#", dateFormat.stringFromDate(dateUpdated)) as String) as String
let replycnt = object.objectForKey("replies") as! Int
if cell.count.text == "\(-10)"
{
object.deleteInBackground()
}
return cell
}
buttons
#IBAction func topButton(sender: AnyObject) {
var button = sender as! UIButton
// var view = button.superview
//
// var otherButton = view?.viewWithTag(102) as! UIButton
// var label = button.superview!.viewWithTag(110) as! UILabel
// otherButton.enabled = true
// button.enabled = false
var rowNumber = button.tag
var mutableDict = NSMutableDictionary()
if let dict = NSUserDefaults.standardUserDefaults().objectForKey("userNiceNopeDictionary") {
mutableDict = dict.mutableCopy() as! NSMutableDictionary
}
let obj = self.objects[rowNumber] as! PFObject
mutableDict.setValue(true, forKey: obj.objectId)
NSUserDefaults.standardUserDefaults().setObject(mutableDict, forKey: "userNiceNopeDictionary")
NSUserDefaults.standardUserDefaults().synchronize()
let hitPoint = sender.convertPoint(CGPointZero, toView: self.tableView)
let hitIndex = self.tableView.indexPathForRowAtPoint(hitPoint)
let object = objectAtIndexPath(hitIndex)
object.incrementKey("count")
//label.text = object.objectForKey("count") as! String
// self.tableView.reloadData()
object.save()
self.tableView.reloadRowsAtIndexPaths([hitIndex!], withRowAnimation: UITableViewRowAnimation.None)
}
#IBAction func bottomButton(sender: AnyObject) {
var button = sender as! UIButton
var rowNumber = button.tag
var mutableDict = NSMutableDictionary()
if let dict = NSUserDefaults.standardUserDefaults().objectForKey("userNiceNopeDictionary") {
mutableDict = dict.mutableCopy() as! NSMutableDictionary
}
let obj = self.objects[rowNumber] as! PFObject
mutableDict.setValue(false, forKey: obj.objectId)
NSUserDefaults.standardUserDefaults().setObject(mutableDict, forKey: "userNiceNopeDictionary")
NSUserDefaults.standardUserDefaults().synchronize()
let hitPoint = sender.convertPoint(CGPointZero, toView: self.tableView)
let hitIndex = self.tableView.indexPathForRowAtPoint(hitPoint)
let object = objectAtIndexPath(hitIndex)
object.incrementKey("count", byAmount: -1)
self.tableView.reloadRowsAtIndexPaths([hitIndex!], withRowAnimation: UITableViewRowAnimation.None)
object.save()
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if(segue.identifier == "killDetail"){
let indexPath = self.tableView.indexPathForSelectedRow()
let obj = self.objects[indexPath!.row] as! PFObject
let detailVC = segue.destinationViewController as! DetailViewController
detailVC.kill = obj
}
}
}
I'm under the impression that there's an issue in my heights so I've included that code as well.
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.separatorInset = UIEdgeInsetsZero
self.tableView.separatorInset = UIEdgeInsetsMake(0, 0, 0, 0)
self.tableView.separatorColor = UIColor(red: 236.0/255, green: 240.0/255, blue: 241.0/255, alpha: 1)
navigationController?.tabBarController?.tabBar.hidden = true
tabBarController?.tabBar.hidden = true
self.tableView.estimatedRowHeight = 60
self.tableView.rowHeight = UITableViewAutomaticDimension
locationManager.desiredAccuracy = 1000
locationManager.delegate = self
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
}
I can't for the life of me figure out what's going on causing this jerk. Like I said I think it might have to do with the automaticdimension in the row height, but when I change that the issue is still apparent.
Don't read that dictionary from user defaults every time you dequeue a cell. Do it once, outside of tableView(cellForRowAtIndexPath:. Do it in viewDidLoad or something. Picking out an element from the dictionary once it's in memory is fine though... You just don't want to read from disk (or flash, I guess) every time a cell is dequeued.
If the dictionary is being changed, for any reason, in other places and you want to maintain a consistent state, read the dictionary in once and just pass it around between controllers/view controllers (through, e.g. prepareForSegue) and write it to user defaults when it's changed.
The date formatter is probably not that big or complex of an object to make, but you only need to make one once, and then can reuse it, so I suggest you only create one once too.
edit: If you have a problem just scrolling up, it could be that the estimated row height doesn't match the actual row height. Try removing the estimated height.

Issue with "if" statement: "trying to style message.content differently according to message.sender

I have created a class of message including, content and sender. I successfully store the desired data in Parse and I am querying them. So far, no problem. Then, I attempt to filter the messages according to the sender, or the receiver, in order to display them in different manners on my tableView.
For instance, let's say that is sender is currentUser, the text is blue, otherwise it is green.
If currentUser sends a message, all the text becomes blue, even the one sent by the other user; and vice versa.
class Message {
var sender = ""
var message = ""
var time = NSDate()
init(sender: String, message: String, time: NSDate)
{
self.sender = sender
self.message = message
self.time = time
}
}
var message1: Message = Message(sender: "", message: "", time: NSDate())
func styleTextView()
{
if message1.sender == PFUser.currentUser()?.username {
self.textView.textColor = UIColor.blueColor()
} else {
self.textView.textColor = UIColor.greenColor()
}
}
func addMessageToTextView(message1: Message)
{
textView.text = message1.message
self.styleTextView()
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
var cell: messageCell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! messageCell
let message = self.array[indexPath.row]
cell.setupWithMessage(message)
return cell
}
I have other codes on my viewController, however I believe they are irrelevant to this matter; if needed, I can provide them.
Any idea why I cannot have the textViews in different style according to the sender?
They are all either blue, either green.
Below is the code for the full set up of the tableViewCell:
class messageCell: UITableViewCell {
private let padding: CGFloat = 10.0
var array1 = [Message]()
private func styleTextView()
{
let halfTextViewWidth = CGRectGetWidth(textView.bounds) / 2.0
let targetX = halfTextViewWidth + padding
let halfTextViewHeight = CGRectGetHeight(textView.bounds) / 2.0
self.textView.font = UIFont.systemFontOfSize(12.0)
if PFUser.currentUser()?.username == message1.sender && textView.text == message1.message {
self.textView.backgroundColor = UIColor.blueColor()
self.textView.layer.borderColor = UIColor.blueColor().CGColor
self.textView.textColor = UIColor.whiteColor()
textView.center.x = targetX
textView.center.y = halfTextViewHeight
} else {
self.textView.backgroundColor = UIColor.orangeColor()
self.textView.layer.borderColor = UIColor.orangeColor().CGColor
self.textView.textColor = UIColor.whiteColor()
self.textView.center.x = CGRectGetWidth(self.bounds) - targetX
self.textView.center.y = halfTextViewHeight
}
}
private lazy var textView: MessageBubbleTextView = {
let textView = MessageBubbleTextView(frame: CGRectZero, textContainer: nil)
self.contentView.addSubview(textView)
return textView
}()
class MessageBubbleTextView: UITextView
{
override init(frame: CGRect = CGRectZero, textContainer: NSTextContainer? = nil)
{
super.init(frame: frame, textContainer: textContainer)
self.scrollEnabled = false
self.editable = false
self.textContainerInset = UIEdgeInsets(top: 7, left: 7, bottom: 7, right: 7)
self.layer.cornerRadius = 15
self.layer.borderWidth = 2.0
}
required init(coder aDecoder: NSCoder)
{
fatalError("init(coder:) has not been implemented")
}
}
private let minimumHeight: CGFloat = 30.0
private var size = CGSizeZero
private var maxSize: CGSize {
get {
let maxWidth = CGRectGetWidth(self.bounds)
let maxHeight = CGFloat.max
return CGSize(width: maxWidth, height: maxHeight)
}
}
func setupWithMessage(message: Message) -> CGSize
{
textView.text = message.message
size = textView.sizeThatFits(maxSize)
if size.height < minimumHeight {
size.height = minimumHeight
}
textView.bounds.size = size
self.styleTextView()
return size
}
}
One possible error can be in this line:
if message1.sender == PFUser.currentUser()?.username
where you are comparing different types since message1 is a String whereas PFUser.currentUser()?.username is an optional String. The right way to compare them is:
if let username = PFUser.currentUser()?.username where username == message1.sender {
self.textView.textColor = UIColor.blueColor()
} else {
self.textView.textColor = UIColor.greenColor()
}
This is because you are changing the text color of the entire UITextView with your code. See the following post for a start in the right direction: Is it possible to change the color of a single word in UITextView and UITextField

Resources