TextView load with delay and slow - ios

When I scroll down in tableview, the TextView load slow and scrolling has break.
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if arrayofCellData[indexPath.row].isDesc == false{
let cell = Bundle.main.loadNibNamed("imagesTableViewCell", owner: self, options: nil)?.first as! imagesTableViewCell
let indexA = self.arrayofCellData[indexPath.row].text
let path = "http://a"+indexA!
let url = URL(string: path)
cell.detailsImg.sd_setImage(with: url)
return cell
}
else {
let cell = Bundle.main.loadNibNamed("imagesTableViewCellDesc", owner: self, options: nil)?.first as! imagesTableViewCellDesc
let textD = self.arrayofCellData[indexPath.row].text!
let style = NSMutableParagraphStyle()
style.lineSpacing = 12
let attributes = [NSParagraphStyleAttributeName : style]
cell.descText.attributedText = NSAttributedString(string: textD, attributes:attributes)
cell.descText.textColor = UIColor.white
cell.descText.font = UIFont(name: (cell.descText.font?.fontName)!, size: 16)
cell.descText.textAlignment = .right
return cell
}
}

These below two lines are the root cause of your lagging. You are trying to use new TableViewCell everytime.
let cell = Bundle.main.loadNibNamed("imagesTableViewCell", owner: self, options: nil)?.first as! imagesTableViewCell
let cell = Bundle.main.loadNibNamed("imagesTableViewCellDesc", owner: self, options: nil)?.first as! imagesTableViewCellDesc
Hence to solve this you have to use dequeueReusableCellWithIdentifier in your if and else statement like below
let cell = tableView.dequeueReusableCellWithIdentifier("imagesTableViewCell", forIndexPath: indexPath) as imagesTableViewCell
let cell = tableView.dequeueReusableCellWithIdentifier("imagesTableViewCellDesc", forIndexPath: indexPath) as imagesTableViewCellDesc
and don't forgot to register your nib in viewDidLoad() like this
tableView.register(UINib(nibName: "imagesTableViewCellDesc", bundle: nil), forCellReuseIdentifier: "imagesTableViewCellDesc")
tableView.register(UINib(nibName: "imagesTableViewCell", bundle: nil), forCellReuseIdentifier:"imagesTableViewCell")
As far as imageLoading is concerned, I don't think that it will lag your scrolling because I think you are using SDWebImage library which automatically caches images and works asynchronously.

Related

Handling Events On Admob UICollectionView

fairly new to Admob. I've been trying to implement AdMob native ads on UICollectionView but I've had little to no luck. I've been able to load and show the ad in a cell but events are not registered e.g views or clicks with the GADNativeAdDelegate. This is the code so far:
// In main view controller
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "exampleCell", for: indexPath) as! exampleCell
let myItem = myItemList[indexPath.item]
if myItem is GADNativeAd {
let nAd = myItems as! GADNativeAd
let nibView = Bundle.main.loadNibNamed("UnifiedNativeAdView", owner: nil, options: nil)?.first
let nativeAdView = nibView as! GADNativeAdView
// Prepare ad content
let nativeAd = nAd
// Add content to native view
(nativeAdView.headlineView as? UILabel)?.text = nativeAd.headline
nativeAdView.mediaView?.mediaContent = nativeAd.mediaContent
(nativeAdView.bodyView as? UILabel)?.text = nativeAd.body
nativeAdView.bodyView?.isHidden = nativeAd.body == nil
(nativeAdView.iconView as? UIImageView)?.image = nativeAd.icon?.image
nativeAdView.iconView?.isHidden = nativeAd.icon == nil
(nativeAdView.advertiserView as? UILabel)?.text = nativeAd.advertiser
nativeAdView.advertiserView?.isHidden = nativeAd.advertiser == nil
nativeAdView.callToActionView?.isUserInteractionEnabled = false
nativeAdView.nativeAd?.delegate = self
nativeAdView.nativeAd?.rootViewController = self
cell.addSubview(nativeAdView)
return cell
}
}
My cell is a basic UICollectionViewCell that is empty as follows:
class exampleCell: UICollectionViewCell {
override func awakeFromNib() {
super.awakeFromNib()
}
}
I've had a look at this answer but it doesn't seem to be applicable.
In cellForItemAt delegate
try this
// Remove previous GADBannerView from the content view before adding a new one.
for subview in reusableAdCell.contentView.subviews {
subview.removeFromSuperview()
}

SDWebImage not loading images Until I scroll the tableView in Swift

If I scroll, then only the images are loading. Here is my code
var nib: [Any] = Bundle.main.loadNibNamed("SampleTableViewCell", owner: self, options: nil)!
let cell = nib[0] as? SampleTableViewCell
let values = detailsArr[indexPath.row] as! SampleModel
let url = URL(string: values.imageStr)
cell?.title_Lbl.text = values.title
cell?.desccription_Lbl.text = values.description
cell?.image_View.sd_setImage(with: url)
cell?.layoutIfNeeded()
tableView.estimatedRowHeight = 370
return cell!
}
You need to register the nib as a reusable cell for the UITableView:
let sampleNib = UINib(nibName: "SampleTableViewCell", bundle: nil)
tableView.register(sampleNib, forCellReuseIdentifier: "SampleTableViewCell")
Then in tableView's dataSource method cellForRowAt deque it:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let sampleCell = tableView.dequeueReusableCell(withIdentifier: "SampleTableViewCell") as! SampleTableViewCell
/*
Customise your cell here.
I suggest you make all your customisations inside the cell, and call here a function from the cell
eg.:
let values = detailsArr[indexPath.row] as! SampleModel
sampleCell.setupCell(with: values)
*/
return sampleCell
}

Tap Gesture not Working for imageView in tableview cell

I have 6 custom cells in the table view. In that 3 of them have an image view I added tapGesture to imageView and enabled the user interaction of imageView still not working. I also tried to add tapGesture in main tread in table view cell class but no use, I even tried to add gesture in the cell for at IndexPath method but not worked, how to solve this?
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellArr = sections[indexPath.section].cell
//Loading cell based on array details
switch cellArr[0] {
case is InsuranceDetails:
let insuranceCell = tableView.dequeueReusableCell(withIdentifier: "insuranceCell") as! InsuranceCell
insuranceCell.setup(object: cellArr[indexPath.row], in: tableView, at: indexPath)
case is Pollution:
let pollutionCell = tableView.dequeueReusableCell(withIdentifier: "pollutionCell") as! PollutionCell
pollutionCell.setup(object: cellArr[indexPath.row], in: tableView, at: indexPath)
return pollutionCell
case is Servicing:
let servicingCell = tableView.dequeueReusableCell(withIdentifier: "servicingCell") as! ServicingCell
servicingCell.setup(object: cellArr[indexPath.row], in: tableView, at: indexPath)
return servicingCell
case is ChallanPaid:
let challanPaidCell = tableView.dequeueReusableCell(withIdentifier: "challanPaidCell") as! ChallanPaidCell
challanPaidCell.setup(object: cellArr[indexPath.row], in: tableView, at: indexPath)
return challanPaidCell
case is InsuranceClaims:
let insuranceClaimCell = tableView.dequeueReusableCell(withIdentifier: "insuranceClaimCell") as! InsuranceClaimCell
insuranceClaimCell.setup(object: cellArr[indexPath.row], in: tableView, at: indexPath)
return insuranceClaimCell
case is FuelRefills:
let fuelRefillCell = tableView.dequeueReusableCell(withIdentifier: "fuelRefillCell") as! FuelRefillCell
fuelRefillCell.setup(object: cellArr[indexPath.row], in: tableView, at: indexPath)
return fuelRefillCell
default:
return UITableViewCell()
}
}
one of my tableview cell class
class InsuranceCell: UITableViewCell {
#IBOutlet weak var insurancePhoto: UIImageView!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
func setup(object: NSManagedObject, in table: UITableView, at indexPath: IndexPath) {
guard let arr = object as? InsuranceDetails else {return}
let tapgesture = UITapGestureRecognizer(target: self, action: #selector(imageTapped))
insurancePhoto.isUserInteractionEnabled = true
tapgesture.numberOfTapsRequired = 1
insurancePhoto.isUserInteractionEnabled = true
insurancePhoto.addGestureRecognizer(tapgesture)
// Do time consuming stuff in the background
DispatchQueue.global(qos: .userInitiated).async {
let imageData = arr.insurancePhoto ?? Data()
let image = UIImage(data: imageData)
let compimage = image?.resized(withPercentage: 0.5)
// Always back to the main thread/queue for UI updates
DispatchQueue.main.async {
guard let cell = table.cellForRow(at: indexPath) as? InsuranceCell else { return }
cell.insurancePhoto.image = compimage
}
}
}
}

Swipe gesture in tableview

I want to add Swipe gesture on my cell. It work fine.but the Problem is when i swipe on first cell but my fifth cell also swipe. I know this indexpath problem. Please help.But i am stuck from few hour.
let swipeLeft = UISwipeGestureRecognizer(target: self, action: #selector(self.handleLeftSwipe))
swipeLeft.direction = UISwipeGestureRecognizerDirection.left
table.addGestureRecognizer(swipeLeft)
let swipeLeftd = UISwipeGestureRecognizer(target: self, action: #selector(self.handleLeftSwipes))
swipeLeftd.direction = UISwipeGestureRecognizerDirection.right
table.addGestureRecognizer(swipeLeftd)
#objc func handleLeftSwipe(sender: UITapGestureRecognizer) {
print("rigt called")
let location = sender.location(in: self.table)
let indexPath = self.table.indexPathForRow(at: location)
let cell = self.table.cellForRow(at: indexPath!) as! TableViewCell
print("swipe")
cell.myView.frame.origin.x = -94
}
#objc func handleLeftSwipes(sender: UITapGestureRecognizer) {
print("labelSwipedLeft called")
let location = sender.location(in: self.table)
let indexPath = self.table.indexPathForRow(at: location)
let cell = self.table.cellForRow(at: indexPath!) as! TableViewCell
print("swipe")
cell.myView.frame.origin.x = 80
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let identifier = "TableViewCell"
var cell: TableViewCell! = tableView.dequeueReusableCell(withIdentifier: identifier) as? TableViewCell
if cell == nil {
var nib : Array = Bundle.main.loadNibNamed("TableViewCell",owner: self,options: nil)!
cell = nib[2] as? TableViewCell
}
return cell!
}
The reason for that is reusing your cells. I assume you do not set anything in your prepareForReuse(). So, your problem is in line cell.myView.frame.origin.x = 80, right? Just set it to default in prepareForReuse or in cellForRowAt indexPath.

How to animate UITableViewCell using Swift?

I have a UITableView and inside the tableViewCell I have a UICollectionView.
My requirement is while tapping on a button of first tableView cell I have to animate second tableViewCell.
Below is my code :-
//Cell For Row at indexPath
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if (0 == indexPath.section) {
let cell = tableView.dequeueReusableCell(withIdentifier: "FirstRowCell") as! FirstRowCell
cell.btnReview.addTarget(self, action: #selector(GotoReview), for: UIControlEvents.touchUpInside)
cell.btnMyProduct.addTarget(self, action: #selector(AnimateCollectionView), for: UIControlEvents.touchUpInside)
//cell.
return cell
} else if ( 1 == indexPath.section) {
let identifier = "TableCollectionCell"
var tableCollectionCell = tableView.dequeueReusableCell(withIdentifier: identifier) as? TableCollectionCell
if(tableCollectionCell == nil) {
let nib:Array = Bundle.main.loadNibNamed("TableCollectionCell", owner: self, options: nil)!
tableCollectionCell = nib[0] as? TableCollectionCell
tableCollectionCell?.delegate = self
}
return tableCollectionCell!
} else {
let identifier = "BrandImagesTableCell"
var brandImagesTableCell = tableView.dequeueReusableCell(withIdentifier: identifier)
if(brandImagesTableCell == nil) {
let nib:Array = Bundle.main.loadNibNamed("BrandImagesTableCell", owner: self, options: nil)!
brandImagesTableCell = nib[0] as? BrandImagesTableCell
}
//brandImagesTableCell.
return brandImagesTableCell!
}
}
In my code you can see:
if (0 == indexPath.section)
In that I have a button target (#selector(AnimateCollectionView)).
I want to animate tableCollectionCell which is at (1 == indexPath.section).
See my AnimateCollectionView method :-
func AnimateCollectionView() {
let identifier = "TableCollectionCell"
var tableCollectionCell = tableView.dequeueReusableCell(withIdentifier: identifier) as? TableCollectionCell
if(tableCollectionCell == nil) {
let nib:Array = Bundle.main.loadNibNamed("TableCollectionCell", owner: self, options: nil)!
tableCollectionCell = nib[0] as? TableCollectionCell
tableCollectionCell?.delegate = self
}
tableCollectionCell?.alpha = 0
UIView.animate(withDuration: 1.50, animations: {
//self.view.layoutIfNeeded()
tableCollectionCell?.alpha = 1
})
}
If you want to animate its change, you can just change some state variables, call tableView.reloadRows(at:with:), and have your cellForRowAt then check those state variables to know what the final cell should look like (i.e. whether it is the "before" or "after" cell configuration).
For example, here is an example, with two cells, toggling the second cell from red to blue cells.
class ViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UINib(nibName: "RedCell", bundle: nil), forCellReuseIdentifier: "RedCell")
tableView.register(UINib(nibName: "BlueCell", bundle: nil), forCellReuseIdentifier: "BlueCell")
}
#IBAction func didTapButton(_ sender: UIButton) {
isRedCell = !isRedCell
tableView.reloadRows(at: [IndexPath(row: 1, section: 0)], with: .fade)
}
var isRedCell = true
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 2
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "ButtonCell", for: indexPath)
return cell
} else if indexPath.row == 1 {
if isRedCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "RedCell", for: indexPath)
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "BlueCell", for: indexPath)
return cell
}
}
fatalError("There are only two rows in this demo")
}
}
Now, assuming you really needed to use NIBs rather than cell prototypes, I would register the NIBs with the tableview like above, rather than having cellForRow have to manually instantiate them itself. Likewise, for my cell with the button, I just used a prototype cell in my storyboard and hooked the button directly to my #IBOutlet, avoiding a NIB for that cell entirely.
But all of that is unrelated to your main problem at hand: You can create your cells however you want. But hopefully this illustrates the basic idea, that on the tap of the button, I'm not trying to load any cells directly, but I just update some status variable that cellForRow will use to know which cell to load and then tell the tableView to animate the reloading of that IndexPath.
By the way, I assumed from your example that the two different potential cells for the second row required different NIBs. But if you didn't, it's even easier (use just one NIB and one cell identifier), but the idea is the same, just update your state variable and reload the second row with animation.

Resources