Swift TableView Cell [closed] - swift

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
I am trying to create tableView cells and customize the layout. But it seems anything I add inside my cells get stuck being the same size height and width as the cell itself. How can I make it to where I can design my cells however I like? i.e, make my images a specific size with margins and paddings. Even my text height is being stretched out to the cells height. I added the borders so that it's visible for what I mean. The height of my label should be just the size of the text itself but it is still stretching.
I am stuck on tableview cells and want to design my cell layout fully programmatically without storyboarding. I've been trying to teach myself all day and just keep going in circles.
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
let tableView = UITableView()
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
self.tableView.delegate = self
self.tableView.dataSource = self
self.view.addSubview(self.tableView)
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
tableView.frame = view.bounds
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 200
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 8
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = "Here is some text"
cell.textLabel?.layer.cornerRadius = 10
cell.textLabel?.layer.borderWidth = 5
cell.textLabel?.layer.borderColor = UIColor.black.cgColor
cell.imageView?.image = UIImage(named: "spiderman")!
cell.imageView?.layer.cornerRadius = 10
cell.imageView?.layer.borderWidth = 5
cell.imageView?.layer.borderColor = UIColor.black.cgColor
return cell
}
}

Thats because you are using UITableViewCell's default textLabel
If you open a storyboard and play around with cell with 'basic' style, you will see that the text is always aligned to center.
I dont think you can adjust height or position of these two predefined properties (.textLabel and .imageView) directly.
Try to create imageView and label manually, and dont use cell.textLabel directly.
Example:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
let label = UITextView(frame: CGRect(x: 200, y: 0, width: 500, height: 50))
label.text = "Here is some text"
label.layer.cornerRadius = 10
label.layer.borderWidth = 5
label.layer.borderColor = UIColor.black.cgColor
cell.addSubview(label)
let image = UIImage(named: "spiderman")!
let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
imageView.image = image
imageView.layer.cornerRadius = 10
imageView.layer.borderWidth = 5
imageView.layer.borderColor = UIColor.black.cgColor
cell.addSubview(imageView);
return cell
}

Related

TableviewCell: set constraints programmatically inside ContentView using autoresize

I am trying to constraint elements (UIView or UITextfield) in a TableViewCell. If i am using a frame like
UITextField(frame: CGRect(x: 150, y: 0, width: 500, height: 110))
everything works fine.
But i am trying to use autoresize and somehow my UITextfield added as SubView in my Cell don't have the same ancestor. The error message is: "they have no common ancestor. Does the constraint or its anchors reference items in different view hierarchies?"
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var Testtext: UITextField{
let test = UITextField(frame: CGRect(x: 150, y: 0, width: 500, height: 110))
test.textColor = .red
test.font = .boldSystemFont(ofSize: 22)
test.text = "Hello World"
return test
}
var cell:UITableViewCell {
let createdCell = UITableViewCell()
createdCell.contentView.addSubview(Testtext)
// Testtext.translatesAutoresizingMaskIntoConstraints = false
// NSLayoutConstraint.activate([
// Testtext.topAnchor.constraint(equalTo: createdCell.topAnchor),
// Testtext.bottomAnchor.constraint(equalTo: createdCell.bottomAnchor),
// Testtext.trailingAnchor.constraint(equalTo: createdCell.trailingAnchor),
// Testtext.leadingAnchor.constraint(equalTo: createdCell.leadingAnchor)
// ])
return createdCell
}
BTW: I don't want to create a Cellclass, because i need to adjust the number of Textfields and UIViews depending on the input arrayscount.
You need
var cell:UITableViewCell {
let createdCell = UITableViewCell()
createdCell.contentView.addSubview(Testtext)
Testtext.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
Testtext.topAnchor.constraint(equalTo: createdCell.contentView.topAnchor),
Testtext.bottomAnchor.constraint(equalTo: createdCell.contentView.bottomAnchor),
Testtext.trailingAnchor.constraint(equalTo: createdCell.contentView.trailingAnchor),
Testtext.leadingAnchor.constraint(equalTo: createdCell.contentView.leadingAnchor)
])
return createdCell
}
but this isn't the correct way you need to dequeueResuableCell inside cellForRowAt to generate the cells instead of creating vars
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! CustomCell
return cell
}

Why is the width of cell in UItableview not same as width of screen in simulator?

The table cell is running shorter than it is supposed to be. (I use different background colour which shows difference width) The setting of cell is custom (only row height is change to 140). The playerCell class has nothing but some IBoutlets. Thanks.
(image: storyboard
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
var count: Int
if playerBank.count == 0
{
count = 1
}
else{
count = playerBank.count
}
return count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! playerCell
if playerBank.isEmpty{
let p = Player()
playerBank = setInvalidPlayer(pBank: p, userInput: userInputPlayerName)
}
let playerInBank: Player = playerBank[indexPath.row]
passImageUrl = cell.setPlayerCell(p: playerInBank)
urlBank.append(passImageUrl)
let bgColorView = UIView()
bgColorView.backgroundColor = UIColor.red
cell.selectedBackgroundView = bgColorView
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
myIndex = indexPath.row
DispatchQueue.main.async {
self.performSegue(withIdentifier: "ShowPlayerInfo", sender: self)
}
}
My first guess is that, while you have a custom cell with custom outlets, that there are no layout constraints in place. So the items that you put into the storyboard are retaining their intrinsic values and not adapting to the device screen size.
If you add constraints to those outlets, especially enough to where the width of the cell can be determined based on the rest of the elements, then your cell should display full width.

Add view dynamically to cells produce issues in table

I have this function:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier)!
let label = UILabel(frame: CGRect(x: 100, y: 14, width: 400, height: 30))
label.text = "\(data[indexPath.row])"
label.tag = indexPath.row
cell.contentView.addSubview(label)
return cell
}
Well, with this function I'm adding a list of rows dynamically.
Why dynamically? Because, the number of columns depends of the data.
Don't take focus on that.
The list has 244 elements.
The result is displayed ok, but once I started scrolling, I get this:
How I can add elements dynamically without get this error?
Cells get reused. You keep adding more and more labels to each cell.
The proper solution is to create a custom cell class that contains the desired label. Then simply set that label's text in cellForRowAt. Don't create and add subviews in cellForRowAt.
But keep in mind that you may just want to use the provided textLabel property of UITableViewCell. No need for a custom cell or your own label.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier)!
cell.textLabel?.text = "\(data[indexPath.row])"
return cell
}
I found a solution, hope this works to you!!!
You have to add to your cellForRowAt this code:
for item in cell.contentView.subviews
{
item.removeFromSuperview()
}
Just after to get the cell.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier)!
for item in cell.contentView.subviews
{
item.removeFromSuperview()
}
let label = UILabel(frame: CGRect(x: 100, y: 14, width: 300, height: 30))
label.text = "\(data[indexPath.row])"
label.tag = indexPath.row
let btn = UIButton(type: UIButtonType.custom) as UIButton
btn.backgroundColor = UIColor.red
btn.setTitle("boton", for: .normal)
btn.frame = CGRect(x:0, y:5, width: 80, height:40)
//btn.addTarget(self, action: "buttonPressed:", for: UIControlEvents.touchUpInside)
btn.tag = indexPath.row
cell.contentView.addSubview(btn)
cell.contentView.addSubview(label)
cell.tag = indexPath.row
return cell
}
UITableview create 10 cell at scroll down recreate cell view
You can using
cell.contentView.removeFromSuperview() before cell.contentView.addSubview(label) or using cell.textLabel?.text
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier)!
cell.contentView.removeFromSuperview()
let label = UILabel(frame: CGRect(x: 100, y: 14, width: 400, height: 30))
label.text = "\(data[indexPath.row])"
label.tag = indexPath.row
cell.contentView.addSubview(label)
return cell
}
Note This solution will delete All subview in cell

Swift: UIButton edgeinsets applies after cell redrawn/scroll

after couple of days struggling I wanted to ask you about UIButton title and image edge insets...
I have custom cell with button and on that button depends on cell type should be different icons and text but the requirement text should be centered and image could be left aligned or right. For that I'm setting edge insets during updating button tile and image. To keep it simple I hard coded image insets left to be 8 and the calculating left point of title from which text should start.
func setTitleWithImage(_ title: String, imageName: String) {
self.btnStatus.setTitle(title, for: .normal)
self.btnStatus.setImage(UIImage(named: imageName), for: .normal)
self.btnStatus.imageEdgeInsets.left = 8
let btnWidth = btnStatus.frame.width
let titleLabelWidth = btnStatus.titleLabel?.frame.width
self.btnStatus.titleEdgeInsets.left = (btnWidth / 2) - (titleLabelWidth! / 2) - (btnStatus.imageView?.frame.width)! + self.btnStatus.imageEdgeInsets.left
}
The problem is that when tableview loaded it is wrong aligned but after scrolling/redraw cell it is aligned correctly. I tried different suggestions but no one helped me.
Before scroll
After scroll
To be more specific here the whole project.
Sources
UPDATED
ViewController almost all for more detailed please download sourrce
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 140
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCell(withIdentifier: "customCell", for: indexPath) as! CustomTableViewCell
cell.setTitleWithImage("DIFFERENT TEXT IS HERE ?", imageName: "icon")
cell.layoutIfNeeded()
cell.setNeedsLayout()
return cell
}
func alignTitleWithImageFrames () {
let btnWidth = btnStatus.frame.width
let titleLabelWidth = btnStatus.titleLabel?.frame.width
self.btnStatus.titleEdgeInsets.left = (btnWidth / 2) - (titleLabelWidth! / 2) - (btnStatus.imageView?.frame.width)! + 13
self.btnStatus.imageEdgeInsets.left = 8
}

How to remove UIView from the superView with specific position programmatically

I am new to swift, using swift 3, I built tableview that reads group of images and I want to have it as below:
when user select an image in the tableview I display it in an UIImageView and when Deselect an image he already selected in the tableview to be removed from the UIImageView ( Multiple Selection is enabled). My code below is working for one image selection only, however if multiple images are selected and then deselected the last selected one only removed from the UIImageview. So my question is how can I remove the UIImageview that belongs to the deselected record in the UItableview
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
image_view.image = UIImage(data: Saveddata[indexPath.row].photo as! Data)
//create image view programmatically
currentImageView = UIImageView(frame: CGRect(x: 130 + (i * 10), y: 50 + (i * 5), width: 50, height: 100))
currentImageView.contentMode = .scaleAspectFit
currentImageView.image = image_view.image
view.addSubview(currentImageView as UIView)
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
currentImageView.removeFromSuperview()
}
You could use tag for each UIImageView based on the indexPath.row so you could refer by tag.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let image = UIImage(data: Saveddata[indexPath.row].photo as! Data)
//create image view programmatically
let imageView = UIImageView(frame: CGRect(x: 130 + (i * 10), y: 50 + (i * 5), width: 50, height: 100))
imageView.contentMode = .scaleAspectFit
imageView.tag = 100 + indexPath.row
imageView.image = image
view.addSubview(imageView as UIView)
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
// get imageView by its tag
let deselectedImageView = view.viewWithTag(100 + indexPath.row) as! UIImageView
deselectedImageView.removeFromSuperview()
}
If you want to update your cell appearance when selected/deselected, you should override the method setSelected(_:animated:) inside your UITableViewCell subclass instead of trying to update it directly from your UITableViewDelegate method:
override func setSelected(_ selected: Bool, animated: Bool) {
// Do whatever you want depending on the selected value
}