Here's the file I'm using for the table view controller. When I run the project the cell shows the text that's written in "names" but it won't show all of it.
I want it to show the whole text in the same cell. That the cell is sized according to what's written in it.
How do I fix this?
import Foundation
import UIKit
class FTBViewController: UITableViewController {
var names = [String]()
var identities = [String]()
override func viewDidLoad() {
names = ["This is the text the cell is displaying but it won't show it all"]
identities = ["A"]
self.navigationItem.title = "Guía"
self.navigationController?.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName: UIColor.whiteColor()]
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return names.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("FCell")
cell?.textLabel!.text = names[indexPath.row]
return cell!
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let vcName = identities[indexPath.row]
let viewController = storyboard?.instantiateViewControllerWithIdentifier(vcName)
self.navigationController?.pushViewController(viewController!, animated: true)
}
}
add
cell?.textLabel!.numberOfLines = 0
cell?.textLabel!.lineBreakMode = .ByWordWrapping
cell?.textLabel!.font = UIFont.systemFontOfSize(14.0) // this is optional if you need use this
Full answer
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("FCell")
cell?.textLabel!.numberOfLines = 0
cell?.textLabel!.lineBreakMode = .ByWordWrapping
cell?.textLabel!.font = UIFont.systemFontOfSize(14.0)
cell?.textLabel!.text = names[indexPath.row]
return cell!
}
You could use following code in viewdidLoad :
tableView.estimatedRowHeight = 44.0
tableView.rowHeight = UITableViewAutomaticDimension
Hope so it helps...
Related
How do I make it such that when names2 is not equals to names, it will add the missing strings from names into the table view but with a different text style?
import UIKit
class TableViewController: UITableViewController {
var names = [String]()
var identities = [String]()
var names2 = [String]()
override func viewDidLoad() {
names = ["First", "Second", "Third", "Fourth"]
identities = ["A", "B", "C", "D"]
names2 = ["First", "Second"]
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return names.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell")
cell?.textLabel!.text = names[indexPath.row]
return cell!
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let vc = identities[indexPath.row]
let viewController = storyboard?.instantiateViewControllerWithIdentifier(vc)
self.navigationController?.pushViewController(viewController!, animated: true)
}
}
For images in collection view
import UIKit
class MedalViewController: UICollectionViewController {
var imagesArray = [String]()
var identities = [String]()
var identities2 = [String]()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
imagesArray = ["1", "2", "3"]
identities = ["Shield", "Tie", "Star"]
identities2 = ["Shield", "Tie"]
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("cell", forIndexPath: indexPath)
let imageView = cell.viewWithTag(1) as! UIImageView
imageView.image = UIImage(named: imagesArray[indexPath.row])
return cell
}
override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return imagesArray.count
}
override func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
let vc = identities[indexPath.row]
let viewController = storyboard?.instantiateViewControllerWithIdentifier(vc)
self.navigationController?.pushViewController(viewController!, animated: true)
viewController?.title = self.identities[indexPath.row]
}
}
How do I make it such that the missing identifier in this case "Star" in which its image is "3" is greyed out in the collectionsView?
You can check that names2 is contains names array object inside cellForRowAtIndexPath and then change the text style you want.
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell")
cell?.textLabel!.text = names[indexPath.row]
if (names2.contains(names[indexPath.row])) {
cell.textLabel.textColor = UIColor.blackColor() //Set other style that you want
}
else {
cell.textLabel.textColor = UIColor.redColor() //Set other style that you want
}
return cell!
}
Edit: I doesn't get properly about image but you could try some thing like this.
if (identities2.contains(identities[indexPath.row])) {
cell.imageView = UIImage(named: identities[indexPath.row])
}
else {
cell.imageView = UIImage(named: "DefaultGrayImage") //Set default image not in identities2
}
I have tableview and customized cell using swift. below is complete code:
class LeftMenuViewController: UIViewController {
let titles: [String] = ["Home", "Category", "Chat", "notification", "Flagger", "Feedback", "Setting", "Log Out"]
override func viewDidLoad() {
super.viewDidLoad()
let leftmenuView : LeftMenu = LeftMenu()
let nib = UINib(nibName: "LeftMenuCell", bundle : nil)
leftmenuView.tableMenu.registerNib(nib, forCellReuseIdentifier: "cell")
leftmenuView.tableMenu.dataSource = self
leftmenuView.tableMenu.delegate = self
leftmenuView.tableMenu.allowsSelection = true
leftmenuView.tableMenu.backgroundColor = UIColor.blackColor()
self.view.addSubview(leftmenuView)
}
}
extension LeftMenuViewController : UITableViewDelegate, UITableViewDataSource {
func tableView(tableMenu: UITableView, numberOfRowsInSection section: Int) -> Int {
return titles.count
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 40
}
func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
print("Clicked \(indexPath.row)")
switch indexPath.row {
case 0:
sideMenuViewController?.contentViewController = UINavigationController(rootViewController: HomeViewController())
sideMenuViewController?.hideMenuViewController()
break
case 1:
sideMenuViewController?.contentViewController = UINavigationController(rootViewController:CategoryViewController())
sideMenuViewController?.hideMenuViewController()
break
default:
break
}
}
func tableView(tableMenu: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell:LeftMenuCell = tableMenu.dequeueReusableCellWithIdentifier("cell") as! LeftMenuCell
cell.backgroundColor = UIColor.blackColor()
cell.menuName.text = titles[indexPath.row]
cell.menuName.textColor = UIColor.whiteColor()
return cell
}
}
But I am confused, my cell can not be clicked / tapped. I thought it needs a simple didDeselectRowAtIndexPath implementation? Even if I print inside that method, it is not writing out "Clicked".
So whats wrong in my code, can anybody help me?
Thanks
Change didDeselectRowAtIndexPath to didSelectRowAtIndexPath.
didSelect is called when the cell is tapped.
didDeselect is called on the first cell when another cell is selected.
If didDeselectRowAtIndexPath still not getting called check selection about be single selection , that should not be no selection.
Refer screen shot.
All views should have a non-zero frame. Try to add the next code into LeftMenuViewController:
override func viewDidLayoutSubviews {
super.viewDidLayoutSubviews()
leftmenuView.frame = self.view.bounds
}
Also it could be the same for tableView inside LeftMenu but using layoutSubviews method.
I'm adding an image to a table view row (actually, I seem to be adding it to the row's cell) when selecting it (and removing when selecting it again). The table view consists of prototype cells.
This works but when I scroll around and get back to the row I had previously selected, the image would be in another row. Also, the image appears in other rows as well.
My guess is this happens because the cells are re-used when scrolling.
Here's the code of a little sample project:
import UIKit
class MyTableViewController: UITableViewController {
// Using integers for simplicity, should work with strings, too.
var numbers = [Int]()
override func viewDidLoad() {
super.viewDidLoad()
for i in 0..<50 {
numbers.append(i)
}
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("TestCell", forIndexPath: indexPath)
cell.textLabel?.text = "\(numbers[indexPath.row] + 1)"
return cell
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return numbers.count
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let cell = tableView.cellForRowAtIndexPath(indexPath)!
if let myImage = curCell.viewWithTag(10) as? MyImage {
myImage.removeFromSuperview()
} else {
let myImage = myImage()
myImage.tag = 10
cell.addSubview(myImage)
}
}
I need to have the image stay in the correct row, also when coming back to this view controller. What's the correct way to tackle this?
Any advice much appreciated!
EDIT: I've tried to implement matt's answer but I seem to be missing something, as the problem is still the same.
EDIT 2: Updated, working as intended now.
import UIKit
class ListItem {
var name: String!
var showsImage = false
init(name: String) {
self.name = name
}
}
class MyTableViewController: UITableViewController {
var listItems = [ListItem]()
override func viewDidLoad() {
super.viewDidLoad()
for i in 0..<50 {
let listItem = ListItem(name: "row \(i)")
listItems.append(listItem)
}
}
// MARK: - Table view data source
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("TestCell", forIndexPath: indexPath)
cell.textLabel?.text = "\(listItems[indexPath.row].name)"
if listItems[indexPath.row].showsImage {
let myImage = myImage
myImage.tag = 10
cell.addSubview(myImage)
} else {
if let myImage = cell.viewWithTag(10) as? myImage {
myImage.removeFromSuperview()
listItems[indexPath.row].showsImage = false
}
return cell
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return listItems.count
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let cell = tableView.cellForRowAtIndexPath(indexPath)!
if let myImage = cell.viewWithTag(10) as? myImage {
myImage.removeFromSuperview()
listItems[indexPath.row].showsImage = false
} else {
listItems[indexPath.row].showsImage = true
tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .None)
}
}
}
EDIT 3: As matt suggested, here's an alternative solution to the code above which subclasses UITableViewCell instead of using a tag for the image.
import UIKit
class MyTableViewCell: UITableViewCell {
var myImage = MyImage()
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
myImage.hidden = true
addSubview(myImage)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
class ListItem {
var name: String!
var showsImage = false
init(name: String) {
self.name = name
}
}
class MyTableViewController: UITableViewController {
var listItems = [ListItem]()
override func viewDidLoad() {
super.viewDidLoad()
for i in 0..<50 {
let listItem = ListItem(name: "row \(i)")
listItems.append(listItem)
}
}
// MARK: - Table view data source
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return listItems.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = MyTableViewCell(style: .Default, reuseIdentifier: "TestCell")
cell.textLabel?.text = "\(listItems[indexPath.row].name)"
cell.myImage.hidden = !(listItems[indexPath.row].showsImage)
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let cell = tableView.cellForRowAtIndexPath(indexPath) as! MyTableViewCell
listItems[indexPath.row].showsImage = cell.myImage.hidden
cell.myImage.hidden = !cell.myImage.hidden
}
}
The problem is that cells are reused in other rows. When they are, cellForRowAtIndexPath is called again. But when it is, you are supplying no information about the image for that row.
The solution: fix your model (i.e. the info you consult in cellForRowAtIndexPath) so that it knows about the image. In didSelect, do not modify the cell directly. Instead, modify the model and reload the cell.
I'm creating an iOS app using swift. I want to build a non scrollable tableView which shows on screen all informations contained in datasource, so the height of each cell depends on the number of entries in data. For example, if the height of the view is 500 and data.count = 10, each cell's height is 50. A problem appears when the cell's height is ~100.8 (corresponding to 5 entries in my data, using my iPhone 5). In fact, even by setting tableView.separatorStyle = .None , a weird separator appears for this cell's height.
Below, the first image (7 entries in data) is normal and on the second (5 entries in data) those separators appear.
Here is my view controller :
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
let reuseIdentifier = "Cell"
var data = ["bobby", "bob", "john", "helena", "clara", "oliver", "steve"]
var visibleHeight:CGFloat!
override func viewDidLoad() {
super.viewDidLoad()
edgesForExtendedLayout = .None
tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: reuseIdentifier)
editModeOff()
tableView.scrollEnabled = false
visibleHeight = viewVisibleSize.height
tableView.separatorStyle = .None
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return data.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{
let cell = tableView.dequeueReusableCellWithIdentifier(reuseIdentifier, forIndexPath: indexPath)
cell.textLabel!.text = data[indexPath.row]
cell.selectionStyle = .None
return cell
}
func tableView(tableView: UITableView, moveRowAtIndexPath sourceIndexPath: NSIndexPath, toIndexPath destinationIndexPath: NSIndexPath) {
let stringToMove = data[sourceIndexPath.row]
data.removeAtIndex(sourceIndexPath.row)
data.insert(stringToMove, atIndex: destinationIndexPath.row)
}
func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == .Delete{
data.removeAtIndex(indexPath.row)
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Fade)
}
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
print(visibleHeight/CGFloat(data.count))
return visibleHeight/CGFloat(data.count)
}
func editModeOn(){
tableView.setEditing(true, animated: true)
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .Done, target: self, action: "editModeOff")
}
func editModeOff(){
tableView.setEditing(false, animated: true)
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .Edit, target: self, action: "editModeOn")
}
}
extension ViewController{
var viewVisibleSize:CGSize{
var size = view.bounds.size
if !UIApplication.sharedApplication().statusBarHidden{
size.height -= UIApplication.sharedApplication().statusBarFrame.height
}
if let navigationController = navigationController{
size.height -= navigationController.navigationBar.bounds.height
}
if let tabBarController = tabBarController{
size.height -= tabBarController.tabBar.bounds.height
}
return size
}
}
I always clear the color of the separator:
tableView.separatorColor = UIColor.clearColor()
I have found a dirty solution by setting :
cell.contentView.layer.borderWidth = 0.5
cell.contentView.layer.borderColor = UIColor.whiteColor().CGColor
in tableView:cellForRowAtIndexPath: method. But for sure, there is a better way...
In your viewDidLoad: you can try self.tableView.tableFooterView = UIView()
It is funny. Problem in your function tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat
It has strange behavior for some float numbers and a separator will appear.
I offer you round a returning height like this:
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
print(self.visibleHeight/CGFloat(self.tableArray.count))
let rett = self.visibleHeight/CGFloat(self.tableArray.count)
let convert = NSString(format: "%.0f", rett)
return CGFloat(convert.floatValue)
}
thanks for all the help so far. I need, when a cell in UITableView is clicked, to re-populate the view with an array read from another class - just can find a way to refresh the view. Code as follows:
Thanks in advance - the help so far has been great for this newbie.
import UIKit
class SecondViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet var tableView: UITableView!
let textCellIdentifier = "TextCell"
var catRet = XnYCategories.mainCats("main")
//var catRet = XnYCategories.subCats("Sport")
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
}
// MARK: UITextFieldDelegate Methods
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return catRet.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(textCellIdentifier, forIndexPath: indexPath) as! UITableViewCell
let row = indexPath.row
cell.textLabel?.text = catRet[row]
return cell
}
// MARK: UITableViewDelegate Methods
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
let row = indexPath.row
//let currentCell = tableView.cellForRowAtIndexPath(indexPath)
//var selectedText = currentCell!.textLabel?.text
//println(selectedText)
let catRet2 = XnYCategories.mainCats(catRet[row])
println(catRet2)
println(catRet[row])
//catRet = catRet2
}
}
Call reloadData() on your tableView as follow
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
let row = indexPath.row
//let currentCell = tableView.cellForRowAtIndexPath(indexPath)
//var selectedText = currentCell!.textLabel?.text
//println(selectedText)
let catRet2 = XnYCategories.mainCats(catRet[row])
println(catRet2)
println(catRet[row])
// *** New code added ***
// remove the comment
catRet = catRet2
// call reloadData()
tableView.reloadData()
// *** New code added ***
}
just do this:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
let row = indexPath.row
catRet = XnYCategories.mainCats(catRet[row])
tableView.reloadData()
}