position: fixed; top: auto !important; margin-left: 112px;

Custom cells are used to create the customized cell in the way we want to display in our UI. In previous tutorial, we studied about how to create default UiTableView cells and now we will illustrate how to self-size or resize UITableView cells using Autolayouts.

Task Output :-

We will create a programming app which basically displays the programming languages and the specific description related to it. So the basic challenge in this app is we have to resize the cells based on the length of the description.


Get Started by creating an UITableView

Open Xcode Goto File > New >Project >Single View Application > Enter Project Name (eg :- FirstProjectViewController) and Select Language as Swift> Done.

Now you can see a file on left navigation Menu of Xcode named, ViewController.swift

We firstly begins with AppDelegate.swift file. Copy and paste this code in didFinishLaunchingWithOptions method (the very first method you can see in Appdelegate.swift).

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?


    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
              
        window = UIWindow(frame: UIScreen.main.bounds)
        let mainController = ViewController() as UIViewController
        let navigationController = UINavigationController(rootViewController: mainController)
        navigationController.navigationBar.isTranslucent = false
        self.window?.rootViewController = navigationController
        self.window?.makeKeyAndVisible()
        
        return true
    }

AppDelegate is the file which will be called at first on initial startup of app. There are many ViewControllers added in your project so in didFinishLaunchingApplications we write the name of specific ViewController to begin with. In this example, we begin with ViewController.swift file.

UINavigationController is the header with teal color as you see in the image of Final Output. UiInavigationController word itself tells its meaning which is "It Controls all the navigation"

self.window?.rootViewController = navigationController

In this way you can set your root ViewController. In our case we want ViewController.swift file to be the first one to start.

ViewController.swift file looks like this :-
//  ViewController.swift
//  Created by Manish Methani.
//  Copyright © 2018 Codzify. All rights reserved.
//

import UIKit

private let myArray: NSMutableArray = ["C Language \nC is called as mother of programming languages used to develop System level Applications and originally developed by Denis M.Ritchie in 1970's to build Unix Operating System.",

"Objective-C \nThere are various ways to compile and run an Objective-C Program. But I recommend using to an Xcode (officially provided by Apple Inc.).All I can say about Xcode is It's amazing It includes everything you are seeing in iPhone. Each App you see in iPhones, iPad, and iWorld is developed in Xcode. All you have to know is just the basics of Objective-C Language to understand the syntax .",

"Swift \nSwift is a new programming language for iOS, macOS, watchOS, and tvOS app development. Many parts of Swift will be familiar with your C & Objective-C experience."]

var myTableView = UITableView()
class ViewController: UIViewController,UITableViewDataSource,UITableViewDelegate {
    override func viewDidLoad()
    {
        super.viewDidLoad()
        
        self.view.backgroundColor = UIColor.white
        self.navigationItem.title = "Programming Languages"
        
        self.navigationController?.navigationBar.barTintColor = UIColor.init(red: 0/255.0, green: 128/255.0, blue: 128/255.0, alpha: 1.0)
        self.navigationController?.navigationBar.titleTextAttributes = [NSAttributedStringKey.foregroundColor: UIColor.white]
        self.navigationController?.navigationBar.tintColor = UIColor.white
        
        
        myTableView = UITableView()
        myTableView.register(CustomTableViewCell.self, forCellReuseIdentifier: "cell")
        myTableView.dataSource = self
        myTableView.delegate = self
        self.view.addSubview(myTableView)
        myTableView.backgroundColor = UIColor.init(red: 245, green: 245, blue: 245, alpha: 1)
        //Two Golden lines for resizing the table view cells
        myTableView.estimatedRowHeight = 100;
        myTableView.rowHeight = UITableViewAutomaticDimension;
        myTableView.separatorStyle = UITableViewCellSeparatorStyle.none;
        
       // Table View AutoLayout constraints
        myTableView.translatesAutoresizingMaskIntoConstraints = false
       
        let topConstraint = NSLayoutConstraint(item: myTableView, attribute: .top, relatedBy: .equal, toItem: self.view, attribute: .top, multiplier: 1, constant: 12)
        self.view.addConstraint(topConstraint)
        
        let leftConstraint = NSLayoutConstraint(item: myTableView, attribute: .left, relatedBy: .equal, toItem: self.view, attribute: .left, multiplier: 1, constant: 0)
        self.view.addConstraint(leftConstraint)
        
        let rightConstraint = NSLayoutConstraint(item: myTableView, attribute: .right, relatedBy: .equal, toItem: self.view, attribute: .right, multiplier: 1, constant: 0)
        self.view.addConstraint(rightConstraint)
        
        let bottoConstraint = NSLayoutConstraint(item: myTableView, attribute: .bottom, relatedBy: .equal, toItem: self.view, attribute: .bottom, multiplier: 1, constant: 0)
        self.view.addConstraint(bottoConstraint)
        
    }
    
 // Table View Delegates
    func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return 0 // you should probably return 1
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return myArray.count
    }
    
    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        print("Num: \(indexPath.row)")
        print("Value: \(myArray[indexPath.row])")        
    }
    
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CustomTableViewCell
        
        cell.backgroundColor = UIColor.clear
        cell.nameLabel.text  =  "\(myArray [indexPath.row])"
        
        return cell
    }
}

A short description of example:

We had given a backgroundColor to NavigationBar, Added a Programming Languages title and given it with the white text color.

Here, viewDidLoad() method is called first. In this method, we initialized a UITableView like this,

myTableView = UITableView()

Then, we registered the Datasource and Delegate methods of UITableView. We have to register these methods to implement its delegate & datasource methods.

 myTableView.dataSource = self
myTableView.delegate = self

Then you have to register the forCellReuseIdentifier and give it same name which you can use in cellForRowAtIndexPath method of UITableView.

myTableView.register(CustomTableViewCell.self, forCellReuseIdentifier: "cell")

Last line adds myTableView as a subView inside view.

 self.view.addSubview(myTableView)

Following lines help in resizing the cells automatically. You do not have to give specific height to any cell, we will use UITableViewAutomaticDimension

myTableView.estimatedRowHeight = 100;
myTableView.rowHeight = UITableViewAutomaticDimension;

In numberOfRowsInSection we are going to use the count of elements in our NSMutableArray to tell the tableView how many rows to create:

 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return myArray.count
  }
 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CustomTableViewCell
        
        cell.backgroundColor = UIColor.clear
        cell.nameLabel.text  =  "\(myArray [indexPath.row])"
        
        return cell
    }

CustomTableViewCell.swift file looks like this

We use Autolayout to create custom UITableView cell. If you missed the concepts of Autolayout you can refer it here.

import UIKit

class CustomTableViewCell: UITableViewCell {
    
    var nameLabel = UILabel()
    
    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        
        self.selectionStyle = UITableViewCellSelectionStyle.none
       
      
        let boxView = UIView()
        self.contentView.backgroundColor = UIColor.clear
        boxView.backgroundColor = UIColor.white
        self.contentView.addSubview(boxView)
        boxView.layer.cornerRadius = 2.0;
        boxView.backgroundColor = UIColor.white;
        
        // BoxView created using autolayout constraints.
        boxView.translatesAutoresizingMaskIntoConstraints = false

        let topConstraint = NSLayoutConstraint(item: boxView, attribute: .top, relatedBy: .equal, toItem: self.contentView, attribute: .top, multiplier: 1, constant: 12)
        self.contentView.addConstraint(topConstraint)
        
        let leftConstraint = NSLayoutConstraint(item: boxView, attribute: .left, relatedBy: .equal, toItem: self.contentView, attribute: .left, multiplier: 1, constant: 12)
        self.contentView.addConstraint(leftConstraint)
        
        
        let rightConstraint = NSLayoutConstraint(item: boxView, attribute: .right, relatedBy: .equal, toItem: self.contentView, attribute: .right, multiplier: 1, constant: -12)
        self.contentView.addConstraint(rightConstraint)
        
        let bottoConstraint = NSLayoutConstraint(item: boxView, attribute: .bottom, relatedBy: .equal, toItem: self.contentView, attribute: .bottom, multiplier: 1, constant: -12)
        self.contentView.addConstraint(bottoConstraint)
        
        
        //Here label added to boxView
        nameLabel = UILabel()
        boxView.addSubview(nameLabel)
        nameLabel.textColor = UIColor.black
        nameLabel.numberOfLines = 0;
        nameLabel.lineBreakMode = NSLineBreakMode.byWordWrapping;

        // namelabel constraints 
        nameLabel.translatesAutoresizingMaskIntoConstraints = false

        let topLabelConstraint = NSLayoutConstraint(item: nameLabel, attribute: .top, relatedBy: .equal, toItem: boxView, attribute: .top, multiplier: 1, constant: 4)
        boxView.addConstraint(topLabelConstraint)
        
        let leftLabelConstraint = NSLayoutConstraint(item: nameLabel, attribute: .left, relatedBy: .equal, toItem: boxView, attribute: .left, multiplier: 1, constant: 12)
        boxView.addConstraint(leftLabelConstraint)
        
        
        let rightLabelConstraint = NSLayoutConstraint(item: nameLabel, attribute: .right, relatedBy: .equal, toItem: boxView, attribute: .right, multiplier: 1, constant: -12)
        boxView.addConstraint(rightLabelConstraint)
        
        
        //Separator line added to View  
        let separatorView = UIView()
        boxView.addSubview(separatorView)
        separatorView.backgroundColor = UIColor.lightGray
        
        // Separator line constraints
        separatorView.translatesAutoresizingMaskIntoConstraints = false
        
        let heightSeparatorConstraint = NSLayoutConstraint(item: separatorView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: 2.0)
        boxView.addConstraint(heightSeparatorConstraint);
        
        let topSeparatorConstraint = NSLayoutConstraint(item: separatorView, attribute: .top, relatedBy: .equal, toItem: nameLabel, attribute: .bottom, multiplier: 1, constant: 12)
        boxView.addConstraint(topSeparatorConstraint)
        
        let leftSeparatorConstraint = NSLayoutConstraint(item: separatorView, attribute: .left, relatedBy: .equal, toItem: boxView, attribute: .left, multiplier: 1, constant: 12)
        boxView.addConstraint(leftSeparatorConstraint)
        
        
        let rightSeparatorConstraint = NSLayoutConstraint(item: separatorView, attribute: .right, relatedBy: .equal, toItem: boxView, attribute: .right, multiplier: 1, constant: -12)
        boxView.addConstraint(rightSeparatorConstraint)
        
      

        // Golden line which do all the resizing of cell stuff  
        let bottomSeparatorCosntraint = NSLayoutConstraint(item: separatorView, attribute: .bottom, relatedBy: .equal, toItem: boxView, attribute: .bottom, multiplier: 1, constant: -12)
        boxView.addConstraint(bottomSeparatorCosntraint)
        
        
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    
    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }
    
    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)
        
        // Configure the view for the selected state
    }
    
}

In this cell, we created one view boxView which is subview of self.contentView Then we added nameLabel which is subview of boxView. Now, we know that Size of nameLabel changes as per length of description of programming languages. So we need to resize the boxView accordingly.

// Golden line which do all the resizing of cell stuff  
        let bottomSeparatorCosntraint = NSLayoutConstraint(item: separatorView, attribute: .bottom, relatedBy: .equal, toItem: boxView, attribute: .bottom, multiplier: 1, constant: -12)
        boxView.addConstraint(bottomSeparatorCosntraint)
        

We added bottom of separatorView as bottom of boxView. top of separatorView will be bottom of nameLabel. top of nameLabel will be boxView relative and top of boxView will be top of self.contentView. Got it? :) Just read it like this to understand the heirarchy properly.

Solve the Quiz of Article

1) What do you think the frame of an UIView is the rectangle, expressed as a location (x,y) and size (width,height) relative to the superview it is contained within?
Yes
No

2) What do you think the bounds of an UIView is the rectangle, expressed as a location (x,y) and size (width,height) relative to its own coordinate system (0,0)?
Yes
No


Previous Next Article







codzify.com


Largest collection of up-to-date tutorials to learn programming languages. We are focused on easy learning. Massive collection of interview questions one may need for preparation.

Social Profile


Linkedin
Twitter
Facebook

Copyright 2019. All rights reserved.