UIActivityIndicatorView disappears in CollectionView Footer - ios

I have a collectionView with only 1 section in my app which download data from API. I have a pagination and I am trying to add a loading footer in my collectionView. The header appears normally. I have in this footer cell an UIActivityIndicatorView and a UILabel. When the first at a limit is triggered, the 2 elements are present in the cell but when the second limit is triggered, the UIActivityIndicatorView is absent.
Have you an idea for that.
The code of the cell (BaseCell is just a class to avoid tapping the init and required init each time):
class loadingCell: BaseCell {
override func setupViews() {
super.setupViews()
backgroundColor = .yellow
let activity = UIActivityIndicatorView()
activity.backgroundColor = .red
activity.startAnimating()
activity.frame = CGRect(x: 10, y: 20, width: 20, height: 20)
let label = UILabel()
label.text = "hello"
label.frame = CGRect(x: 100, y: 20, width: 40, height: 20)
label.backgroundColor = .green
addSubview(activity)
addSubview(label)
}
}
The collection delegate methods :
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize {
return CGSize(width: SCREENW, height: 50)
}
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
if kind == UICollectionElementKindSectionFooter {
let loadingFooterView = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionElementKindSectionFooter, withReuseIdentifier: loadingCell, for: indexPath)
return loadingFooterView
}
return UICollectionReusableView()
}
The cell is well registered.
What happens when first limit is triggered:
And with the second:

Based on #MaksymMusiienko comment, I have tried this which do the job to reset the animation of the spinner.
class loadingCell: BaseCell {
let activitySpinner: UIActivityIndicatorView = {
let spinner = UIActivityIndicatorView()
spinner.backgroundColor = .red
spinner.startAnimating()
spinner.frame = CGRect(x: 10, y: 20, width: 20, height: 20)
return spinner
}()
override func setupViews() {
super.setupViews()
backgroundColor = .yellow
let label = UILabel()
label.text = "hello"
label.frame = CGRect(x: 100, y: 20, width: 40, height: 20)
label.backgroundColor = .green
addSubview(activitySpinner)
addSubview(label)
}
override func prepareForReuse() {
super.prepareForReuse()
activitySpinner.startAnimating()
}
}

Related

How to increase the width of custom cells in UITableView

I have created the UITableView with the custom UITableViewCell. But the problem which I am getting is the width of the cells is not the frame width though I have assigned in the CGReact. Please have a look over my code :
CustomTableViewCell Class:
import UIKit
class CustomTableViewCell: UITableViewCell {
lazy var backView : UIView = {
let view = UIView(frame: CGRect(x: 10, y: 6, width: self.frame.width, height: 76))
view.backgroundColor = .red
view.layer.applySketchShadow()
return view
}()
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
lazy var iconTime : UIImageView = {
var object = UIImageView(frame: CGRect(x: 10, y: 54, width: 12, height: 12))
object.image = #imageLiteral(resourceName: "clock")
return object
}()
lazy var notification : UILabel = {
var object = UILabel(frame: CGRect(x: 10, y: 7, width: backView.frame.width, height: 40))
object.adjustsFontSizeToFitWidth = true
object.minimumScaleFactor = 0.5
object.font = object.font.withSize(28.0)
object.numberOfLines = 3
return object
}()
lazy var notificationTime : UILabel = {
var object = UILabel(frame: CGRect(x: 30, y: 40, width: backView.frame.width, height: 40))
object.adjustsFontSizeToFitWidth = true
object.minimumScaleFactor = 0.5
object.font = object.font.withSize(12.0)
return object
}()
override func layoutSubviews() {
contentView.backgroundColor = UIColor.clear
backgroundColor = UIColor.clear
backView.layer.cornerRadius = 5
backView.clipsToBounds = true
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
addSubview(backView)
[notification, notificationTime, iconTime].forEach(backView.addSubview(_:))
}
}
And my view controller as follows :
import UIKit
class UserModal {
var tableView = UITableView()
var notification: String?
var notificationTime : String?
init(notification: String, notificationTime: String) {
self.notification = notification
self.notificationTime = notificationTime
}
}
class newNotificationController : UIViewController {
var tableView = UITableView()
var userMod = [UserModal]()
override func viewDidLoad() {
super.viewDidLoad()
setTableView()
userMod.append(UserModal(notification: "Data ", notificationTime: "Time"))
userMod.append(UserModal(notification: "This is some Notification which needs to be populated in the Grid view for testing but lets see what is happening here!! ", notificationTime: "12-12-1212 12:12:12"))
userMod.append(UserModal(notification: "Data ", notificationTime: "Time"))
}
func setTableView() {
tableView.frame = self.view.frame
tableView.backgroundColor = UIColor.clear
tableView.delegate = self
tableView.dataSource = self
tableView.separatorColor = UIColor.clear
self.view.addSubview(tableView)
tableView.register(CustomTableViewCell.self, forCellReuseIdentifier: "cell")
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
navigationController?.setNavigationBarHidden(true, animated: animated)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
navigationController?.setNavigationBarHidden(false, animated: animated)
}
}
extension newNotificationController: UITableViewDelegate , UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return userMod.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as? CustomTableViewCell else { fatalError("Unable to populate Notification History")}
cell.notification.text = userMod[indexPath.row].notification
cell.notificationTime.text = userMod[indexPath.row].notificationTime
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 85
}
}
Please have a look over the result:
I am not getting it why the width of my cells is the width of the frame. Any help will be highly appreciated. Thanks!!
The problem is in this code is frame width, somehow the width of the self is not the width of a device, so because of this, you are facing this issue.
lazy var backView : UIView = {
let view = UIView(frame: CGRect(x: 10, y: 6, width: self.frame.width, height: 76))
view.backgroundColor = .red
view.layer.applySketchShadow()
return view
}()
To resolve this issue you can set frame like this
let view = UIView(frame: CGRect(x: 10, y: 6, width: UIScreen.main.bounds.size.width - 10, height: 76))
You set the width your view
UIView(frame: CGRect(x: 5, y: 6, width: self.frame.width - 10,
height: 76))
tableView.frame = CGRect(x: 0, y: 0, width:
self.view.frame.size.width, height: self.view.frame.size.height)
you need to give constraint to the tableview. Top, Leading, Trailing, Bottom.
put this tableView.translatesAutoresizingMaskIntoConstraints = false line in your function
func setTableView() {
tableView.frame = self.view.frame
tableView.backgroundColor = UIColor.clear
tableView.delegate = self
tableView.dataSource = self
tableView.separatorColor = UIColor.clear
self.view.addSubview(tableView)
tableView.translatesAutoresizingMaskIntoConstraints = false //add this line
tableView.register(CustomTableViewCell.self, forCellReuseIdentifier: "cell")
}
and change width: UIScreen.main.bounds.size.width - 10 it.
thanks..

How to navigate another view controller when clicking on item inside cell of collectionView Using Swift 3

We want to show another controller by replacing main controller when clicking on item (i.e ImageView) inside a cell collection. But we are not able to get main collection view and can't able to navigate targeted controller. We are using following approach -
HomeViewComtroller.swift
import LBTAComponents
class HomeViewController: DatasourceController {
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.title = "Home"
collectionView?.contentInset = UIEdgeInsetsMake(50, 0, 0, 0)
collectionView?.scrollIndicatorInsets = UIEdgeInsetsMake(50, 0, 0, 0)
collectionView?.backgroundColor = UIColor(r: 232, g: 236, b: 241, a: 1)
let homeViewDatasource = HomeViewDatasource()
self.datasource = homeViewDatasource
}
override func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
if indexPath.section == 0 {
return CGSize(width: view.frame.width, height: 120)
} else if indexPath.section == 6 {
return CGSize(width: view.frame.width, height: 120)
} else {
return CGSize(width: view.frame.width, height: 200)
}
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
return CGSize(width: view.frame.width, height: 33)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize {
return CGSize(width: view.frame.width, height: 10)
}
// lazy var homeMainCatgCell: HomeMainCatgCell = {
// let homemain = HomeMainCatgCell ()
// homemain.homeViewcontroller = self
// return homemain
// }()
func handleCtgClick (ctgname: String ,ctgId: String) {
let dummySettingViewController = UIViewController()
dummySettingViewController.view.backgroundColor = UIColor.white
dummySettingViewController.navigationItem.title = ctgname
navigationController?.navigationBar.tintColor = UIColor.white
navigationController?.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName: UIColor.white]
navigationController?.pushViewController(dummySettingViewController, animated: true)
}
}
HomeViewDatasource
import LBTAComponents
class HomeViewDatasource: Datasource {
override func headerClasses() -> [DatasourceCell.Type]? {
return [HomeMainCatgCellHeader.self,HomeSaleCatgCellHeader.self,HomeNewArrivalCellHeader.self,HomeBestSallingCellHeader.self,HomeBigDiscountCellHeader.self,HomeSpecialOfferCellHeader.self,HomeBrandCellHeader.self]
}
override func footerClasses() -> [DatasourceCell.Type]? {
return[HomeCellsFooter.self]
}
override func cellClasses() -> [DatasourceCell.Type] {
return [HomeMainCatgCell.self,HomeSaleCtagCell.self,HomeNewArrivalsCell.self,HomeBestSallingCatgCell.self,HomeBigDiscountCatgCell.self,HomeSpecialOfferCatgCell.self,HomeBrandVIewCell.self]
}
override func numberOfItems(_ section: Int) -> Int {
return 1
}
override func numberOfSections() -> Int {
return 7
}
}
HomeMainCatgCell.swift
import LBTAComponents
class HomeMainCatgCell: DatasourceCell {
var homeViewcontroller: HomeViewController?
let personalcareCatgImageView: UIImageView = {
let iv = UIImageView()
iv.image = #imageLiteral(resourceName: "personalcareimage")
iv.tag = 0
iv.contentMode = .scaleToFill
return iv
}()
let healthcareCatgImageView: UIImageView = {
let iv = UIImageView()
iv.image = #imageLiteral(resourceName: "healthcareimage")
iv.contentMode = .scaleToFill
iv.tag = 1
return iv
}()
let homecareCatgImageView: UIImageView = {
let iv = UIImageView()
iv.image = #imageLiteral(resourceName: "homecareimage")
iv.contentMode = .scaleToFill
iv.tag = 2
return iv
}()
let kitchencareCatgImageView: UIImageView = {
let iv = UIImageView()
iv.image = #imageLiteral(resourceName: "kitchencareiamge")
iv.contentMode = .scaleToFill
iv.tag = 3
return iv
}()
override func setupViews() {
super.setupViews()
let personalcareCatgImageContainerView = UIView()
personalcareCatgImageContainerView.backgroundColor = .white
let homecareCatgImageContainerView = UIView()
homecareCatgImageContainerView.backgroundColor = .white
let healthcareCatgImageContainerView = UIView()
healthcareCatgImageContainerView.backgroundColor = .white
let kitchencareCatgImageContainerView = UIView()
kitchencareCatgImageContainerView.backgroundColor = .white
let imageStackView = UIStackView(arrangedSubviews: [personalcareCatgImageContainerView,homecareCatgImageContainerView,healthcareCatgImageContainerView,kitchencareCatgImageContainerView])
imageStackView.axis = .horizontal
imageStackView.distribution = .fillEqually
addSubview(imageStackView)
imageStackView.anchor(topAnchor, left: leftAnchor, bottom: self.bottomAnchor, right: self.rightAnchor, topConstant: 0, leftConstant: 0, bottomConstant: 0, rightConstant: 0, widthConstant: frame.width, heightConstant: frame.height)
imageStackView.addSubview(personalcareCatgImageView)
imageStackView.addSubview(healthcareCatgImageView)
imageStackView.addSubview(homecareCatgImageView)
imageStackView.addSubview(kitchencareCatgImageView)
personalcareCatgImageView.anchor(personalcareCatgImageContainerView.topAnchor, left: personalcareCatgImageContainerView.leftAnchor, bottom: personalcareCatgImageContainerView.bottomAnchor, right: personalcareCatgImageContainerView.rightAnchor, topConstant: 5, leftConstant: 5, bottomConstant: 5, rightConstant: 5, widthConstant: personalcareCatgImageContainerView.frame.width , heightConstant: personalcareCatgImageContainerView.frame.width)
healthcareCatgImageView.anchor(healthcareCatgImageContainerView.topAnchor, left: healthcareCatgImageContainerView.leftAnchor, bottom: healthcareCatgImageContainerView.bottomAnchor, right: healthcareCatgImageContainerView.rightAnchor, topConstant: 5, leftConstant: 5, bottomConstant: 5, rightConstant: 5, widthConstant: healthcareCatgImageContainerView.frame.width , heightConstant: healthcareCatgImageContainerView.frame.width)
homecareCatgImageView.anchor(homecareCatgImageContainerView.topAnchor, left: homecareCatgImageContainerView.leftAnchor, bottom: homecareCatgImageContainerView.bottomAnchor, right: homecareCatgImageContainerView.rightAnchor, topConstant: 5, leftConstant: 5, bottomConstant: 5, rightConstant: 5, widthConstant: homecareCatgImageContainerView.frame.width , heightConstant: homecareCatgImageContainerView.frame.width)
kitchencareCatgImageView.anchor(kitchencareCatgImageContainerView.topAnchor, left: kitchencareCatgImageContainerView.leftAnchor, bottom: kitchencareCatgImageContainerView.bottomAnchor, right: kitchencareCatgImageContainerView.rightAnchor, topConstant: 5, leftConstant: 5, bottomConstant: 5, rightConstant: 5, widthConstant: kitchencareCatgImageContainerView.frame.width , heightConstant: kitchencareCatgImageContainerView.frame.width)
personalcareCatgImageView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleClickCtg)))
personalcareCatgImageView.isUserInteractionEnabled = true
healthcareCatgImageView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleClickCtg)))
healthcareCatgImageView.isUserInteractionEnabled = true
homecareCatgImageView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleClickCtg)))
homecareCatgImageView.isUserInteractionEnabled = true
kitchencareCatgImageView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleClickCtg)))
kitchencareCatgImageView.isUserInteractionEnabled = true
}
func handleClickCtg(gestureRecognizer: UITapGestureRecognizer) {
var CtgName: String? = nil
var CtgId: String? = nil
guard let tag = gestureRecognizer.view?.tag else {return}
print(tag)
switch tag {
case 0:
CtgName = "Personal Care"
CtgId = "121"
case 1:
CtgName = "Health Care"
CtgId = "122"
case 2:
CtgName = "Home Care"
CtgId = "123"
case 3:
CtgName = "Kitchen Care"
CtgId = "124"
default:
return
}
self.homeViewController?.handleCtgClick(ctgname: CtgName! ,ctgId: CtgId!)
}
}
Main Problem
first of all i am not binding the click of entire cell, I only want to bing click on ImageView inside cell. So for that i bind GestureRecognizer on image view like -
kitchencareCatgImageView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleClickCtg)))
Click event works fine in terms of it's print the tag (added on image view) via print(tag) inside click function. But when call function self.homeViewcontroller.handleCtgClick(ctgname: CtgName! ,ctgId: CtgId!) (function exist in HomeViewcontroller class). it's not changing the view controller.
I also debug handleCtgClick function and i found i am getting the object of HomeViewcontroller is nil.
thanks in Advance
If you declare a global instance of your controller in your cell class this will create a Reference cycle and create a leak in your app. Your cell will have a strong reference to your controller and your controller will have a strong reference to your tableview which in turn keeps a strong reference to the cell, and second you might not be able to tell the index path of the clicked cell if you allow editing. You can try the following method to overcome both problems.
First of all create an enum in your cell class with cases as named according to your image views so your controller knows which image view is clicked and you can link your tags to it too. Something like:
enum CategoryViews:Int{
case personal = 0,healthcare = 1,homecare = 2,kitchencare = 3
}
Then create a protocol in your cell class like:
protocol HomeMainCatgCellDelegate:class{
func clicked(view:CategoryViews,forCell cell:HomeMainCatgCell)
}
Then create a weak variable in your cell class and call the protocol method in your action handler method
class HomeMainCatgCell: DatasourceCell {
weak var delegate:HomeMainCatgCellDelegate?
//Remove the variable var homeViewcontroller: HomeViewController? to avoid reference cycle and we don't need it anyway.
...
func handleClickCtg(gestureRecognizer: UITapGestureRecognizer) {
guard let tag = gestureRecognizer.view?.tag else {return}
print(tag)
if let clickedImageView = CategoryViews(rawValue:tag){
self.delegate?.clicked(view:clickedImageView,forCell:self)
}
}
}
Then in your view controller class you can you have to confirm to the HomeMainCatgCellDelegate protocol and set the cell's delegate to self.
class HomeViewController: DatasourceController, HomeMainCatgCellDelegate{
...
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
//Dequeue your cell here
cell.delegate = self
...
return self
}
func clicked(view:CategoryViews,forCell cell:HomeMainCatgCell){
//And you can handle your events accordingly here
if let indexpath = self.collectionView.indexPath(for: cell){
//Here you will get the indexpath of clicked cell and then you can put a switch condition to check which imageview is clicked
switch view{
case .personal:break
case .healthcare:break
case .homecare:break
case .kitchencare:break
}
}
}
}
Hope this helps.
The problem is that your "homeViewcontroller" variable is not set up correctly.
This code:
var homeViewcontroller = HomeViewController()
Creates an instance of a HomeViewController class. But this instance is in no way related to the screen you think it is. The screen that presented your current view is a completely different instance.
To be honest the way you are chaining everything is pretty weird and its not very intuitive. But if you want to fix your problem without altering your code too much you have to pass the REAL HomeViewController downwards.
So on the HomeViewController.swift you have this code:
let homeViewDatasource = HomeViewDatasource()
self.datasource = homeViewDatasource
Pass the "handleCtgClick" as a closure to it.
Something like
homeViewDataSource.presenterClosure = {(ctgname: String ,ctgId: String) in
let dummySettingViewController = UIViewController()
dummySettingViewController.view.backgroundColor = UIColor.white
dummySettingViewController.navigationItem.title = ctgname
navigationController?.navigationBar.tintColor = UIColor.white
navigationController?.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName: UIColor.white]
navigationController?.pushViewController(dummySettingViewController, animated: true)
}
(Note that you have to create this closure variable declaration within your HomeViewDatasource.swift so that you can assign it from the HomeViewController.swift)
Then repeat this step again to pass it to the HomeMainCatgCell.swift
Then you will be able to call this function referencing the local closure variable you created.
ALTERNATIVELY:
You can just pass the reference to the HomeViewController itself. But if you decide to do this make sure you keep passing it as an "optional" variable with a "weak" property or you will create a retain loop.

UICollectionViewCell with AutoLayout not working in iOS 10

I'm trying to create a dynamic UICollectionView whose cells auto-resize based on the text inside it. But for some reasons, my custom UICollectionViewCell won't expand to the full width. I am using SnapKit as AutoLayout and all my views are code-based; no xib or storyboard. Here's a debug view of what I got at the moment:
I want the cell to expand full width and the height to fit whatever the content is. Here's a snippet on my UICollectionViewController
override func viewDidLoad() {
super.viewDidLoad()
self.title = "Home"
let layout = UICollectionViewFlowLayout()
layout.itemSize = CGSize(width: view.frame.width, height: view.frame.height)
layout.scrollDirection = .vertical
layout.estimatedItemSize = CGSize(width: 375, height: 250)
collectionView = UICollectionView(frame: CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height), collectionViewLayout: layout)
collectionView.dataSource = self
collectionView.delegate = self
collectionView.backgroundColor = UIColor(red: 245/255, green: 245/255, blue: 245/255, alpha: 1)
collectionView.register(HomeCollectionViewCell.self, forCellWithReuseIdentifier: reuseIdentifier)
self.view.addSubview(collectionView)
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath)
// Configure the cell
if let c = cell as? HomeCollectionViewCell {
c.contentView.frame = c.bounds
c.contentView.autoresizingMask = [.flexibleHeight, .flexibleWidth]
configureCell(c, indexPath: indexPath)
}
return cell
}
func configureCell(_ cell: HomeCollectionViewCell, indexPath: IndexPath) {
cell.setText(withTitle: items[(indexPath as NSIndexPath).section].title)
}
And here's a snippet of my custom UICollectionViewCell
override init(frame: CGRect) {
super.init(frame: frame)
self.contentView.autoresizingMask = [.flexibleHeight, .flexibleWidth]
self.contentView.translatesAutoresizingMaskIntoConstraints = true
self.contentView.bounds = CGRect(x: 0, y: 0, width: 99999, height: 99999)
createTitle()
}
private func createTitle() {
titleView = TTTAttributedLabel(frame: CGRect(x: 0, y: 0, width: contentView.frame.width, height: 56))
titleView.tag = 1
titleView.numberOfLines = 2
titleView.delegate = self
titleView.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(titleView)
titleView.snp_updateConstraints(closure: {
make in
make.leading.trailing.equalTo(contentView).offset(10)
make.top.equalTo(contentView).offset(10)
make.bottom.equalTo(contentView).offset(-10)
})
}
func setText(withTitle title:String, paragraph: String, image: String) {
let titleAttributed = AttributedString(string: title, attributes: titleStringAttr)
titleView.attributedText = titleAttributed
titleView.sizeToFit()
}
I've spent 3 days just working on this on and on.. Any advice appreciated!
Well it's not really a solution, but the TTTAttributedLabel does some black magic that causes the AutoLayout not to work. So for me, I changed the TTTAttributedLabel to UILabel and it works fine.
FYI I posted similar question on SnapKit Github issues; credits to robertjpayne there for the hint (https://github.com/SnapKit/SnapKit/issues/261)

Swift Add Footer View In UITableView

This is actually a tableview and tableview cell, and i wanted to add a Submit button after the end of the tableview cell, but how do i do it?
I tried to do it at the storyboard add the button manually, but its not working, the button is not showing. Is there any other way to do it?
I wanted to do like the screenshot below.
Using StoryBoard
In UITableView You can drag UIView, it will set as FooterView if you have more then 0 prototype cell. After Drag you can see it in table view hierarchy as a subview. Now, you can add the label button on that View, you can also set IBAction into ViewController Class File.
Programmatically
Follow 3 Steps
Make one custom view with button,
Swift 3.X / Swift 4.X
let customView = UIView(frame: CGRect(x: 0, y: 0, width: 200, height: 50))
customView.backgroundColor = UIColor.red
let button = UIButton(frame: CGRect(x: 0, y: 0, width: 100, height: 50))
button.setTitle("Submit", for: .normal)
button.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
customView.addSubview(button)
Swift 2.X
let customView = UIView(frame: CGRectMake(0, 0, 200, 50))
customView.backgroundColor = UIColor.redColor()
let button = UIButton(frame: CGRect(x: 0, y: 0, width: 100, height: 50))
button.setTitle("Submit", forState: .Normal)
button.addTarget(self, action: #selector(buttonAction), forControlEvents: .TouchUpInside)
customView.addSubview(button)
Add that view in Table Footer View.
Swift 2.X/Swift 3.X/Swift 4.X
myTblView.tableFooterView = customView
you can do action on that button in same class.
Swift 3.X/Swift 4.X
#objc func buttonAction(_ sender: UIButton!) {
print("Button tapped")
}
Swift 2.X
func buttonAction(sender: UIButton!) {
print("Button tapped")
}
Swift 3/4
1. If you want to add Table footer which is only visible at the end of TabelView
let customView = UIView(frame: CGRect(x: 0, y: 0, width: tableView.frame.width, height: 150))
customView.backgroundColor = UIColor.clear
let titleLabel = UILabel(frame: CGRect(x:10,y: 5 ,width:customView.frame.width,height:150))
titleLabel.numberOfLines = 0;
titleLabel.lineBreakMode = .byWordWrapping
titleLabel.backgroundColor = UIColor.clear
titleLabel.textColor = PTConstants.colors.darkGray
titleLabel.font = UIFont(name: "Montserrat-Regular", size: 12)
titleLabel.text = "Payment will be charged to your Apple ID account at the confirmation of purchase. Subscription automatically renews unless it is canceled at least 24 hours before the end of the current period. Your account will be charged for renewal within 24 hours prior to the end of the current period. You can manage and cancel your subscriptions by going to your account settings on the App Store after purchase."
customView.addSubview(titleLabel)
tableView.tableFooterView = customView
2. If you want to add section footer which is visible while scrolling through section.
Adopt UITableViewDelegate and implement following delegate method.
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let vw = UIView()
vw.backgroundColor = UIColor.clear
let titleLabel = UILabel(frame: CGRect(x:10,y: 5 ,width:350,height:150))
titleLabel.numberOfLines = 0;
titleLabel.lineBreakMode = .byWordWrapping
titleLabel.backgroundColor = UIColor.clear
titleLabel.font = UIFont(name: "Montserrat-Regular", size: 12)
titleLabel.text = "Footer text here"
vw.addSubview(titleLabel)
return vw
}
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 150
}
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let footerView = UIView(frame: CGRect(x: 0, y: 0, width: tableView.frame.size.width, height: 50))
return footerView
}
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 50
}
Add UILabel as UITableView.Footer in swift
let footerView:UILabel = UILabel(frame: CGRect(x: 0, y: 0, width:320 , height: 500))
footerView.text = "add description ro Timevc in order user will see the result of lesson time"
footerView.numberOfLines = 0;
footerView.sizeToFit()
tableView.tableFooterView = footerView
tableView.contentInset = (UIEdgeInsetsMake(0, 8, -footerView.frame.size.height, 8))
// for Header and footer
// for header
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let HeaderView = UIView(frame: CGRect(x: 0, y: 0, width: TableViews.frame.size.width, height: 10))
HeaderView.backgroundColor = .green
let HeaderTitle = UILabel(frame: CGRect(x: 10, y: 10, width: TableViews.frame.size.width, height: 20))
HeaderTitle.text = "Hi You Welcome"
HeaderView.addSubview(HeaderTitle)
return HeaderView
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { 40 }
// for footer
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let footer = UIView()
footer.backgroundColor = UIColor.green
let titleLabel = UILabel(frame: CGRect(x: 10, y: 5, width: 350, height: 30))
titleLabel.textColor = .blue
titleLabel.text = "Hi I am Muhammad Hassan"
footer.addSubview(titleLabel)
return footer
}
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat { 40 }
... this is the best function for the header and footer ...
You can use
tableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 16, right: 0)

How do I add subviews to a custom UICollectionViewCell

I have a custom UICollectionViewCell class where I want to add subviews.
My cell class: The SetUpView() method will add all the subvies I need.
import Foundation
import UIKit
class RecipeCell: UICollectionViewCell {
var RecipeImg: UIImage!
var StarRatingImg: UIImage!
var RecipeTitleText = ""
var RecipeTextDescription = ""
var View: UIView!
var ImageContainer: UIImageView!
var FavIcon: UIImageView!
var StarRatingContainer: UIImageView!
var KCAL: UILabel!
var RecipeTitle: UITextView!
var RecipeText: UITextView!
func SetUpView()
{
//DropDown!.backgroundColor = UIColor.blueColor()
self.translatesAutoresizingMaskIntoConstraints = false
//View for recipe
View = UIView(frame: CGRectMake(0, 0, self.frame.width, self.frame.height))
View.backgroundColor = UIColor.whiteColor()
//Recipe image
ImageContainer = UIImageView(frame: CGRectMake(0, 0, View.frame.width, View.frame.height/2))
ImageContainer.image = RecipeImg
ImageContainer.contentMode = .ScaleToFill
//Recipe favorit icon
FavIcon = UIImageView(frame: CGRectMake(ImageContainer.frame.width - 35, 5, 30, 30))
FavIcon.image = UIImage(named: "LikeHeart")
//Star rating image
StarRatingContainer = UIImageView(frame: CGRectMake(10, ImageContainer.frame.height + 5, ImageContainer.frame.width - 20, (View.frame.height/2) * (1/5)))
StarRatingContainer.image = StarRatingImg
StarRatingContainer.contentMode = .ScaleAspectFit
//RecipeTitle container
RecipeTitle = UITextView(frame: CGRectMake(10, StarRatingContainer.frame.height + ImageContainer.frame.height + 10, View.frame.width - 20, 30))
RecipeTitle.font = UIFont(name: "OpenSans-Semibold", size: 12)
//RecipeTitle.backgroundColor = UIColor.redColor()
RecipeTitle.editable = false
RecipeTitle.text = RecipeTitleText
RecipeTitle.textContainerInset = UIEdgeInsetsMake(0, 0, 0, 0)
//RecipeText container
RecipeText = UITextView(frame: CGRectMake(10, StarRatingContainer.frame.height + ImageContainer.frame.height + RecipeTitle.frame.height + 15, View.frame.width - 20, 50))
RecipeText.font = UIFont(name: "OpenSans", size: 12)
//RecipeText.backgroundColor = UIColor.grayColor()
RecipeText.editable = false
RecipeText.text = RecipeTextDescription
RecipeText.textContainerInset = UIEdgeInsetsMake(0, 0, 0, 0)
//KCAL label
KCAL = UILabel(frame: CGRectMake(15, StarRatingContainer.frame.height + ImageContainer.frame.height + RecipeTitle.frame.height + RecipeText.frame.height + 20, 200, 20))
KCAL.text = "420 KCAL. PER. PORTION"
KCAL.font = UIFont(name: "OpenSans-Bold", size: 10)
KCAL.textColor = UIColor(CGColor: "#dc994a".CGColor)
//Adding the views
self.addSubview(View)
View.addSubview(ImageContainer)
View.addSubview(KCAL)
View.addSubview(StarRatingContainer)
View.addSubview(RecipeTitle)
View.addSubview(RecipeText)
ImageContainer.addSubview(FavIcon)
View.bringSubviewToFront(ImageContainer)
}
}
I have a UICollectionView which uses the custom cell class.
I create my UICollectionView in viewDidLoad()
// Create Collection view
layout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 10, right: 0)
layout.itemSize = CGSize(width: screenWidth/MenuViewConst - 1, height: screenWidth - 1)
layout.minimumInteritemSpacing = 1
layout.minimumLineSpacing = 1
collectionView = UICollectionView(frame: CGRect(x: 0, y: 105, width: self.view.frame.width, height: self.view.frame.height - 150), collectionViewLayout: layout)
collectionView?.tag = 5
collectionView!.dataSource = self
collectionView!.delegate = self
collectionView!.registerClass(RecipeCell.self, forCellWithReuseIdentifier: "CollectionViewCell")
collectionView!.backgroundColor = UIColor.lightGrayColor()
collectionView!.contentInset.top = 0
In cellForItemAtIndexPath delegate I set up the UICollectionView to use my custom cell class. But I can't call the SetUpView() method from my custom cell class here, because that will just keep adding subviews on subviews. I can't figure out how to add the subviews to the UICollectionViewCell before entering the delegate. Hope you guys can help - Thank you
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("CollectionViewCell", forIndexPath: indexPath) as! RecipeCell
let recipe = self.RecipeArr[indexPath.row]
cell.backgroundColor = UIColor.grayColor()
cell.layer.borderColor = UIColor.whiteColor().CGColor
cell.layer.borderWidth = 0.5
cell.RecipeImg = UIImage(named: "Burger")
cell.StarRatingImg = UIImage(named: "StarRating")
cell.RecipeTitleText = recipe["name"].string!
cell.RecipeTextDescription = recipe["instruction"].string!
//BAD IDEA!
//cell.SetUpView()
print("new cell")
return cell
}
You need to use init(frame: CGRect) inherited function in the UICollectionViewCell .
class RecipeCell: UICollectionViewCell {
var imageView : UIImageView?
override init(frame: CGRect) {
super.init(frame: frame)
//initialize all your subviews.
imageView = UIImageView()
}
}
also don't forget to register your custom class in the viewDidLoad function
collectionView!.registerClass(RecipeCell.self, forCellWithReuseIdentifier: "CollectionViewCell")
and your collectionview delegate would be like this
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("CollectionViewCell", forIndexPath: indexPath) as! RecipeCell
cell.imageView.image = UIImage(named:"yourImage.png")
}

Resources