SDWebImage not loading images Until I scroll the tableView in Swift - ios

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
}

Related

Make tableView cell with struct and data by indexpath

I already known how to make a basic tableView, below is my basic code
class ShoppingTableViewController: UITableViewController{
var description = ["D1", "299900", "D2", "P201712310000003000", "D3", "ASS+DfDFxSuu", "D10", "901", "D11", "00,46246226301561000110001001", "D12", "20201231123030"]
var dictDescription = ["D10": "901", "D11": "00,46246226301561000110001001", "D3": "ASS+DfDFxSuu", "D12": "20201231123030", "D2": "P201712310000003000", "D1": "299900"]
override func viewDidLoad() {
super.viewDidLoad()
// Xib
tableView.register(UINib(nibName:PropertyKeys.pictureCell , bundle: nil), forCellReuseIdentifier: PropertyKeys.pictureCell)
tableView.register(UINib(nibName:PropertyKeys.infoCell , bundle: nil), forCellReuseIdentifier: PropertyKeys.infoCell)
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 4
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
switch indexPath.row {
case 0:
let cell = tableView.dequeueReusableCell(withIdentifier: PropertyKeys.pictureCell, for: indexPath) as! PictureWithTableViewCell
cell.iconImageView.image = UIImage(named: "amount")
cell.lbDescription.text = "Type"
cell.lbName.text = "Shopping"
return cell
case 1:
let cell = tableView.dequeueReusableCell(withIdentifier: PropertyKeys.infoCell, for: indexPath) as! InfoTableViewCell
cell.lbDescription.text = "Taiwan dollar"
cell.lbName.text = m_dictDescription["D1"]
return cell
case 2:
let cell = tableView.dequeueReusableCell(withIdentifier: PropertyKeys.pictureCell, for: indexPath) as! PictureWithTableViewCell
cell.iconImageView.image = UIImage(named: "info")
cell.lbDescription.text = "BankName"
cell.lbName.text = m_dictDescription["D11"]
return cell
case 3:
if m_dictDescription["D2"] != nil {
let cell = tableView.dequeueReusableCell(withIdentifier: PropertyKeys.infoCell, for: indexPath) as! InfoTableViewCell
cell.lbDescription.text = "orderNumber"
cell.lbName.text = m_dictDescription["D2"]
return cell
}else {
let cell = tableView.dequeueReusableCell(withIdentifier: PropertyKeys.infoCell, for: indexPath) as! InfoTableViewCell
cell.isHidden = true
return cell
}
but this is an unsafe way because i write func number of rows and cell for row as hardcode.
so I want to change tableView composing way from decide cell format first then fill data in (like my basic code) to let data decide my number of rows and cell for row. (use indexPath)
but I got some problems:
I try to write:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let test = self.m_arrDescription[indexPath.row]
cell.lbName.text = test
It works but every cell looks the same while I want to present different cells.
I search some information on internet, perhaps I can use struct and combine m_arrDescription to make tableview cell.
// use struct to decide cell label or image , for example: cell.lbDescription.text ...
struct CellFormat {
var title : String
var image : UIImage
var name : String
}
So far this is what i've written, can anyone please kindly help me to go on?
Be clearly, how do I use [indexPath.row] in this code ?
please create first one enum
enum CellType: String, CaseIterable {
case title, image, name
}
and then use this code in tableview delegate methods.
switch CellType(rawValue: indexPath.row) {
case .title:
break
case .image:
break
case .name:
break
case .none:
break
}
If any problem let me know

TextView load with delay and slow

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.

Parsing multiple images in swift from JSON

Json has multiple images,
img1
Json has date with multiple images, I want show Date and first image of that Date in tableview, working fine.
img2
Note :
when click any cell in tableview, display that Date with all images in collection view, But am parsing only first image of that Date,that image only showing in collection view
how to parse all images from Json and pass to collection view from tableview, and display images into collocation view
img3
this is the code ...
json Code
if errorCode == "0" {
if let Media_list = jsonData["events"] as? [Any] {
self.Mediainfo.removeAll()
for i in 0 ..< Media_list.count {
if let MediaEventData = Media_list[i] as? [String: Any] {
var eventImages = MediaEventData["eventImages"] as? [[String: Any]]
if (eventImages?.count)! > 0 {
let bannerImage = eventImages?[0]["bannerImage"] as? String
print(bannerImage as Any)
self.imageUrl = self.url+"/images/events/" + String(describing: bannerImage!)
self.Mediainfo.append(MediaEvent(
eventId: MediaEventData["eventId"]as?String,
date: MediaEventData["date"]as?String,
eventname: MediaEventData["eventName"]as?String,
bannerImages: self.imageUrl
)
)
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Media", for: indexPath)as! MediaCustomTableViewCell
let row = indexPath.row
let media = Mediainfo[row] as MediaEvent
cell.DisplayDate.text = media.date
cell.DisplayName.text = media.eventName
cell.selectionStyle = .none
cell.DisplayImage.downloadImageFrom(link:media.bannerImages, contentMode: UIViewContentMode.scaleAspectFit)
return cell
}
override func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return CGFloat.leastNormalMagnitude
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
let media = Mediainfo[(indexPath.row)] as MediaEvent
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let tabBarController = storyboard.instantiateViewController(withIdentifier: "IMAGEVID") as! UITabBarController
if let viewControllers = tabBarController.viewControllers,
let imageController = viewControllers.first as? ImagesCollectionViewController {
imageController.RecivedData1 = media.bannerImages
}
navigationController?.pushViewController(tabBarController, animated: true)
}
collection view Code :
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! ImageCollectionViewCell
cell.ImageviewCell.downloadImageFrom(link:nameofImages[indexPath.row], contentMode: UIViewContentMode.scaleAspectFit)
return cell
}
pls help me......!
u can do soemthing like this
let eventImages = MediaEventData["eventImages"] as? [[String: Any]]
if (eventImages?.count)! > 0 {
for i in 0...eventImages.count{
let bannerImage = eventImages?[i]["bannerImage"] as? String
self.imageUrl = self.url+"/images/events/" + String(describing: bannerImage!)
self.Mediainfo.append(bannerImage)
// or like u did u can append to array
self.Mediainfo.append(MediaEvent(
eventId: MediaEventData["eventId"]as?String,
date: MediaEventData["date"]as?String,
eventname: MediaEventData["eventName"]as?String,
bannerImages: self.imageUrl
)
} }
In didselect
let media = Mediainfo[(indexPath.row)] as MediaEvent
imageController.RecivedData1 = media.bannerImages
Your doing like this Means Your are slecting a particular cell and
that index your are passing to NextVC.
if you want to show all images You should pass complete array to
nextvc
You should declare a array of same type Mediainfo array in Next VC
and do like
EX: imageController.array = Mediainfo

Swift: set Image to Custom cell ImageView

i want to set the Image to Custom cell. I am confuse how to do this.
lets say I have a custom cell in my UITable View.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("CustomCellOne", forIndexPath: indexPath) as! CustomOneCell
let tapGestureRecognizer = UITapGestureRecognizer(target:self, action:#selector(imageTapped(img:)))
cell.imageView.isUserInteractionEnabled = true
cell.imageView.addGestureRecognizer(tapGestureRecognizer)
return cell
}
Now as soon as i tap in the Image the following function gets called:
func imageTapped(img: AnyObject){
print("Image clicked.")
if let pickedImage = info[UIImagePickerControllerOriginalImage] as? UIImage {
let imageData: NSData = UIImagePNGRepresentation(myImage)
let image: UIImage = UIImage(data:imageData,scale:1.0)
print(image)
//i am uploading the photo from here. and i want to set this picture to my cell imageView.
}
dismissViewControllerAnimated(true, completion: nil
}
I am confused how to call the cell imageview from here??
How can i further procced?? I just need to set That obtained image to imgeView in cell other everything works fine..
Here's an example I have just tested
I have a custom TableViewCell, named ImageTableViewCell, which contains a single UIImageView, named customImageView
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: "cellImage", for: indexPath) as! ImageTableViewCell
// initialising with some dummy data of mine
cell.customImageView.image = UIImage(named: "Image\(indexPath.row).png")
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(self.imageTapped(_:)))
cell.addGestureRecognizer(tapGesture)
return cell
}
and then in the ViewController
func imageTapped(_ sender: UITapGestureRecognizer)
{
let myCell = sender.view as! ImageTableViewCell
myCell.customImageView.image = UIImage(named: "imageTapped.jpg")
}
This should update the image immediately, without any requirement to reload the table

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