How do I make the my first tableview cell twice the height of the rest of the following cells?
This is my tableview code:
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return posts.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell")
let label1 = cell?.viewWithTag(1) as! UILabel
label1.text = posts[indexPath.row].title
let imageView = cell?.viewWithTag(2) as! UIImageView
let post = self.posts[indexPath.row];
imageView.sd_setImage(with: URL(string: post.downloadURL), placeholderImage: UIImage(named: "placeholder"))
return cell!
}
You should use this function
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.row == 0{
return 70.0
}
return 35.0
}
Related
i am adding multiple selection in tableview with sections in tableview, so how can i store that section index as well as indexpath of that cell for display when user click on cell inside that particular sections that will store in array as selected item and reflect in cellForRowAtindexpath the better solution is appreciated
func numberOfSections(in tableView: UITableView) -> Int {
return sections.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return itemsInSections[section].count
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return self.sections.count;
}
func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
let header = view as! UITableViewHeaderFooterView
header.textLabel?.textColor = UIColor(red: 8/255, green: 38/255, blue: 76/255, alpha: 1.0)
header.backgroundColor = UIColor.clear
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tablheaders.dequeueReusableCell(withIdentifier: "Cell", for: indexPath as IndexPath)
let section = indexPath.section
if checkdarray.count > 0
{
if (self.checkdarray[section][indexPath.row] as Int == 1)
{
cell.accessoryType = .checkmark;
}
else
{
cell.accessoryType = .none;
}
}
cell.textLabel?.text = itemsInSections[indexPath.section][indexPath.row] as! String
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let section = indexPath.section as Int
let indepaths = indexPath.row as Int
tableView.cellForRow(at: indexPath as IndexPath)?.accessoryType = .checkmark
checkdarray.insert([1], at: [section][indepaths])
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
tableView.cellForRow(at: indexPath as IndexPath)?.accessoryType = .none
// checkdarray.remove(at: indexPath.row)
//checkdarray.insert(0, at: indexPath.row)
}
The most efficient and reliable solution is to keep the isSelected state in the data model.
Use a struct as data model and add a member isSelected along with the other information you need.
struct Model {
var isSelected = false
var someOtherMember : String
// other declarations
}
In cellForRow set the checkmark according to the isSelected member
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) // use always the passed tableView instance
let model = itemsInSections[indexPath.section][indexPath.row]
cell.accessoryType = model.isSelected ? .checkmark : .none
cell.textLabel?.text = model.someOtherMember
return cell
}
In didSelectRowAt and didDeselectRowAt update the model and reload the row
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
itemsInSections[indexPath.section][indexPath.row].isSelected = true
tableView.reloadRows(at: [indexPath], with: .none)
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
itemsInSections[indexPath.section][indexPath.row].isSelected = false
tableView.reloadRows(at: [indexPath], with: .none)
}
Never use an extra array to save index paths. Don't do that.
I have used button in table...
// declare var
var checkarrMenu = Set<IndexPath>()
// In tableView
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return array.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = mManageTableView.dequeueReusableCell(withIdentifier: "TableViewCellID")as! TableViewCell
cell.mRadioBtnAct.tag = indexPath.row
cell.mRadioBtnAct.addTarget(self, action: #selector(mRadioCheck(sender:)), for: .touchUpInside)
if checkarrMenu.contains(indexPath){
cell.mradioimage.image = UIImage(named: "Radiochecked")
}else{
cell.mradioimage.image = UIImage(named: "Radio checkedlightRadio3")
}
return cell
}
// on radio btn Action
#objc func mRadioCheck(sender:UIButton){
let touchPoint: CGPoint = sender.convert(CGPoint.zero, to: mManageTableView)
// maintable --> replace your tableview name
let clickedButtonIndexPath = mManageTableView.indexPathForRow(at: touchPoint)
if checkarrMenu.contains(clickedButtonIndexPath){
checkarrMenu.remove(clickedButtonIndexPath)
}else{
checkarrMenu.insert(clickedButtonIndexPath)
}
tableView.reloadData()
}
// hope its works for you!
Is it possible to get 2 columns in 1 row using UITableView instead of using UICollectionView.
The code I'm using returning 1 column per 1 row while I need 2 columns in 1 row at a time like the image attached.
The code used is swift 3:
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat{
return 0
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return SCREEN_WIDTH / 4;
}
//Original Func
// func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
// return 50;
// }
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
cell.backgroundColor = UIColor.white
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return subCategoryMenuData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
subCategoryTable.register(UINib(nibName: "subCategoryCellTableViewCell", bundle: nil), forCellReuseIdentifier: "subCategoryCellTableViewCell")
//let cell:UITableViewCell = UITableViewCell(style:UITableViewCellStyle.default, reuseIdentifier:"cell")
let cell:subCategoryTableViewCell = tableView.dequeueReusableCell(withIdentifier: "cell") as! subCategoryTableViewCell
cell.backgroundImageView.image = UIImage(named: "ic_placeholder.png")
//NetworkManager.sharedInstance.getImageFromUrl(imageUrl:(subCategoryMenuData[indexPath.row] as AnyObject).thumbnail , imageView: cell.backgroundImageView)
cell.categoryName.text = (subCategoryMenuData [indexPath.row] as? String)
cell.categoryName?.textColor = UIColor().HexToColor(hexString: REDCOLOR)
cell.selectionStyle = .none
//cell.textLabel?.text = (subCategoryMenuData [indexPath.row] as? String)
//let imageFilter = UIImageView(frame: CGRect(x:SCREEN_WIDTH - 60, y: 10, width: 30, height: 30))
//cell.accessoryType = .disclosureIndicator
//cell.addSubview(imageFilter)
return cell
}
I tried changing the numberofSections and numberofRowsinSections, none of them have worked. Any solutions please?
Is it possible to get 2 columns in 1 row using UITableView instead of using UICollectionView
Basically, no. UICollectionView basically is nothing but a generalization of UITableView, allowing you to transcend its limitations. UITableView is one vertically scrolling column of single cells; that's all. If you want more than that, step up to UICollectionView.
class InfotableViewController: UIViewController,UITableViewDelegate,UITableViewDataSource{
let myActivityIndicator = UIActivityIndicatorView()
var name = [String]()
var imagearray=[UIImage]()
#IBOutlet weak var table: UITableView!
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 150
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = table.dequeueReusableCell(withIdentifier: "cell") as! profileTableViewCell
cell.tableimage.image = nil;
cell.tableimage.image = imagearray[indexPath.row] as! UIImage
cell.tablelabel.text = name[indexPath.row] as! String
self.myActivityIndicator.stopAnimating()
return cell
}
You should do this,
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 100
}
and this,
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = table.dequeueReusableCell(withIdentifier: "cell") as! profileTableViewCell
cell.tableimage.image = nil;
let index = indexPath.row%5
cell.tableimage.image = imagearray[index] as! UIImage
cell.tablelabel.text = name[indexPath.row] as! String
self.myActivityIndicator.stopAnimating()
return cell
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell1")
cell?.textLabel?.text = (list1[indexPath.row % list1.count]
cell?.imageView?.image = (list1[indexPath.row % list1.count]
return cell!
}
I am trying to download image from server and want to load images inside my cell but as i am downloading inside cellForRowAt method it wont get height for the first time. If i scroll up and scroll down again the image will have proper height.
Using Kingfisher to download images from server
var homeList = [NSDictionary]()
var rowHeights : [Int:CGFloat] = [:]
func numberOfSections(in tableView: UITableView) -> Int
{
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return homeList.count
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return 100
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if let height = self.rowHeights[indexPath.row]{
print(" Height \(height)")
return height
}
else{
return 160
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let homeObject = homeList[safe: indexPath.row] {
if let dynamicURL = homeObject["dynamic_card_url"] as? String, dynamicURL != "" {
tableView.register(UINib(nibName: "DynamicCell", bundle: nil), forCellReuseIdentifier: "\(indexPath.row)")
let cell = tableView.dequeueReusableCell(withIdentifier: "\(indexPath.row)", for: indexPath) as! DynamicCell
KingfisherManager.shared.downloader.downloadImage(with: URL(string: dynamicURL)!, options: .none, progressBlock: nil, completionHandler: { (image, error, url, data) in
DispatchQueue.main.async {
if (image != nil || url != nil){
let aspectRatio = (image! as UIImage).size.height/(image! as UIImage).size.width
cell.dynamicImageView.image = image
let imageHeight = self.view.frame.width*aspectRatio
self.rowHeights[indexPath.row] = imageHeight
}else{
print("Image or URL is nil")
}
}
})
cell.selectionStyle = .none
cell.backgroundColor = UIColor.clear
return cell
}
}
}
When you downloaded your image you should reload your cell to change it size to appropriate one. You get right sizes as you scrolling because tableView calls heightForRowAt when it needs to display new cell. So inside in DispatchQueue.main.async { reload the cell after setting all necessary properties UITableView().reloadRows(at: [IndexPath], with: UITableViewRowAnimation.automatic)
I used this guys suggestion: https://stackoverflow.com/a/33499766/8903213
code:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
cell.imageView?.kf.setImage(with: URL(string: urlOfPhoto)!, placeholder: PlaceholderImages.user, completionHandler: {
(image, error, cacheType, imageUrl) in
cell.layoutSubviews()
})
...
and this seems to be working for me.
I'm new to swift and working on a project in Swift 3.0 where I have a UITableView with three custom cells. In the first one I just have a image,button and a label. In the second one I have an image plus a label along with expandable and collapsible headers.Thus I have three different sections for this second cell. And lastly the third one is also contains just a label. In the first cell the UILabel is set underneath the image which contains a description about a person (constraints are been set). My requirement is only for the first cell dynamically adjust the cell size based on the size of the description. Help would much appreciate, the code as bellow.
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
print("Number of Sections: \(section)")
return arrayForTableView[section]
}
func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
let headerView : UITableViewHeaderFooterView = view as! UITableViewHeaderFooterView
headerView.contentView.backgroundColor = UIColor.yellow.withAlphaComponent(1.0)
}
func tapped(sender: UITapGestureRecognizer)
{
if let tag = sender.view?.tag{
expanedSections[tag] = !expanedSections[tag]
}
tableView.reloadData()
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = UITableViewHeaderFooterView()
headerView.tag = section
let tapRecog = UITapGestureRecognizer(target: self, action: #selector(tapped))
tapRecog.numberOfTapsRequired = 1
tapRecog.numberOfTouchesRequired = 1
tapRecog.delegate = self
headerView.addGestureRecognizer(tapRecog)
return headerView
}
func numberOfSections(in tableView: UITableView) -> Int {
return arrayForTableView.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
switch section {
case 0:
return 1
case 1:
return expanedSections[section] ? getItemsForSection(self.tableData.freeGifts): 0
case 2:
return expanedSections[section] ? getItemsForSection(self.tableData.exclusiveOffers) : 0
case 3:
return expanedSections[section] ? getItemsForSection(self.tableData.allAudios) : 0
case 4:
return expanedSections[section] ? getItemsForSection(self.tableData.testamonials) : 0
default:
return 0
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// var cell: UITableViewCell?
print("Section : \(indexPath.section) : \(indexPath.row)")
switch indexPath.section {
case 0:
let cell = tableView.dequeueReusableCell(withIdentifier: "HealerDetailsCell", for: indexPath) as! HealerDetailsTableViewCell
//cell.aboutLabel.preferredMaxLayoutWidth = (tableView.bounds)
cell.aboutLabel.sizeToFit()
populateHealerDetails.populateTable(cell, self.tableData.healerDetails)
return cell
case 1:
if tableData.freeGifts.count > 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "OffersCell",for: indexPath)
PopulateHealerDetailsAndOffers.populateTable(cell, self.tableData.freeGifts[indexPath.row] as! NSDictionary)
return cell
} else {
let cell = UITableViewCell(style: .default, reuseIdentifier: "Cell")
cell.textLabel?.text = "No Free Gifts At This Time"
return cell
}
case 2:
if tableData.exclusiveOffers.count > 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "OffersCell",for: indexPath)
PopulateHealerDetailsAndOffers.populateTable(cell, self.tableData.exclusiveOffers[indexPath.row] as! NSDictionary)
return cell
}else {
let cell = UITableViewCell(style: .default, reuseIdentifier: "Cell")
cell.textLabel?.text = "No Exclusive Offers At This Time"
return cell
}
case 3:
if tableData.allAudios.count > 0{
let cell = tableView.dequeueReusableCell(withIdentifier: "OffersCell",for: indexPath)
PopulateHealerDetailsAndOffers.populateTable(cell, self.tableData.allAudios[indexPath.row] as! NSDictionary)
return cell
}else{
let cell = UITableViewCell(style: .default, reuseIdentifier: "Cell")
cell.textLabel?.text = "NO Audios To Display"
return cell
}
case 4:
if tableData.testamonials.count > 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "TestamonialsCell", for: indexPath)
return cell
}else{
let cell = UITableViewCell(style: .default, reuseIdentifier: "Cell")
cell.textLabel?.text = "No Testamonials"
return cell
}
default:
let cell = tableView.dequeueReusableCell(withIdentifier: "TestamonialsCell", for: indexPath)
return cell
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
//let indexPath = tableView.indexPathForSelectedRow!
//let currentCellValue = tableView.cellForRow(at: indexPath)! as UITableViewCell
}
1.Set the constraint of label.
2.Put numberOflines is equal to 0(Through storyboard or programmatically)
Add this code in viewDidLoad:
tableView.estimatedRowHeight = 300
tableView.rowHeight = UITableViewAutomaticDimension
Use this delegate method
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
For version >= iOS 8
override func viewDidLoad()
{
self.tableView.rowHeight = UITableViewAutomaticDimension;
self.tableView.estimatedRowHeight = 44.0; // set to whatever your "average" cell height is
}
Steps to set constraints on storyboard:here
Important
If multiple lines labels, don't forget set the numberOfLines to 0.
Don't forget label.preferredMaxLayoutWidth =
CGRectGetWidth(tableView.bounds)
I think you want to expand/elapse UITableViewCell depending on the data each cell would have at runtime. I suppose, you already have implemented all of the first aid options regarding UITableView in swift.
Please try this method, which will always be called when your each cell is loaded.
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
//CellAnimator.animateCell(cell: cell, withTransform: CellAnimator.TransformWave, andDuration: 1)
//This commented line possibly might not be your requirement.
//But this is actually used to animate cell while loading.
//You can try some constraints or cell height related stuff here which would definitely work for each cell differently.
//Try calling cell specific loads either.
tableView.scrollToRow(at: indexPath as IndexPath, at: .none, animated: true)
/*let indexPath = IndexPath(item: (selectedCellIndexPath?.row)!, section: 0)
tableView.reloadRows(at: [indexPath], with: .none)
checkTrue = true
*/
}
Please check out this:
import UIKit
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var tableView: UITableView!
var tableViewDataSource = ["fewhf wfh wf wfw h dfw \n\n wufhw f ewfw wf w \n\n f wefe wfef w","fewhf wfh wf wfw h dfw \n\n wufhw f ewfw wf w \n\n f wefe wfef w",
"fewhf wfh wf wfw h dfw \n\n wufhw f ewfw wf w \n\n f wefe wfef w",
"fewhf wfh wf wfw h dfw \n\n wufhw f ewfw wf w \n\n f wefe wfef w"
]
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
tableView.delegate = self
tableView.dataSource = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//Tableview
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tableViewDataSource.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CellHere") as! TableViewCellHere
cell.cellHere.text = tableViewDataSource[indexPath.row]
cell.cellHere.textAlignment = .justified
return cell
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.row == 0 || indexPath.row == 1
{
return 120.0
}
else
{
return 50.0
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.row == 0 || indexPath.row == 1
{
return 120.0
}
else
{
return 50.0
}
}
}
This is working for me like this:
enter image description here