How do I resize the header of a uitableview? - ios

I have a uitableview
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let width = tableView.frame.width - CGFloat((start*2))
let headerView = UIView()
headerView.frame.origin.x = 0
headerView.frame.origin.y = -45
headerView.frame.size.width = tableView.frame.width
let desc = UILabel()
desc.frame.origin.x = label.frame.origin.x
desc.frame.origin.y = line.frame.maxY + 10
desc.frame.size.width = width
desc.numberOfLines = 0
desc.font = UIFont(name: "Lato-Regular", size: 17);
desc.textColor = UIColor(red: 0.53, green: 0.53, blue: 0.53, alpha: 1.00)
desc.text = self.data.desc
desc.backgroundColor = UIColor.clear
desc.textAlignment = .left
desc.adjustsFontForContentSizeCategory = true
if (loadMoreDesc) {
desc.sizeToFit()
} else {
desc.frame.size.height = 110
}
headerView.addSubview(desc)
let moreButtonDesc = UIButton(frame: CGRect(x: desc.frame.minX, y: desc.frame.maxY, width: 80, height: 15))
moreButtonDesc.contentVerticalAlignment = UIControl.ContentVerticalAlignment.center
moreButtonDesc.titleLabel?.textAlignment = .left
if (loadMoreDesc) {
moreButtonDesc.setTitle("Less", for: .normal)
} else {
moreButtonDesc.setTitle("More", for: .normal)
}
moreButtonDesc.titleLabel?.font = UIFont(name: "Lato-Regular", size: 15);
moreButtonDesc.setTitleColor(UIColor(red: 0.00, green: 0.48, blue: 1.00, alpha: 1.00), for: .normal)
moreButtonDesc.addTarget(self, action:#selector(self.expandDesc(sender:)), for: .touchUpInside)
headerView.addSubview(moreButtonDesc)
When people click on "More" button the description should expand and the height of the table view header should increase to fit the description (desc). How can I accomplish this? Here's my expandDesc function
#objc func expandDesc(sender: UIButton) {
loadMoreDesc = !loadMoreDesc
tableView.reloadData()
}
Please note that the description is of dynamic height. I won’t know the height to set for the header unless I know the height of the description.

please can you try this
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
if loadMoreDesc {
return 100
} else {
return 50.0
}
}

Related

My UITableView crashes when I add a gradient background?

I have a UITableView under a UIViewController with a custom cell. The text for the UILabel in each cell is held in an array of strings. I’m coding in Swift Playgrounds, and when I run the Playground with an empty array it works fine (there aren’t an cells, of course, but the playground does run). When I populate the array, I get the error “there as a problem running this page... check your code...”. When I step through the code, it gets stuck at the line:
view.addSubview(gradientView)
What am I doing wrong?
import UIKit
import PlaygroundSupport
class ViewController: UITableViewController {
// Array that holds menu items
var menuItems = ["option 1","option 2","option 3"]
override func viewDidLoad() {
super.viewDidLoad()
// Add a gradient background
// Set height, width to view height, width
var gradientView = UIView(frame: CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height))
let gradientLayer:CAGradientLayer = CAGradientLayer()
gradientLayer.frame.size = gradientView.frame.size
// Set colors
gradientLayer.colors = [UIColor(red: 253/255, green: 94/255, blue: 172/255, alpha: 1).cgColor, UIColor(red: 121/255, green: 73/255, blue: 242/255, alpha: 1).cgColor]
// Skew gradient (diagonally)
gradientLayer.startPoint = CGPoint(x: 0, y: 0)
gradientLayer.endPoint = CGPoint(x: 0.5, y: 1)
// Rasterize to improve performance
gradientLayer.shouldRasterize = true
//Add gradient
gradientView.layer.addSublayer(gradientLayer)
view.addSubview(gradientView)
// Reguster custom cell
tableView.register(MenuItemCell.self, forCellReuseIdentifier: "cell_1")
// Turn off seperators
tableView.separatorStyle = .none
// Set header height
tableView.sectionHeaderHeight = 75
}
// Custom header
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView?{
let customView = UIView(frame: CGRect(x: 0, y: 0, width: 200, height: 75))
customView.backgroundColor = .clear //UIColor(white: 0.9, alpha: 1)
let button = UIButton(type: .custom)
button.setTitle("😁", for: .normal)
button.frame = CGRect(x: 20, y: 20, width: 50, height: 50)
button.layer.cornerRadius = 25
button.layer.shadowRadius = 8.0
button.layer.shadowColor = UIColor.black.cgColor
button.layer.shadowOffset = CGSize(width: 0, height: 0)
button.layer.shadowOpacity = 0.5
let blur = UIVisualEffectView(effect: UIBlurEffect(style:
UIBlurEffect.Style.light))
blur.frame = button.bounds
blur.isUserInteractionEnabled = false //This allows touches to forward to the button.
button.insertSubview(blur, at: 0)
customView.addSubview(button)
return customView
}
#objc func updateView(){
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return menuItems.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell_1", for: indexPath) as! MenuItemCell
cell.selectionStyle = .none
//cell.messageLabel.text = textMessages[indexPath.row]
cell.bubbleBackgroundView.backgroundColor = UIColor(white: 0.9, alpha: 1)
return cell
}
}
class MenuItemCell: UITableViewCell {
let optionLabel = UILabel()
let bubbleBackgroundView = UIView()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
bubbleBackgroundView.layer.shadowOpacity = 0.35
bubbleBackgroundView.layer.shadowRadius = 6
bubbleBackgroundView.layer.shadowOffset = CGSize(width: 0, height: 0)
bubbleBackgroundView.layer.shadowColor = UIColor.black.cgColor
bubbleBackgroundView.layer.cornerRadius = 25
bubbleBackgroundView.translatesAutoresizingMaskIntoConstraints = false
addSubview(bubbleBackgroundView)
addSubview(optionLabel)
optionLabel.numberOfLines = 0
optionLabel.translatesAutoresizingMaskIntoConstraints = false
// lets set up some constraints for our label
let constraints = [optionLabel.topAnchor.constraint(equalTo: topAnchor, constant: 32),
optionLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 32),
optionLabel.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -32),
optionLabel.widthAnchor.constraint(equalToConstant: 250),
bubbleBackgroundView.topAnchor.constraint(equalTo: optionLabel.topAnchor, constant: -16),
bubbleBackgroundView.leadingAnchor.constraint(equalTo: optionLabel.leadingAnchor, constant: -16),
bubbleBackgroundView.bottomAnchor.constraint(equalTo: optionLabel.bottomAnchor, constant: 16),
bubbleBackgroundView.trailingAnchor.constraint(equalTo: optionLabel.trailingAnchor, constant: 16),
]
NSLayoutConstraint.activate(constraints)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
PlaygroundPage.current.liveView = ViewController()

Insert a floating action button on UITableView in Swift

I'm trying to add a floating action button (not a floating menu button) which will navigate me to the next view controller with a single click. I'm not getting the floating button right. I have tried the below code and it is not showing the appropriate button on the table view as it is getting scrolled along with the table. Is there any way to stick the button at the same place without getting scrolled along with the table?
func floatingButton(){
let btn = UIButton(type: .custom)
btn.frame = CGRect(x: 285, y: 485, width: 100, height: 100)
btn.setTitle("All Defects", for: .normal)
btn.backgroundColor = #colorLiteral(red: 0.1764705926, green: 0.4980392158, blue: 0.7568627596, alpha: 1)
btn.clipsToBounds = true
btn.layer.cornerRadius = 50
btn.layer.borderColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
btn.layer.borderWidth = 3.0
btn.addTarget(self,action: #selector(DestinationVC.buttonTapped), for: UIControlEvent.touchUpInside)
view.addSubview(btn)
}
All subviews added to UITableView will automatically scroll with it.
What you can do is add the button to the application Window, just remember to remove it when the ViewController disappears.
var btn = UIButton(type: .custom)
func floatingButton(){
btn.frame = CGRect(x: 285, y: 485, width: 100, height: 100)
btn.setTitle("All Defects", for: .normal)
btn.backgroundColor = #colorLiteral(red: 0.1764705926, green: 0.4980392158, blue: 0.7568627596, alpha: 1)
btn.clipsToBounds = true
btn.layer.cornerRadius = 50
btn.layer.borderColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
btn.layer.borderWidth = 3.0
btn.addTarget(self,action: #selector(DestinationVC.buttonTapped), for: UIControlEvent.touchUpInside)
if let window = UIApplication.shared.keyWindow {
window.addSubview(btn)
}
}
and in viewWillDisappear:
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
btn.removeFromSuperview()
}
For iOS 13 and above you can check for the key window using this extension:
extension UIWindow {
static var key: UIWindow? {
if #available(iOS 13, *) {
return UIApplication.shared.windows.first { $0.isKeyWindow }
} else {
return UIApplication.shared.keyWindow
}
}
}
Here's a working example on XCode 10 with Swift 4.2.
Note that the FAB button will disappear when the view disappears, and reappears when the controller is loaded again.
import UIKit
class ViewController: UITableViewController {
lazy var faButton: UIButton = {
let button = UIButton(frame: .zero)
button.translatesAutoresizingMaskIntoConstraints = false
button.backgroundColor = .blue
button.addTarget(self, action: #selector(fabTapped(_:)), for: .touchUpInside)
return button
}()
override func viewDidLoad() {
super.viewDidLoad()
setupTableView()
}
override func viewDidAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if let view = UIApplication.shared.keyWindow {
view.addSubview(faButton)
setupButton()
}
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if let view = UIApplication.shared.keyWindow, faButton.isDescendant(of: view) {
faButton.removeFromSuperview()
}
}
func setupTableView() {
tableView.backgroundColor = .darkGray
}
func setupButton() {
NSLayoutConstraint.activate([
faButton.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -36),
faButton.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -36),
faButton.heightAnchor.constraint(equalToConstant: 80),
faButton.widthAnchor.constraint(equalToConstant: 80)
])
faButton.layer.cornerRadius = 40
faButton.layer.masksToBounds = true
faButton.layer.borderColor = UIColor.lightGray.cgColor
faButton.layer.borderWidth = 4
}
#objc func fabTapped(_ button: UIButton) {
print("button tapped")
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 5
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
return UITableViewCell()
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 64
}
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 32
}
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
return UIView()
}
}
If you currently using tableViewController then no , you must subclass UIViewController add UItableView and your floating button to it
Or you may override scollviewDidScroll and change button y according to tableview current offset
drag scrollview as IBOutlet and set it's delegate to the viewController
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let off = scrollView.contentOffset.y
btn.frame = CGRect(x: 285, y: off + 485, width: btn.frame.size.width, height: btn.frame.size.height)
}
code snapshot
in action
see in action
There is a way that is worked for me. In my table view controller, defined a button first, then override the function scrollViewDidScroll(), like this:
import UIKit
class MyTableViewController: UITableViewController {
private let button = UIButton(type: UIButton.ButtonType.custom) as UIButton
override func viewDidLoad() {
let bottomImage = UIImage(named: "yourImage.png")
let yPst = self.view.frame.size.height - 55 - 20
button.frame = CGRect(x: 12, y: yPst, width: 55, height: 55)
button.setImage(bottomImage, for: .normal)
button.autoresizingMask = [.flexibleTopMargin, .flexibleRightMargin]
button.addTarget(self, action: #selector(buttonClicked(_:)), for:.touchUpInside)
button.layer.shadowRadius = 3
button.layer.shadowColor = UIColor.lightGray.cgColor
button.layer.shadowOpacity = 0.9
button.layer.shadowOffset = CGSize.zero
button.layer.zPosition = 1
view.addSubview(button)
}
override func scrollViewDidScroll(_ scrollView: UIScrollView) {
let off = self.tableView.contentOffset.y
let yPst = self.view.frame.size.height
button.frame = CGRect(x: 12, y:off + yPst, width: button.frame.size.width, height: button.frame.size.height)
}
#objc private func buttonClicked(_ notification: NSNotification) {
// do something when you tapped the button
}
}

addSubview not working after converting

I upgraded xcode from 7.3.1 to 8 and converted to swift 2.2, other than the storyboard being a mess everything worked except adding a UIView programatically.
This was working fine before, now nothing shows up at all and there are no errors. Any ideas?
override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
//create view
let vw = UIView()
vw.backgroundColor = UIColor(red: 0.9137, green: 0.9176, blue: 0.9216, alpha: 1.0) /* #e9eaeb */
//create label inside view
let label: UILabel = UILabel()
label.frame = CGRectMake(0, 0, 200, 28)
label.textAlignment = NSTextAlignment.Left
label.textColor = UIColor.grayColor()
label.font = label.font.fontWithSize(13)
if !clearSearch {
label.text = " Recent Searches"
} else {
label.text = " Search Results"
}
vw.addSubview(label)
//create button inside view
let button: UIButton = UIButton()
button.frame = CGRectMake(self.view.frame.size.width - 45, 0, 40, 28)
button.titleLabel?.font = UIFont.systemFontOfSize(13)
button.setTitle("Clear", forState: UIControlState.Normal)
button.addTarget(self, action: #selector(deleteSearches), forControlEvents: UIControlEvents.TouchUpInside)
button.setTitleColor(UIColor(red: 0.3216, green: 0.7176, blue: 0.5333, alpha: 1.0), forState: UIControlState.Normal)
vw.addSubview(button)
return vw
}
Thanks for any help.
Looks like this is now required.
override func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 28
}

Add two buttons in footer in the same row

hello I want to add two buttons on my ViewController programmatically like this
What I have done is this
func createButton(buttonTitle: String,buttonAction: Selector) -> UIButton{
let button = UIButton(type: UIButtonType.System) as UIButton
button.frame = CGRectMake(0, 0, CGRectGetWidth(self.view.frame)/2, 48)
// button.translatesAutoresizingMaskIntoConstraints = false
button.setTitle(buttonTitle, forState: UIControlState.Normal)
button.addTarget(self, action:buttonAction, forControlEvents: UIControlEvents.TouchUpInside)
button.setTitleColor(UIColor.whiteColor(), forState:UIControlState.Normal)
button.titleLabel?.font = UIFont(name: Variables.MONTESERRAT_REGULAR, size: 20.0)
button.backgroundColor = UIColor().blueColor() //top
button.titleEdgeInsets = UIEdgeInsetsMake(0.0,10.0, 10.0, 0.0)
return button
}
override func tableView(tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let footerView = UIView()
footerView.frame = CGRectMake(0, 0, CGRectGetWidth(self.view.frame), 48)
bottomButton = createButton("PUBLISH", buttonAction: "Publish")
footerView.addSubview(bottomButton!)
return footerView
}
At the moment it only prints one button. for second button I am doing this
override func tableView(tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let footerView = UIView()
footerView.frame = CGRectMake(0, 0, CGRectGetWidth(self.view.frame), 48)
bottomButton = createButton("PUBLISH", buttonAction: "Publish")
bottomButton2 = createButton("Delete", buttonAction: "Delete")
footerView.addSubview(bottomButton!)
footerView.addSubview(bottomButton2!)
return footerView
}
This code is not printing two buttons. just printing only one
I think the problem is that both buttons have the same position, so one is showing above the other.
Try this:
func createButton(buttonTitle: String,buttonAction: Selector, buttonNumber : Int) -> UIButton{
let backgroundColor = buttonNumber == 0 ? UIColor.blueColor() : UIColor.orangeColor()
let space : CGFloat = 5
let button = UIButton(type: UIButtonType.System) as UIButton
let width = (CGRectGetWidth(self.view.frame) - space)/2
let xPos = buttonNumber == 0 ? 0 : width + space
button.frame = CGRectMake(xPos, 0, width, 48)
// button.translatesAutoresizingMaskIntoConstraints = false
button.setTitle(buttonTitle, forState: UIControlState.Normal)
button.addTarget(self, action:buttonAction, forControlEvents: UIControlEvents.TouchUpInside)
button.setTitleColor(UIColor.whiteColor(), forState:UIControlState.Normal)
// button.titleLabel?.font = UIFont(name: Variables.MONTESERRAT_REGULAR, size: 20.0)
button.backgroundColor = backgroundColor
button.titleEdgeInsets = UIEdgeInsetsMake(0.0,10.0, 10.0, 0.0)
return button
}
And then add it like so:
override func tableView(tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let footerView = UIView()
footerView.frame = CGRectMake(0, 0, CGRectGetWidth(self.view.frame), 48)
bottomButton = createButton("PUBLISH", buttonAction: "Publish", buttonNumber: 0)
bottomButton2 = createButton("Delete", buttonAction: "Delete", buttonNumber: 1)
footerView.addSubview(bottomButton!)
footerView.addSubview(bottomButton2!)
return footerView
}

swift uitableviewCell repeat subviews

I have a UIButton in a uitableviewcell associated to a target:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCellWithIdentifier("Cell") as! ProCell
cell.btn.tag = indexPath.row
cell.btn.addTarget(self, action: "buttonClicked:", forControlEvents: UIControlEvents.TouchUpInside)
return cell
}
This is the buttonClicked function:
func buttonClicked(sender:UIButton) {
let boton = sender as UIButton
let index = boton.tag
let buttonPosition: CGPoint = boton.convertPoint(CGPointZero, toView: self.tableView)
var indexPath: NSIndexPath = self.tableView.indexPathForRowAtPoint(buttonPosition)!
let cell = self.tableView.cellForRowAtIndexPath(indexPath) as! ProductoCell
cell.btn.setImage(UIImage (named: "rotacion-Null"), forState: UIControlState.Normal)
let indicador = UIActivityIndicatorView()
indicador.frame = CGRect(x: 0, y: 0, width: 25, height: 25)
indicador.color = UIColor(red: 153.0/255.0, green: 0.0, blue: 0.0, alpha: 1.0)
indicador.startAnimating()
cell.btn.addSubview(indicador)
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
let datosEd = ed.search(product)
dispatch_async(dispatch_get_main_queue(), {
//update UI in main thread once the loading is completed.
indicador.stopAnimating()
indicador.hidesWhenStopped = true
let label2 = UILabel(frame: CGRect(x: 15 , y: -5, width: 16, height: 16))
label2.textAlignment = NSTextAlignment.Center
label2.font = UIFont.boldSystemFontOfSize(13.0)
label2.backgroundColor = UIColor (red: 0.85, green: 0.20, blue: 0.33, alpha: 1.0)
label2.textColor = UIColor.whiteColor()
label2.layer.masksToBounds = true
label2.layer.cornerRadius = 8
let rowData = datosEd[0] as! NSDictionary
if rowData["art"] as! String == "No Results" {
label2.text = "0"
cell.contentView.addSubview(label2)
cell.btn.setImage(UIImage (named: "ed-25G"), forState: UIControlState.Normal)
} else {
label2.text = String(datosEd.count)
cell.btn.addSubview(label2)
cell.btn.setImage(UIImage (named: "ed-25R"), forState: UIControlState.Normal)
}
});
})
}
The problem is when I scroll down and scroll up back again, the subview(label2) is repeated in some cells.
Reading some responses think it has to do with the reuse of the cells, but I do not how to make the subviews are not repeated.
Some help, please... :-)

Resources