hey i have a tableview with images and some text labels the whole cell is 400 in height and i want to extend it to 700 when i click the cell to make the user see more information of the cell so i wrote this code
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if isExpanded && self.selectedIndex == indexPath{
return 700
}
return 400.0
}
var selectedIndex:IndexPath?
var isExpanded = false
func didExpandCell() {
self.isExpanded = !isExpanded
self.postsTableView.reloadRows(at: [selectedIndex!], with: .automatic)
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.selectedIndex = indexPath
self.didExpandCell()
}
but this code requires a .xib file off the Cell, i have tryed to run the app without the code below but it doesnt work and i have tryed it with it and it doesnt work because i need a .xib file for the cell so i was wondering if it is possible that someone could help me with this and just explain how i can this cells epandable without this .xib file of the cell
func unnesseryNibFile(){
//this code goes in the viewDidLoad func and it is required to have a .xib file of the Cell protoype
let nib = UINib.init(nibName: "postTableViewCell", bundle: nil)
self.postsTableView.register(nib, forCellReuseIdentifier: "Cell")
}
here is my 'cellForRowAt'
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! PostTableViewCell
// Configure the cell...
let post = self.posts[indexPath.row] as! [String: AnyObject]
cell.locationLabel.text = post["location"] as? String
cell.usernameLabel.text = post["username"] as? String
cell.titleLabel.text = post["title"] as? String
cell.contentTextView.text = post["content"] as? String
if let imageName = post["image"] as? String {
let imageRef = Storage.storage().reference().child("images/\(String(describing: imageName))")
imageRef.getData(maxSize: 25 * 1024 * 1024, completion: { (data, error) -> Void in
if error == nil {
//succeful
let image = UIImage(data: data!)
cell.postImageView.image = image
}else{
//Not Succesful
print("error Downloading The Image\(String(describing: error?.localizedDescription))")
}
})
}
return cell
}
thanks for your time. :)
Related
Now my ViewController code is here -
import UIKit
struct jsonstruct: Codable {
let name: String
let meta_data: [Categories]
enum CodingKeys: String, CodingKey {
case name
case meta_data
}
}
struct Categories: Codable {
let value: String
enum CodingKeys: String, CodingKey {
case value
}
}
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
var arrdata : [jsonstruct] = [jsonstruct]()
var categorydata : [Categories] = [Categories]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
getdata()
}
func getdata() {
let url = URL(string: "https://mywebstaging.net/ab/garnier/wp-json/wc/v3/products?consumer_key=<key>&consumer_secret=<secret>")
URLSession.shared.dataTask(with: url!) { (data, response, error) in
do{if error == nil{
self.arrdata = try JSONDecoder().decode([jsonstruct].self, from: data!)
print(self.arrdata)
DispatchQueue.main.async {
self.tableView.reloadData()
}
}catch{
print("Error in get json data")
}
}.resume()
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if tableView == tableView {
return arrdata.count
}else{
return categorydata.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if tableView == tableView {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CellTableViewCell
let getdata = arrdata[indexPath.row]
cell.lblid.text = getdata.name
return cell
}
else{
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CellTableViewCell
let getdatadesciption = self.categorydata[indexPath.row]
cell.lblname.text = getdatadesciption.value
return cell
}
}
}
Hare only the "name" is being displayed in the tableview. But the "value" is not coming. The output I'm getting like this. Please guide me. Thanks in advance.
Replace
if tableView == tableView {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CellTableViewCell
let getdata = arrdata[indexPath.row]
cell.lblid.text = getdata.name
return cell
}
else{
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CellTableViewCell
let getdatadesciption = self.categorydata[indexPath.row]
cell.lblname.text = getdatadesciption.value
return cell
}
with getdata.meta_data.first?.value contains top category name
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CellTableViewCell
let getdata = arrdata[indexPath.row]
cell.lblid.text = getdata.name
cell.lblname.text = getdata.meta_data.first?.value
return cell
You don't have to maintain 2 arrays it's only one
Replace
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if tableView == tableView {
return arrdata.count
} else {
return categorydata.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if tableView == tableView {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CellTableViewCell
let getdata = arrdata[indexPath.row]
cell.lblid.text = getdata.name
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CellTableViewCell
let getdatadesciption = self.categorydata[indexPath.row]
cell.lblname.text = getdatadesciption.value
return cell
}
}
With
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrdata.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CellTableViewCell
let data = arrdata[indexPath.row]
let category = data.meta_data.first
cell.lblid.text = data.name
cell.lblname.text = category.value
return cell
}
What I want to do:
I have a feed (TableView( and once the user taps on a Post (TableViewCell), he should see a new Page (TableView) with the Post he tapped on first (the same TableViewCell) on top and a couple of comments below.
My Problem:
I dont get how to "clone" that TableViewCell.
Here two pictures for a better understanding:
Some complications:
I have multiple post types in the main feed, so the code would have to differentiate between them to see which cell type to use to display the content.
My code:
Main Feed
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0{
return mixed.count
}
else if section == 1{
return phots.count
}
else{
return texttt.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0{
let cell = tableView.dequeueReusableCell(withIdentifier: mixedTableViewCell.identifier, for: indexPath) as! mixedTableViewCell
cell.configure(with: self.mixed[indexPath.row])
return cell
}
else if indexPath.section == 1{
let cell = tableView.dequeueReusableCell(withIdentifier: popularTableViewCell.identifier, for: indexPath) as! popularTableViewCell
cell.configure(with: self.phots[indexPath.row])
return cell
}
else{
let cell = tableView.dequeueReusableCell(withIdentifier: textTableViewCell.identifier, for: indexPath) as! textTableViewCell
cell.configure(with: self.texttt[indexPath.row])
return cell
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "commentsVC")
vc.modalPresentationStyle = .fullScreen
self.navigationController?.pushViewController(vc, animated: true)
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
My second ViewController
class CommentsViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet var table: UITableView!
var texty = [TextComment]()
override func viewDidLoad() {
super.viewDidLoad()
table.register(popularTableViewCell.nib(), forCellReuseIdentifier: popularTableViewCell.identifier)
table.register(featuredTableViewCell.nib(), forCellReuseIdentifier: featuredTableViewCell.identifier)
table.register(textTableViewCell.nib(), forCellReuseIdentifier: textTableViewCell.identifier)
table.register(mixedTableViewCell.nib(), forCellReuseIdentifier: mixedTableViewCell.identifier)
table.register(textComTableViewCell.nib(), forCellReuseIdentifier: textComTableViewCell.identifier)
table.delegate = self
table.dataSource = self
}
func numberOfSections(in tableView: UITableView) -> Int {
2
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0{
return 1
}
else{
return 15
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0{
let cell = tableView.dequeueReusableCell(withIdentifier: textTableViewCell.identifier, for: indexPath) as! textTableViewCell
return cell
}
else{
let cell = tableView.dequeueReusableCell(withIdentifier: textComTableViewCell.identifier, for: indexPath) as! textComTableViewCell
return cell
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.section == 0{
// self.table.estimatedRowHeight = 250
// self.table.rowHeight = UITableView.automaticDimension
// return UITableView.automaticDimension
return 300
}
else{
// self.table.estimatedRowHeight = 150
// self.table.rowHeight = UITableView.automaticDimension
// return UITableView.automaticDimension
return 150
}
}
Note
Right now the it isnt working at all, how I want it. I just have these "mock" posts as space-fillers in there.
Any help or ideas would be greatly appreciated!
My structs
struct PhotoPost {
let numberOfComments: Int
let username: String
let timestampName: String
let userImageName: String
let postImageName: String
let postID: String
}
struct TextPost {
let numberOfComments: Int
let username: String
let timestampName: String
let userImageName: String
let textName: String
let postID: String
}
struct MixedPhoto {
let numberOfComments: Int
let username: String
let timestampName: String
let userImageName: String
let textName: String
let postImageName: String
let postID: String
}
Here my errors:
Each instance of UITableView has its own pool of cells, for this reason it would not be correct to "steal" an instance of the cell from one UITableView and put it into another. Also, as far as i can see you already have a convenient way to feed your cells with data, and dequeue corresponding types. Thus the only thing left here is to pass the required data from MainFeed under your tableView(_: didSelectRowAt:) function, something like that:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
guard let vc = storyboard.instantiateViewController(withIdentifier: "commentsVC") as? CommentsViewController else {
return
}
switch indexPath.section {
case 0:
vc.mixedData = mixed[indexPath.row]
case 1:
vc.photoData = photos[indexPath.row]
default:
vc.textData = texttt[indexPath.row]
}
vc.modalPresentationStyle = .fullScreen
navigationController?.pushViewController(vc, animated: true)
}
And then, under the CommentsViewController's tableView(_:, cellForRowAt:) function, implement pretty much the same stuff you did in MainFeed:
var mixedData: MixedPhoto?
var photoData: PhotoPost?
var textData: TextPost?
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0 {
let cell: UITableViewCell
switch (mixedData, photoData, textData) {
case (.some(let value), _, _):
cell = tableView.dequeueReusableCell(withIdentifier: mixedTableViewCell.identifier, for: indexPath) as! mixedTableViewCell
cell.configure(with: value)
case (_, .some(let value), _):
cell = tableView.dequeueReusableCell(withIdentifier: popularTableViewCell.identifier, for: indexPath) as! popularTableViewCell
cell.configure(with: value)
case (_, _, .some(let value)):
cell = tableView.dequeueReusableCell(withIdentifier: textTableViewCell.identifier, for: indexPath) as! textTableViewCell
cell.configure(with: value)
default:
fatalError("The data is not set")
}
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: textComTableViewCell.identifier, for: indexPath) as! textComTableViewCell
return cell
}
}
Also I should say that it's a good idea to implement a common protocol for your data types, so you actually can define a single non-optional variable in the CommentsViewController instead of three optionals.
I have to show a couple of different cells. I called tableView(_:cellForRowAt:) for that, and in the method I use two different IDs for different classes of UITableViceCell
Here is a simple code:
class SimpleView: UITableViewController {
...
let cellIdMain = "JournalMainCellID"
let cellIdExtra = "JournalMainSceneAddNewID"
...
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == journals.count {
guard let cellAdding = tableView.dequeueReusableCell(withIdentifier: cellIdExtra, for: indexPath) as? JournalMainSceneAddNew else {
fatalError("Cannot connect to the cell")
}
return cellAdding
}
guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdMain, for: indexPath) as? JournalMainSceneCell else {
fatalError("Cannot connect to the cell")
}
cell.numberOfCountriesLabel.text = "\(journals[indexPath.row].numberOFCountries)"
return cell
}
}
When I tried to find memory leaks I found:
When I click on the details I found:
Why this happened? It looks pretty simple and straightforward.
Updated: pictures were updated.
you are writing if conditions which will work only in one case as indexpath.row will only be equal to count
even though it will not work because after going through if it will execute block of code after if
which means your if block is waste
and why are you using cell.delegate??
Update your code with the following code.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == journals.count {
let cellAdding: JournalMainSceneAddNew = {
guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdExtra) as? JournalMainSceneAddNew else {
return JournalMainSceneAddNew(style: UITableViewCellStyle.value1, reuseIdentifier: cellIdExtra)
}
return cell
}()
return cellAdding
}
let cell: JournalMainSceneCell = {
guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdMain) as? JournalMainSceneCell else {
return JournalMainSceneCell(style: UITableViewCellStyle.value1, reuseIdentifier: cellIdMain)
}
return cell
}()
cell.numberOfCountriesLabel.text = "\(journals[indexPath.row].numberOFCountries)"
return cell
}
I just set my UITableCell linebreak to byWordWrapping and add this method:
override func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
Now My UITableCell Images are massive, what is the best way to resize them or have the images aspect to fit?
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "commentsCell", for: indexPath)
cell.textLabel?.numberOfLines = 0
cell.textLabel?.lineBreakMode = .byWordWrapping
cell.detailTextLabel?.numberOfLines = 0
cell.detailTextLabel?.lineBreakMode = .byWordWrapping
if((self.array[indexPath.row]["profileImg"] as! String) == "")
{
cell.textLabel?.text = (self.array[indexPath.row]["username"] as! String)
cell.detailTextLabel?.text = (self.array[indexPath.row]["comment"] as! String)
cell.imageView?.image = UIImage(named: "default.png")
}
else
{
let imgUrl = URL(string:"http://auxpod.com/uploads/" + (self.array[indexPath.row]["profileImg"] as! String))
Alamofire.request(imgUrl!).responseImage { response in
DispatchQueue.main.async {
if let image = response.result.value {
cell.textLabel?.text = (self.array[indexPath.row]["username"] as! String)
cell.detailTextLabel?.text = (self.array[indexPath.row]["comment"] as! String)
cell.imageView?.image = image
}
}
}
}
return cell
}
1-
Don't load the image inside cellForRowAt as it keeps download the image every scroll so use SDWebImage that caches it after first download
2-
Create a custom cell class , hook the the height constraint of the imageView and change it according to the required aspect ratio
imageViewH.constant = imageRealHeight * imageCellWidth / imageRealWidth
I have a tableview that loads database info from Firebase and the image pulls from Firebase storage with my hardcoded directory/file.
I want the value of cell.videoID.text so that I can pass it to another viewcontroller via Segue. I just can't seem to get the value of cell.videoID.text when the cell is clicked and have tried all sorts of ways from this and other sites.
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return vehicleList.count
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! ViewControllerTableViewCell
let vehicle: VehicleModel
vehicle = vehicleList[indexPath.row]
cell.videoID.text = vehicle.id
cell.neworusedLabel.text = vehicle.neworused
cell.yearLabel.text = vehicle.year
cell.priceLabel.text = vehicle.price
cell.makeLabel.text = vehicle.make
cell.modelLabel.text = vehicle.model
cell.packageLabel.text = vehicle.package
cell.colorLabel.text = vehicle.color
// Get the image from storage container
let storage = Storage.storage().reference()
let imagePath = "tmpDir/tmpImage.png"
let tempImageRef = storage.child(imagePath)
tempImageRef.getData(maxSize: 1 * 600 * 600) { data, error in
if error == nil {
cell.lblView.image = UIImage(data: data!)
} else {
print(error?.localizedDescription)
}
}
return cell
}
var valueToPass:String!
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// Get Cell Label
let indexPath = tableView.indexPathForSelectedRow!
let currentCell = tableView.cellForRow(at: indexPath)! as UITableViewCell
print("currentCell")
print("You selected cell #\(indexPath.row)!")
// valueToPass = "Trying to get the videoID"
performSegue(withIdentifier: "detailSegue", sender: self)
}
My answer was: valueToPass = vehicleList[indexPath.row].id
Thanks to Kosuke above in the comments!