Repeated cells while scrolling uitableview
you seem to have created a separate class for UITableViewCell. The problem with your code is that you are not resetting the labels when reuse happens.
Oveeride prepareForReuse method in your custom UITableviewCell class and reset your interfaces there. That should fix the issue.
Values Repeat When Scrolling in TableView
From the code you have posted, it is clear that you are not setting the enabled
property of the UIButton
with respect to the DataSource
(The array and its objects you are using to load the tableview, that is the elements in objects
array). Whatever objects that array contains, add a property to determine if the condition for the button should be true or false, and then in cellForRowAtIndexPath
set the enabled property of the button according to that. When the button is clicked, add a callback to the ViewController(using a delegate) and set the property there.
Sample Code
In custom cell class:
protocol CellButtonDelegate
{
func buttonClicked(cell : PFTableViewCell)
}
public var delegate : CellButtonDelegate?
public var buttonEnabled : Bool?
{
get
{
return heartOutlet.enabled
}
set
{
heartOutlet.enabled = newValue
}
}
@IBAction func heartButton(sender: AnyObject) {
if(parseObject != nil) {
if var votes:Int? = parseObject!.objectForKey("votes") as? Int {
votes!++
parseObject!.setObject(votes!, forKey: "votes")
parseObject!.saveInBackground()
votesLabel?.text = "\(votes!)"
}
}
delegate?.buttonClicked(self)
}
In ViewController:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath, object: PFObject?) -> PFTableViewCell? {
var cell: FeedTableViewCell? = tableView.dequeueReusableCellWithIdentifier(cellIdentifier) as? FeedTableViewCell
if(cell == nil) {
cell = NSBundle.mainBundle().loadNibNamed("FeedTableViewCell", owner: self, options: nil)[0] as? FeedTableViewCell
}
if let pfObject = object {
//I took out the irrelevant methods. I can add them if that makes a difference...
var votes:Int? = pfObject["votes"] as? Int
if votes == nil {
votes = 0
}
cell?.buttonEnabled = objects[indexPath.row].isEnabled //The new property you need to add. true by default
cell?.delegate = self //Make sure you implement the delgate
cell?.votesLabel?.text = "\(votes!)"
return cell?
}
func buttonClicked(cell : PFTableViewCell)
{
//Here, get the indexPath using the cell and assign the new property in the array.
}
Please note that the above code is rough. Just get the idea from the code and implement it as per your requirement.
Duplication in values of tableView when Scrolling Swift
From the Apple Docs:
At runtime, the table view stores cell objects in an internal queue. When the table view asks the data source to configure a cell object for display, the data source can access the queued object by sending a dequeueReusableCellWithIdentifier: message to the table view, passing in a reuse identifier. The data source sets the content of the cell and any special properties before returning it. This reuse of cell objects is a performance enhancement because it eliminates the overhead of cell creation.
So what you're doing when reusing cells from the queue is retrieving cells you have already created and configured. Changes made to the created Cells will be also applied to the reused cells which are displayed when scrolling as soon as the reused cells aren't visible anymore. This means you have to re-assign any values you want to override which are custom to the unique cell you are displaying, which also applies if there is no content/an empty string you want to display. Otherwise you will get random results as you have been experiencing.
let cell = tableView.dequeueReusableCellWithIdentifier("TimingsCell", forIndexPath: indexPath) as! timingCell
let timings = self.Details!.timingsArray
let dayTime = timings[indexPath.row]
cell.dayLabel.text = dayTime.dayName
if dayTime.open != nil && dayTime.close != nil {
cell.timeLabel.text = "\(convertTimeFormat(dayTime.open!)) - \(convertTimeFormat(dayTime.close!))"
}
else{
//change label to empty string when reusing
cell.timeLabel.text = "";
}
return cell
How to make a loop appending 20 -20 rows in a tableview when scrolling?
I'll elaborate the pagination
in tableView
using an example. You can go through it and then implement it in your project.
1. Let's assume you've a String array that contains around 500 elements.
var allUsers = [String](repeating: "User", count: 500)
2. Create another String array
that initially contains first 10 elements from allUsers
array
.
var dataSource = [String]()
override func viewDidLoad() {
super.viewDidLoad()
self.addElements() //explained next..
}
The dataSource array
will act as the actual dataSource
for the tableView
.
3. Let's maintain an offset
that'll keep track of the index
from which we need to add next 10 elements, i.e.
var nextOffset = 0
func addElements() {
let newOffset = nextOffset+10
for i in nextOffset..<newOffset {
dataSource.append(allUsers[i])
}
nextOffset = newOffset
}
addElements()
method simply add next 10 elements starting from the nextOffset
.
4. The UITableViewDataSource
methods look like,
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataSource.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = "\(dataSource[indexPath.row]) : \(indexPath.row)"
return cell
}
5. Now implement UITableViewDelegate
method - tableView(_:willDisplay:forRowAt:)
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
let currentCount = self.dataSource.count
if currentCount < 500 && indexPath.row == (currentCount-1) { //last row
self.addData()
self.setUpLoaderView(toShow: true)
} else {
self.setUpLoaderView(toShow: false)
}
}
In the above methods, I've checked if the cell
is being displayed for the last row
. If yes, then we add more data to it using addData()
method and show a loaderView
at bottom using setUpLoaderView(toShow:)
method.
6. Here is the definition of both the methods,
func addData() {
DispatchQueue.main.asyncAfter(deadline: .now() + 10) {
self.addElements()
self.tableView.reloadData()
}
}
func setUpLoaderView(toShow: Bool) {
if toShow {
self.tableView.tableFooterView?.isHidden = false
self.tableView.tableFooterView = self.loaderMoreView
} else {
self.tableView.tableFooterView = UIView()
}
}
In addData()
I've added a delay
of 10 seconds
as per your requirement. So the loader
will be visible for 10 seconds
before the tableView
is updated with new data.
7. loaderMoreView
is simply a UIActivityIndicatorView
that is set as the tableFooterView
, like:
private lazy var loaderMoreView: UIView = {
let loaderView = UIActivityIndicatorView(style: .whiteLarge)
loaderView.color = UIColor.gray
loaderView.startAnimating()
return loaderView
}()
images repeating cells when scrolled in tableview
AlamofireImage handles this very well. https://github.com/Alamofire/AlamofireImage
import AlamofireImage
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! DataTableViewCell
cell.selectionStyle = .none
let kid = kidsdata[indexPath.row] as KidDetails
cell.NameLabel.text = kid.name
cell.ClassNameLabel.text = kid.standard
// assuming cell.ProfileImage is a UIImageView
cell.ProfileImage.image = nil
let frame = CGSize(width: 50, height: 50)
let filter = AspectScaledToFillSizeWithRoundedCornersFilter(size: frame, radius: 5.0)
cell.ProfileImage.af_setImage(withURL: urlToImage, placeholderImage: nil, filter: filter,
imageTransition: .crossDissolve(0.3), runImageTransitionIfCached: false)
return cell
}
Data repeat in UITableView when scrolling
use cell Identifier different
For example like bellow...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *CellIdentifier = [NSString stringWithFormat:@"%d,%d",indexPath.section,indexPath.row];
UITableViewCell *cell = [_tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
/// write your code here..
}
}
OR set nil
like bellow..
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//static NSString *CellIdentifier = @"CellIdentifier";
UITableViewCell *cell = [_tableView dequeueReusableCellWithIdentifier:nil];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil] autorelease];
/// write your code here..
}
}
Swift tableView checkmark repeating on scroll
First make a class/struct of Workout with a flag
struct Workout {
let name: String
let isComplete: Bool
}
Make a sample Data Model
var workouts = [
Workout(name: "Squats", isComplete: false),
Workout(name: "Burpees", isComplete: false),
Workout(name: "Crunches", isComplete: true),
Workout(name: "Push Ups", isComplete: false),
Workout(name: "Jumping Jacks", isComplete: true),
Workout(name: "High Knees", isComplete: false),
Workout(name: "Lunges", isComplete: false),
Workout(name: "Plank", isComplete: false),
Workout(name: "Sechigh Knees", isComplete: false),
Workout(name: "Tricep Dips", isComplete: false),
Workout(name: "Mountain Climbers", isComplete: true),
Workout(name: "Wall Sit", isComplete: true),
Workout(name: "Squats 2", isComplete: false),
Workout(name: "Burpees 2", isComplete: false),
Workout(name: "Crunches 2", isComplete: true),
Workout(name: "Push Ups 2", isComplete: false),
Workout(name: "Jumping Jacks 2", isComplete: false),
Workout(name: "High Knees 2", isComplete: false),
Workout(name: "Lunges 2", isComplete: false),
Workout(name: "Plank 2", isComplete: false),
Workout(name: "Sechigh Knees 2", isComplete: true),
Workout(name: "Tricep Dips 2", isComplete: false),
Workout(name: "Mountain Climbers 2", isComplete: false),
Workout(name: "Wall Sit 2", isComplete: false),
]
Make a custom UITableViewCell with a Workout type variable
class CustomCell: UITableViewCell {
var workout: Workout? {
didSet {
guard let workout = workout else { return }
self.textLabel?.text = workout.name
if workout.isComplete {
self.accessoryType = .checkmark
}
else {
self.accessoryType = .none
}
}
}
}
Then in tableView:cellForRowAtIndexPath:
method pass the variable
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CustomCell
cell.workout = workouts[indexPath.row]
return cell
}
Related Topics
iOS UIlabel Autoshrink So Word Doesn't Truncate to Two Lines
Checking Cellular Network Type in iOS
iOS Facebook Sdk Error Domain Com.Facebook.Sdk Code 2 and Code 7
How to Keep Spritekit Scene Paused When App Becomes Active
How to Post Data Using Afnetworking 2.0
How to Lock Viewcontroller in Portrait Mode
Do Xcode 8 Swift 3 Apps Run on iOS 7 Successfully
Update Responsejson to Responsedecodable in Swift
Is There a Way of Automatically Writing Custom Values to The Bundle's .Plist During a Build Phase
Receipt Validation in iOS Returns Incorrect Info During Sandbox Testing
Gcm Support for iOS Application When Application in Background or Killed
Cocos2D Sprite Repeat Animation Forever
Uiactivityviewcontroller Subject Not Working for Outlook
Perform "Use Photo" Button on Custom Image Picker Overlay
What Exactly Does ': Class' Do in a Protocol Declaration