Home > Software design >  Table View Design overlapping
Table View Design overlapping

Time:04-25

I am new to swift .I want to display the records with image view in table view cell . I have defined the property with leadingAnchor , trailingAnchor, widthAnchor, heightAnchor with content view . But when I run the app it overlapping the view .

Here is the code in cell .

import UIKit

class PeopleCell: UITableViewCell {

    
    static let identifier = "PeopleCell"
    
    let containerView:UIView = {
        let view = UIView()
        view.translatesAutoresizingMaskIntoConstraints = false
        view.clipsToBounds = true // this will make sure its children do not go out of the boundary
        return view
    }()
    
    let profileImageView:UIImageView = {
        let img = UIImageView()
        img.contentMode = .scaleAspectFill // image will never be strecthed vertially or horizontally
        img.translatesAutoresizingMaskIntoConstraints = false // enable autolayout
        img.layer.cornerRadius = 35
        img.clipsToBounds = true
        return img
    }()
    
    let firstnameTitleLabel:UILabel = {
        let label = UILabel()
        label.font = UIFont.boldSystemFont(ofSize: 20)
        label.textColor = .black
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()
    
    let lastnameTitleLabel:UILabel = {
        let label = UILabel()
        label.font = UIFont.boldSystemFont(ofSize: 14)
        label.textColor =  .white
        label.backgroundColor = #colorLiteral(red: 0.1764705926, green: 0.4980392158, blue: 0.7568627596, alpha: 1)
        label.layer.cornerRadius = 5
        label.clipsToBounds = true
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()

    
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        
        self.contentView.addSubview(profileImageView)
        containerView.addSubview(firstnameTitleLabel)
        containerView.addSubview(lastnameTitleLabel)
        self.contentView.addSubview(containerView)
         
        profileImageView.centerYAnchor.constraint(equalTo:self.contentView.centerYAnchor).isActive = true
        profileImageView.leadingAnchor.constraint(equalTo:self.contentView.leadingAnchor, constant:10).isActive = true
        profileImageView.widthAnchor.constraint(equalToConstant:70).isActive = true
        profileImageView.heightAnchor.constraint(equalToConstant:70).isActive = true
        
        containerView.centerYAnchor.constraint(equalTo:self.contentView.centerYAnchor).isActive = true
        containerView.leadingAnchor.constraint(equalTo:self.profileImageView.trailingAnchor, constant:10).isActive = true
        containerView.trailingAnchor.constraint(equalTo:self.contentView.trailingAnchor, constant:-10).isActive = true
        containerView.heightAnchor.constraint(equalToConstant:40).isActive = true
        
        firstnameTitleLabel.topAnchor.constraint(equalTo:self.containerView.topAnchor).isActive = true
        firstnameTitleLabel.leadingAnchor.constraint(equalTo:self.containerView.leadingAnchor).isActive = true
        firstnameTitleLabel.trailingAnchor.constraint(equalTo:self.containerView.trailingAnchor).isActive = true
        
        lastnameTitleLabel.topAnchor.constraint(equalTo:self.firstnameTitleLabel.bottomAnchor).isActive = true
        lastnameTitleLabel.leadingAnchor.constraint(equalTo:self.containerView.leadingAnchor).isActive = true
        lastnameTitleLabel.topAnchor.constraint(equalTo:self.firstnameTitleLabel.bottomAnchor).isActive = true
        lastnameTitleLabel.leadingAnchor.constraint(equalTo:self.containerView.leadingAnchor).isActive = true
        
        
    }
   
    
   required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    func configureCell(firstName: String, lastName: String) {
        firstnameTitleLabel.text = "Firstname :\(firstName)"
        lastnameTitleLabel.text = "Lastname : \(lastName)"
        
        }
        
    
    func configureImageCell(row: Int, viewModel: ViewModel) {
        
        profileImageView.image = nil
        
        viewModel
            .downloadImage(row: row) { [weak self] data in
                let image = UIImage(data: data)
                self?.profileImageView.image = image
            }
    }
}

Here is the view controller code .

import UIKit
import Combine

class PeopleViewController: UIViewController {
    
    var coordinator: PeopleBaseCoordinator?
    
    
    init(coordinator: PeopleBaseCoordinator) {
        super.init(nibName: nil, bundle: nil)
        self.coordinator = coordinator
        title = "People"
    }
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    private let viewModel = ViewModel()
    private var subscribers = Set<AnyCancellable>()
    
    
    var activityIndicator = UIActivityIndicatorView(style: .medium)
    
    
    private lazy var tableView: UITableView = {
        let tableview = UITableView()
        tableview.translatesAutoresizingMaskIntoConstraints = false
        tableview.dataSource = self
        tableview.prefetchDataSource = self
        tableview.showsVerticalScrollIndicator = false
        tableview.register(PeopleCell.self, forCellReuseIdentifier: PeopleCell.identifier)
        
        return tableview
    }()
    
   

    override func viewDidLoad() {
        super.viewDidLoad()
        
        activityIndicator.startAnimating()
        setUpUI()
       
        setUpBinding()
        self.activityIndicator.stopAnimating()
     
        // Do any additional setup after loading the view.
    }
    
    
    private func setUpUI() {
        view.backgroundColor = .white
        
        title = "People List "
        
      
        view.addSubview(tableView)
   
        tableView.topAnchor.constraint(equalTo:view.safeAreaLayoutGuide.topAnchor).isActive = true
        tableView.leftAnchor.constraint(equalTo:view.safeAreaLayoutGuide.leftAnchor).isActive = true
        tableView.rightAnchor.constraint(equalTo:view.safeAreaLayoutGuide.rightAnchor).isActive = true
        tableView.bottomAnchor.constraint(equalTo:view.safeAreaLayoutGuide.bottomAnchor).isActive = true
       
        
        
        // Creating constrain for Indecator
        activityIndicator.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(activityIndicator)
        activityIndicator.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        activityIndicator.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
          
    }
    
    private func setUpBinding() {
        viewModel
            .$peoples
            .receive(on : RunLoop.main)
            .sink { [weak self ] _ in
                self?.tableView.reloadData()
            }
            .store(in: &subscribers)
        viewModel.getPeople()
        
    }

}
extension PeopleViewController: UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return viewModel.peoples.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
        guard let cell = tableView.dequeueReusableCell(withIdentifier: PeopleCell.identifier, for: indexPath) as? PeopleCell
        else { return UITableViewCell() }
        
        
        let row = indexPath.row
        let people = viewModel.peoples[row]
        cell.configureCell(firstName: people.firstName, lastName: people.lastName)
    
        cell.configureImageCell(row: row, viewModel: viewModel)
        
        return cell
        
    }
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 100
    }
}
extension PeopleViewController: UITableViewDataSourcePrefetching {
    
    func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath]) {
        viewModel.getPeople()
    }
    
}

Here is the result .

enter image description here

CodePudding user response:

This is rather tricky because it seems your constraints are fine, assuming that your tableview height is 100, but the screenshot tableview cells seem a little shorter than 100. Let's assume the cell height is 100 correct.

I suggest you try configuring the imageView (and other views) in override func layoutSubViews(), which is a function that renders whenever the contentView's bound change. It should also be noted that better practice is where the imageSize is relative to the cell/contentView's frame instead of hardcoded values.

So it should look like

import UIKit

class PeopleCell: UITableViewCell {

    let profileImageView:UIImageView = {
        let img = UIImageView()
        return img
    }()

    override func layoutSubviews() {
        super.layoutSubviews()

profileImageView.translatesAutoresizingMaskIntoConstraints = false profileImageView.centerYAnchor.constraint(equalTo:self.contentView.centerYAnchor).isActive = true
       profileImageView.leadingAnchor.constraint(equalTo:self.contentView.leadingAnchor, constant:10).isActive = true
      profileImageView.widthAnchor.constraint(equalToConstant:self.frame.width * 0.7).isActive = true
      profileImageView.heightAnchor.constraint(equalToConstant:self.frame.width * 0.7).isActive = true

//You may want to try with other type of contentMode such as aspectFit, etc
profileImageView.contentMode = .scaleAspectFill
profileImageView.layer.cornerRadius = self.frame.width / 2
profileImageView.clipsToBounds = true
        
}

//If above doesn't work, you may want to look into the imageConfiguration function you made and ensure that contentMode is applied properly. 

    func configureImageCell(row: Int, viewModel: ViewModel) {
        
        profileImageView.image = nil
        
        viewModel
            .downloadImage(row: row) { [weak self] data in
                let image = UIImage(data: data)
                self?.profileImageView.image = image
                self?.profileImageView.contentMode = .scaleAspectFill
            }
    }

If all of the above code doesn't work, try to find the profileImageView size values by using breakpoints or ViewHierarchy within Xcode. To check the height of image or cell itself, they should be sufficient for you to find clues to resolve the issue.

All the best.

  • Related