I know that adjusting UILabel height and UITableViewCell is probably a pretty standard issue, but I'm finding lots of answers that are based on the storyboard and inspectors, but not by just using Swift 3. I've created a table which covers the screen. The height for the cell is being determined as follows:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
My tableViewCell has a couple of objects in it, a UIImageView (myImage) and a UILabel (myText), set-up in a custom class. The positioning and sizing takes place in cellForRowAt.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! CustomCell
cell.myImage.image = UIImage(named: "MyImage")
cell.myImage.layer.frame = CGRect(origin: CGPoint(x: 0, y: 10), size: (cell.myImage?.image?.size)!)
cell.myText.text = myArray[indexPath.row]
cell.myText.frame = CGRect(x: UIScreen.main.bounds.size.width * 0.25, y: 0, width: UIScreen.main.bounds.size.width * 0.7, height: 90)
cell.myText.numberOfLines = 0
return cell
}
The result is a bunch of stacked cells, overlapping each other. What should I do to adjust the height of the UILabel frame to the amount of text coming from myArray and adjust the cell height so that it's at least the height of myImage or myText?
You can make multiline label inside table view in Swift 3.
import UIKit
private let useAutosizingCells = true
class TableViewController: UITableViewController {
fileprivate let cellIdentifier = "Cell"
// MARK: - Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
//setup initial row height here
if useAutosizingCells && tableView.responds(to: #selector(getter: UIView.layoutMargins)) {
tableView.estimatedRowHeight = 44.0
tableView.rowHeight = UITableViewAutomaticDimension
}
}
// MARK: - UITableViewDataSource
extension TableViewController {
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return detailsModel.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath)
let details = detailsModel[indexPath.row]
cell.textLabel?.text = details.title
cell.detailTextLabel?.text = details.description
if useAutosizingCells && tableView.responds(to: #selector(getter: UIView.layoutMargins)) {
cell.textLabel?.numberOfLines = 0
cell.detailTextLabel?.numberOfLines = 0
}
return cell
}
}
Related
I have a UITableViewController, which has a custom cell that I want to display an image and labels. screenshots can explain my problem very well, it looks like this
.
And when I select any cell it looks like
In tableviewcontroller cell is not visible in proper shape according to constraints
here is my custom cell with autolayout constraints
How I can fix this issue? ... I created this tableviewcontroller programmatically without using storyboard.
here is code sample of data source and delegates of tableviewcontroller
override func numberOfSections(in tableView: UITableView) -> Int {
var numOfSections: Int = 0
let count = conversations.count
if count > 0 {
// tableView.separatorStyle = .none
numOfSections = 1
tableView.backgroundView = nil
}
else
{
let frame = CGRect(x: 0,
y: 0,
width: tableView.bounds.size.width,
height: tableView.bounds.size.height)
let noDataLabel: UILabel = UILabel(frame: frame)
noDataLabel.text = "You don't have any messages. 🙃"
noDataLabel.textColor = UIColor.black
noDataLabel.textAlignment = .center
tableView.backgroundView = noDataLabel
tableView.separatorStyle = .none
}
return numOfSections
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return conversations.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "inboxCell", for: indexPath) as! InboxCell
cell.conversation = conversations[indexPath.row]
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let uids = conversations[indexPath.row].conversationUseruids
for uid in uids{
if uid == Account.account.user.uid{
}
else{
User.getUser(with: uid, completion: { (user) in
self.selectedUser.append(user!)
})
}
}
tableView.deselectRow(at: indexPath, animated: true)
let index = indexPath.row as Int
messageVC.conversationIndex = index
messageVC.conversation = self.conversations[index]
navigationController?.pushViewController(messageVC, animated: true)
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 80
}
it happen because your image not have upper lower constraint if not working than let me know
I have a tableView on mainStoryboard with two custom cells. I would like to reduce the spacing between two cells.
I was trying to find the answer but could not find any. I have image and code added below.
class HomeViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, MFMailComposeViewControllerDelegate {
#IBOutlet var tblStoryList: UITableView!
var array = PLIST.shared.mainArray
override func viewDidLoad() {
super.viewDidLoad()
//spacing between header and cell
self.tblStoryList.contentInset = UIEdgeInsetsMake(-20, 0, 0, 0)
//delete separator of UITableView
tblStoryList.separatorStyle = .none
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.array.count + 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "HeaderCell", for: indexPath) as! HeaderCell
cell.headerTitle.text = "First Stage"
return cell
}
let cell = tableView.dequeueReusableCell(withIdentifier: "StoryTableviewCell", for: indexPath) as! StoryTableviewCell
//making plist file
let dict = self.array[indexPath.row - 1]
let title = dict["title"] as! String
let imageName = dict["image"] as! String
let temp = dict["phrases"] as! [String:Any]
let arr = temp["array"] as! [[String:Any]]
let detail = "progress \(arr.count)/\(arr.count)"
//property to plist file
cell.imgIcon.image = UIImage.init(named: imageName)
cell.lblTitle.text = title
cell.lblSubtitle.text = detail
cell.selectionStyle = UITableViewCellSelectionStyle.none
return cell
}
header cell
import UIKit
class HeaderCell: UITableViewCell {
#IBOutlet weak var headerTitle: UILabel!
override func layoutSubviews() {
super.layoutSubviews()
headerTitle.layer.cornerRadius = 25
headerTitle.layer.masksToBounds = true
}
}
I think you have set some static height to the cells in heightForRowAt indexPath method, set it to UITableViewAutomaticDimension. and estimatedHeightForRowAt indexPath set it to static value for better performance.
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return 40 //expected minimum height of the cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
And not to forget that you need to set "correct constraints" to get the desired result by this method. Constraints are required to let know the table cell about its height.
Try this..
self.tableView.rowHeight = 0; // in viewdidload
[self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone]; // in viewdidload
-(CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section{
return 0.01f;
}
-(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{
return <your header height>;
}
-(UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section{
return [[UIView alloc] initWithFrame:CGRectZero];
}
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{
return <your header view>;
}
Also have table seprator as none.
You need to return height for each cell accordingly . for example
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.row == 0 {
// return height for first row, i.e
return 40
}
// return height for other cells. i.e
return 90
}
You can set table each and every cell height dynamic with Autolayout table view will take cell hight from Autolayout
for that you dont need write this 2 method
Remove this method
tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) ->
CGFloat
{
}
Write this 2 line in ViewDidload method
self.tblView?.rowHeight = UITableViewAutomaticDimension
self.tblView?.estimatedRowHeight = 60
And set your imageview bottom space with Autolayout that you want to keep for example 10 and set relation of bottom layout is greater then or equal and set priority is 252 instead of 1000
You will get clear idea about this in my screen shot check that as well how to do this Do this in all custom cell this way you can set height dynamic no need to calculate height of each and every cell and not need to return
I need an auto scrolling Image slider in top of viewcontroller followed by list of some entities(dynamic cells with image and title). To implement that I have taken a uitableview and I'm adding scrollview to my first cell, and my code is as follows
public func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.row == 0{
return 200
}
else {
return 50
}
}
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 20
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
if indexPath.row == 0 {
let sv = UIScrollView(frame: CGRect(x: 0, y: 0, width: cell.frame.width, height: cell.frame.height))
sv.auk.show(url: "url for image1")
sv.auk.show(url: "url for image2")
cell.addSubview(sv)
print("inside if")
}
else {
print("else")
cell.textLabel?.text = "cool"
}
return cell
}
I'm using this repository to create image slider which creates slider on a scrollview, So for first cell I have added scrollview. But as you can see in the picture the image slider reappears on multiple rows. Please tell me what is the mistake that I'm doing.In case if there is any better approaches please suggest .
Try taking a separate class for dynamic cells. Dequeue both the cells (static and dynamic cells) in the cellForRow method as follows:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return indexPath.row == 0 ? 200 : 50
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return 20 }
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
scrollViewWidth = cell.frame.width
scrollViewHeight = cell.frame.height
let scrollView = prepareScrollView(width: scrollViewWidth, height: scrollViewHeight)
cell.addSubview(scrollView )
print("First row")
return cell
}
else {
let myCustomCell: MyCustomTableViewCellClass = tableView.dequeueReusableCell(withIdentifier: "MyCustomTableViewCellIdentieier", for: indexPath) as! MyCustomTableViewCellClass
myCustomCell.textLabel?.text = "Cool"
print("Other dynamic rows")
return myCustomCell
}
}
func prepareScrollView(_ width: Float, height: Float) -> UIScrollView {
let scrollViewFrame = CGRect(x: 0, y: 0, width: width, height: height)
let scrollView = UIScrollView(frame: scrollViewFrame)
scrollView.auk.show(url: "url for image1")
scrollView.auk.show(url: "url for image2")
return scrollView
}
Take a separate class as MyCustomTableViewCellClass of type UITableViewCell and subclass your dynamic cell with this class. Don't forget to give cell identifier as "MyCustomTableViewCellIdentieier"
After this, your static cell will dequeue only once and no chances od repeating UI elements
You can try this code in your table view cell class -
override func prepareForReuse() {
//set your lable and image view to nil
}
SideMenuTVCell is a my custom UITableViewCell class -
Hope like this you have your own class within this class you add prepareForReuse() method -
class SideMenuTVCell: UITableViewCell {
#IBOutlet weak var iconIView: UIImageView!
#IBOutlet weak var lblTitle: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
override func setHighlighted(_ highlighted: Bool, animated: Bool) {
super.setHighlighted(highlighted, animated: animated)
}
override func prepareForReuse() {
//set your lable and image view to nil
self.iconIView.image = nil
self.lblTitle.text = nil
}
}
I have a problem: I have UITableView with UITableViewCell, at cell I have UICollectionView with a different number UICollectionViewCell. I want to UITableViewCell height corresponds to the height of UICollectionView.
I see real height UICollectionView here:
class TimeViewCell: UITableViewCell {
#IBOutlet weak var labelTime: UILabel!
var dataForShow = [String]() {
didSet{
self.collectionView?.reloadData()
}
}
#IBOutlet weak var collectionView: UICollectionView!
override func awakeFromNib() {
super.awakeFromNib()
collectionView.delegate = self
collectionView.dataSource = self
}
}
extension TimeViewCell: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return dataForShow.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionCell", for: indexPath) as! CustomCollectionCell
cell.labelCollection.text = dataForShow[indexPath.row]
let realValueHeightOfCollection = collectionView.contentSize.height
//when print realValueHeightOfCollection I see 50.0 (if dataForShow.count <4) or 110.0 (if dataForShow.count >5)
return cell
}
}
but how to pass that height to height UITableViewCell?
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellTime", for: indexPath) as! TimeViewCell
let showHour = self.infoWripper.sorted(by: { $0.hour < $1.hour })[indexPath.row]
cell.labelTime.text = showHour.showHour()
cell.dataForShow = showHour.showFullTime()
//here may be set the height of cell?
return cell
}
upd Storyboard:
I Have an approach for you:
I used this in my code and m sharing with you
in TableView height method:
// MARK: - TableView Delegate Methods:
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
var height: CGFloat = 0.0
// // //print("arrTA[indexPath.row] = \(arrTA[indexPath.row])")
let dict = arrTA[indexPath.row] as! NSDictionary
let str = dict[ISSELECTED] as! String
let strFlage = dict[FLAGE] as! String
let arrFileCount = dict[DATA]!["file_list"] as! NSArray//dict.objectForKey(DATA)?.objectForKey("file_list").count as NSMutableArray
if(strFlage == "MA") {
height = 50.0
} else {
height = self.setExpandedViewHeight(arrFileCount.count) + 0.0
}
return height
}
And I used this function in managing height:
func setExpandedViewHeight(intArrCount: Int) -> CGFloat {
var height: CGFloat = 0.0
var generatedHeight: Int = 0
generatedHeight = intArrCount / 3 /// We get number of rows
if(intArrCount % 3 == 0) {
height = CGFloat(generatedHeight) * 100
} else {
height = (CGFloat(generatedHeight) + 1 ) * 100
}
return height
}
I hope you will read and debug the code at your end and execute it.
I decided my problem by adding one line:
tableTime.rowHeight = cell.collectionView.collectionViewLayout.collectionViewContentSize.height
in func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {...}
If you are using autolayout then you can try this...
self.tableView.estimatedRowHeight = <estimatedRowHeight>;
self.tableView.rowHeight = UITableViewAutomaticDimension;
UITableViewAutomaticDimension will work if you've set leading, trailing, bottom, and top constraints relative to cell container view.
estimatedRowHeight : set this value with possible row height.
When you have set these properties, you neither need to implement heightForRowAtIndexpath nor estimatedRowHeight.
I have a TableView, and the table is populated from an array. The cell is of type TableViewCell.xib. I want to change the colour of the label in the cell.
Here's my TableViewController
struct cell_data {
let label1: String!
}
class TableViewController: UITableViewController {
let cellDataArray = [cell_data]([cell_data(label1: "This text is for label 1")])
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return cellDataArray.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = Bundle.main.loadNibNamed("TableViewCell", owner: self, options: nil)?.first as! TableViewCell
cell.label_1.text = cellDataArray[indexPath.row].label1
cell.selectionStyle = .none
let whiteRoundedView : UIView = UIView(frame: CGRect(x:10, y:5, width: self.view.frame.size.width - 20, height: cell.frame.size.height - 7))
whiteRoundedView.layer.backgroundColor = UIColor.green.cgColor
whiteRoundedView.layer.masksToBounds = false
whiteRoundedView.layer.shadowOffset = CGSize(width: -1, height: 1)
whiteRoundedView.layer.shadowOpacity = 0.3
cell.contentView.addSubview(whiteRoundedView)
cell.contentView.sendSubview(toBack: whiteRoundedView)
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath)
}
override func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath)
}
}
What I want to do be able to do is change the colour of the label of the cell when I select a row without affecting the UIView inside the cell. That is, once I change the height of the UIView when I select a row, I have tried reloading but reloading the cell set the UIView's height to the original setting.
And once I have set the label's colour, I want to set it back to it's original colour when I deselect the row.
I hope I made it clear enough. Thanks in advance.
You don't need to reloading the cell to update the label's color. You can try by overriding method in your TableViewCell with the following code:
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
if (selected) {
//Change your label color for selected state
} else {
//Change your label color for unselected state
}
}
try this:
func tableView(tableView: UITableView, didHighlightRowAtIndexPath indexPath: NSIndexPath)
{
let cell = tableView.cellForRowAtIndexPath(indexPath)! as! customTableViewCell // name of your custom cell class
cell.label_1.backgroundColor = UIColor.whiteColor()//give your selection color
}
Try this
override func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath) as yourCell
cell.yourlable.textcolor = yourColor;
}