Label automatically hide/show on scrolling in Header View - swift

I am using expandable tableView, which is show/hide on click sectionHeader.
As I want to add Label/Button on HeaderView. but at the time of scrolling the label show/hide automatically. but I doesn't want label is disappear on scroll of tableView.
My Code is -
func tableView(tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
// Background view is at index 0, content view at index 1
if let bgView = view.subviews[0] as? UIView
{
if section == 0 {
let labelValue = UILabel(frame: CGRect(x: 5, y: 80, width: 40, height: 20))
labelValue.backgroundColor = UIColor.greenColor()
bgView.addSubview(labelValue)
}
if section == 1{
let labelValue = UILabel(frame: CGRect(x: 5, y: 80, width: 40, height: 20))
labelValue.backgroundColor = UIColor.redColor()
bgView.addSubview(labelValue)
}
if section == 2{
let labelValue = UILabel(frame: CGRect(x: 5, y: 80, width: 40, height: 20))
labelValue.backgroundColor = UIColor.yellowColor()
bgView.addSubview(labelValue)
}
if section == 3{
let labelValue = UILabel(frame: CGRect(x: 5, y: 80, width: 40, height: 20))
labelValue.backgroundColor = UIColor.blueColor()
bgView.addSubview(labelValue)
}
}
view.layer.borderColor = UIColor.blackColor().CGColor
view.layer.borderWidth = 0.3
}
ViewForHeaderSection
func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = HeaderView(tableView: self.customTableView, section: section)
headerView.backgroundColor = UIColor.whiteColor()
let label = UILabel(frame: headerView.frame)
label.textAlignment = NSTextAlignment.Center
label.font = UIFont (name: "HelveticaNeue-Light", size: 16)
label.textColor = UIColor.blackColor()
let labelValue = UILabel(frame: CGRect(x: 14, y: 15, width: 43, height: 32))
labelValue.textAlignment = NSTextAlignment.Center
labelValue.textColor = UIColor.whiteColor()
labelValue.font = UIFont(name: "HelveticaNeue-Bold", size: 13)
labelValue.text = "14"
//let btnExpand = UIButton(frame: headerView.frame)
let btnExpand = UIButton(frame:CGRect(x: 320, y: 17, width: 24, height: 24))
btnExpand.setBackgroundImage(UIImage(named: "expand"), forState: .Normal)
btnExpand.addTarget(self, action: #selector(HomeViewController.expandTableView), forControlEvents: .TouchUpInside)
if section == 0 {
label.text = "Runing Vehicle"
labelValue.backgroundColor = UIColor(red: 14/255.0, green: 76/255.0, blue: 12/255.0, alpha: 1.0)
btnExpand.addTarget(self, action: #selector(HomeViewController.expandTableView), forControlEvents: .TouchUpInside)
}
if section == 1 {
label.text = "Idle Vehicle"
labelValue.backgroundColor = UIColor(red: 148/255.0, green: 0/255.0, blue: 11/255.0, alpha: 1.0)
}
if section == 2 {
label.text = "Vehicle AT POI"
labelValue.backgroundColor = UIColor(red: 162/255.0, green: 136/255.0, blue: 5/255.0, alpha: 1.0)
}
if section == 3 {
label.text = "All Vehicle"
labelValue.backgroundColor = UIColor(red: 31/255.0, green: 61/255.0, blue: 127/255.0, alpha: 1.0)
}
headerView.addSubview(label)
headerView.addSubview(labelValue)
headerView.addSubview(btnExpand)
return headerView
}
func expandTableView(){
print("Hello")
customTableView.contentSize = CGSizeMake(375, 667)
}

You need to add that small label with that background color inside viewForHeaderInSection method because with willDisplayHeaderView it will add that label multiple time, so change your viewForHeaderInSection and remove the willDisplayHeaderView method.
func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = HeaderView(tableView: self.customTableView, section: section)
headerView.backgroundColor = UIColor.whiteColor()
let label = UILabel(frame: headerView.frame)
label.textAlignment = NSTextAlignment.Center
label.font = UIFont (name: "HelveticaNeue-Light", size: 16)
label.textColor = UIColor.blackColor()
let labelValue = UILabel(frame: CGRect(x: 0, y: 0, width: 50, height: headerView.frame.size.height))
if section == 0 {
label.text = "Runing Vehicle"
labelValue.backgroundColor = UIColor.greenColor()
}
if section == 1 {
label.text = "Idle Vehicle"
labelValue.backgroundColor = UIColor.redColor()
}
if section == 2 {
label.text = "Vehicle AT POI"
labelValue.backgroundColor = UIColor.yellowColor()
}
if section == 3 {
label.text = "All Vehicle"
labelValue.backgroundColor = UIColor.blueColor()
}
headerView.addSubview(label)
headerView.addSubview(labelValue)
return headerView
}
Edit: Change your last line of code that return the headerView like this
headerView.addSubview(label)
headerView.addSubview(labelValue)
headerView.addSubview(btnExpand)
headerView.sendSubviewToBack(label)
headerView.bringSubviewToFront(btnExpand)
return headerView

Related

Getting trouble when hovering a custom segmented control in swift

I tried to create custom segmented control which should change its look if you are hovering it. But it does not work as I expected.
Here's the code (I am sorry that it is that long but I already made it 200 lines shorter then it was):
class MySegmentedControl: UIView {
var state = MySegmentedControl_State.unknown
var buttons = [MySegmentedControl_ButtonView]()
func setUpView(){
let view = UIView(frame: self.frame)
view.frame.origin.x = 0
view.frame.origin.y = 0
view.addSubview(holderView())
self.addSubview(view)
}
func holderView() -> UIView{
let view = UIView(frame: CGRect(origin: CGPoint(x: 100, y: 0), size: CGSize(width: 490, height: 70)))
view.layer.borderWidth = 5
view.layer.borderColor = UIColor.gray.cgColor
view.layer.cornerRadius = view.frame.height / 2
view.layer.masksToBounds = true
view.clipsToBounds = true
view.backgroundColor = #colorLiteral(red: 0.5741485357, green: 0.5741624236, blue: 0.574154973, alpha: 1)
//place the first button
let button_1 = MySegmentedControl_ButtonView(text: "One", frame: CGRect(x: 0, y: 0, width: 163.3333, height: 70), type: .one, delegate: self)
//place the second Button
let button_2 = MySegmentedControl_ButtonView(text: "Two", frame: CGRect(x: 163.3333, y: 0, width: 163.3333, height: 70), type: .two, delegate: self)
//place the third Button
let button_3 = MySegmentedControl_ButtonView(text: "Three", frame: CGRect(x: 163.3333*2, y: 0, width: 163.3333, height: 70), type: .three, delegate: self)
buttons.append(button_1); buttons.append(button_2); buttons.append(button_3)
view.addSubview(button_1)
view.addSubview(button_2)
view.addSubview(button_3)
return view
}
class MySegmentedControl_ButtonView: UIView{
private var selected = false
private var hovering = false
var text = ""
private var type: MySegmentedControl_State
private var delegate: MySegmentedControl_ButtonView_Delegate
private var label = UILabel()
func setUpView(){
layer.cornerRadius = frame.height/2
let label = UILabel(frame: frame)
self.label = label
label.tintColor = .white
label.text = text
label.sizeToFit()
label.center = self.center
label.font = label.font.withSize(15)
let regionizer = UIHoverGestureRecognizer(target: self, action: #selector(didHover(_:)))
addGestureRecognizer(regionizer)
addSubview(label)
//set up the button
let button = UIButton(frame: bounds, primaryAction: UIAction(handler: { [self] action in
selected = true
delegate.shouldChangeState(to: type)
delegate.shouldDeselectOthers(without: text)
if !hovering{
backgroundColor = #colorLiteral(red: 0.9961533629, green: 0.9931518435, blue: 1, alpha: 0.8)
}else{
self.backgroundColor = #colorLiteral(red: 0.7540688515, green: 0.7540867925, blue: 0.7540771365, alpha: 0.9435433103)
}
}))
addSubview(button)
}
func deselect(){
self.selected = false
if hovering{
backgroundColor = #colorLiteral(red: 0.7540688515, green: 0.7540867925, blue: 0.7540771365, alpha: 0.15)
UIView.animate(withDuration: 0.2) {[self]in
label.frame.origin.y = 10
label.font = label.font.withSize(12)
}
}else{
backgroundColor = #colorLiteral(red: 0.2605174184, green: 0.2605243921, blue: 0.260515637, alpha: 0.15)
UIView.animate(withDuration: 0.2) {[self]in
label.frame.origin.y = 10
label.font = label.font.withSize(12)
}
}
}
#objc
func didHover(_ recognizer: UIHoverGestureRecognizer){
switch recognizer.state{
case .began, .changed:
hovering = true
if selected{
backgroundColor = #colorLiteral(red: 0.7540688515, green: 0.7540867925, blue: 0.7540771365, alpha: 0.15)
UIView.animate(withDuration: 0.2) {[self]in
label.frame.origin.y = 10
label.font = label.font.withSize(12)
}
}else{
backgroundColor = #colorLiteral(red: 0.2605174184, green: 0.2605243921, blue: 0.260515637, alpha: 0.15)
UIView.animate(withDuration: 0.2) {[self]in
label.frame.origin.y = 10
label.font = label.font.withSize(12)
}
}
case .ended:
hovering = false
if selected{
self.backgroundColor = #colorLiteral(red: 0.9961533629, green: 0.9931518435, blue: 1, alpha: 0.2)
UIView.animate(withDuration: 0.2) {[self]in
label.center.y = center.y
label.font = label.font.withSize(15)
}
}else{
self.backgroundColor = .clear
UIView.animate(withDuration: 0.2) {[self]in
label.center.y = center.y
label.font = label.font.withSize(15)
}
}
default:break
}
}
init(text: String, frame: CGRect, type: MySegmentedControl_State, delegate: MySegmentedControl_ButtonView_Delegate){
self.type = type
self.delegate = delegate
super.init(frame: frame)
self.text = text
setUpView()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
}
extension MySegmentedControl: MySegmentedControl_ButtonView_Delegate{
func shouldDeselectOthers(without: String) {
for button in buttons{
if button.text != without{
button.deselect()
}
}
}
func shouldChangeState(to state: MySegmentedControl_State) {
self.state = state
}
}
protocol MySegmentedControl_ButtonView_Delegate{
func shouldDeselectOthers(without: String)
func shouldChangeState(to state: MySegmentedControl_State)
}
enum MySegmentedControl_State: String{
case unknown = "Non specific case avalaible"
case one = "One selected"
case two = "Two selected"
case three = "Three selected"
}
But the second of my buttons is displayed as the third and the the third does not get displayed, but if I hover the place where button two SHOULD be, it still gets hovered.
Here is a shout video:
Video showing problems with this code
My App is running on MacOS with MacCatalyst
In setUpView() inside class MySegmentedControl_ButtonView, you are trying to set the label's position with:
label.center = self.center
However, self.center is relative to self's superview. So your labels are being shifted.
If you change that line to:
label.center = CGPoint(x: self.bounds.midX, y: self.bounds.midY)
the label centering will be correct.
As I asked in my comment though... why aren't you using auto-layout? It would make things much easier (and much more flexible).

Unable to Format the Section Header of UITableView

One View Controller which has three Table Views in it. I am struggling with formatting and setting the section header for each table.My func for viewForHeaderInSection is attached below
My Goal is to achieve something like the image. Struggling to format and design the section header for each of the table views. Using the attached code get the Terminating app due to uncaught exception 'CALayerInvalid', reason: 'layer <CALayer: 0x12cc80610> is a part of cycle in its layer tree' error message
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
if(tableView == firstTableView){
let button = UIButton(frame: CGRect(x: 270, y: 15, width:20 , height: 20))
button.tag = section
button.setImage(UIImage(named: "InfoIcon"), for: UIControl.State.normal)
button.addTarget(self,action:#selector(buttonClicked),for:.touchUpInside)
let view = UIView(frame: CGRect(x: 20, y: 8, width: tableView.frame.size.width, height: 30))
view.addSubview(button)
let label = UILabel(frame: CGRect(x: 12, y: 7, width: tableView.frame.size.width, height: 30))
label.font = UIFont.systemFont(ofSize: 24)
label.textColor = .white
label.text = "Learn More"
view.addSubview(label)
view.backgroundColor = UIColor.gray // Set your background color
}
else if (tableView == secondTableView) {
let button = UIButton(frame: CGRect(x: 270, y: 15, width:20 , height: 20))
button.tag = section
button.setImage(UIImage(named: "InfoIcon"), for: UIControl.State.normal)
button.addTarget(self,action:#selector(buttonClickedSecond),for:.touchUpInside)
let view = UIView(frame: CGRect(x: 20, y: 8, width: tableView.frame.size.width, height: 30))
view.addSubview(button)
let label = UILabel(frame: CGRect(x: 12, y: 7, width: tableView.frame.size.width, height: 30))
label.font = UIFont.systemFont(ofSize: 24)
label.textColor = .white
label.text = "Get Support"
view.addSubview(label)
view.backgroundColor = UIColor.gray
}
else if (tableView == thirdTableView)
{
let button = UIButton(frame: CGRect(x: 270, y: 15, width:20 , height: 20))
button.tag = section
button.setImage(UIImage(named: "InfoIcon"), for: UIControl.State.normal)
button.addTarget(self,action:#selector(buttonClickedThird),for:.touchUpInside)
let view = UIView(frame: CGRect(x: 20, y: 8, width: tableView.frame.size.width, height: 30))
view.addSubview(button)
let label = UILabel(frame: CGRect(x: 12, y: 7, width: tableView.frame.size.width, height: 30))
label.font = UIFont.systemFont(ofSize: 24)
label.textColor = .white
label.text = "Community"
view.addSubview(label)
view.backgroundColor = UIColor.gray
}
return view
}
Any help and assistance will be appreciated. Thanks!
In your viewForHeaderInSection func, you are creating a UIView object named view inside each if block. At the end of each if block, that object goes out-of-scope... it no longer exists.
Xcode doesn't give you a warning or error on this line:
return view
because view is an existing object of your controller.
This is one of the reasons it's a bad practice to use "built-in" object names for variables you are creating.
Change the top of your func to this:
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let view = UIView(frame: CGRect(x: 20, y: 8, width: tableView.frame.size.width, height: 30))
if(tableView == firstTableView){
// etc...
and remove that line from within each of your if blocks.
Better yet, change it to something like:
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let myHeaderView = UIView(frame: CGRect(x: 20, y: 8, width: tableView.frame.size.width, height: 30))
if(tableView == firstTableView){
// etc... but change all instances of view. to myHeaderView.
} // end of last if block
return myHeaderView
}

How to set button width based on text for dynamically created button in swift 3?

I created the dynamic buttons. I need to change the width of button based on tittle label text. Here is my code.
for i in 0..<holdingSize {
let button = UIButton(type: .custom)
if i == 0 {
frame = CGRect(x: 10, y: 5, width: 100, height: 30)
}else{
buttonY = buttonY + 110
frame = CGRect(x: buttonY, y: 5, width: 100, height: 30)
}
button.setTitle("\(arrayOfHoldings[i])", for: UIControlState.normal) // We are going to use the item name as the Button Title here.
button.titleLabel?.text = "\(arrayOfHoldings[i])"
button.titleLabel?.font = UIFont(name: (button.titleLabel?.font.fontName)!, size: 15)
button.setTitleColor(Colors.green, for: .normal)
button.sizeToFit()
}
Try this
func labelSizeWithString(text: String,fontSize: CGFloat, maxWidth : CGFloat,numberOfLines: Int) -> CGRect{
let font = UIFont.systemFontOfSize(fontSize)//(name: "HelveticaNeue", size: fontSize)!
let label = UILabel(frame: CGRectMake(0, 0, maxWidth, CGFloat.max))
label.numberOfLines = numberOfLines
label.font = font
label.text = text
label.sizeToFit()
return label.frame
}
This will give you the frame of the label, you can set the height of your button from that.
FOR SWIFT 3.0
func labelSize(for text: String,fontSize: CGFloat, maxWidth : CGFloat,numberOfLines: Int) -> CGRect{
let font = UIFont.systemFont(ofSize: fontSize)//(name: "HelveticaNeue", size: fontSize)!
let label = UILabel(frame: CGRect(x: 0, y: 0, width: maxWidth, height: CGFloat.leastNonzeroMagnitude))
label.numberOfLines = numberOfLines
label.font = font
label.text = text
label.sizeToFit()
return label.frame
}

How to center a custom UIView in a TableView?

I'm trying to center a custom view inside a UITableView and it works fine but when i scroll it doesn't update to the center of the tableview it just stays at the top. Here's my code:
let customView = UIView(frame: CGRect(x: 0, y: 0, width: 150, height: 75))
customView.backgroundColor = UIColor(red: 0/255, green: 174/255, blue: 250/255, alpha: 1.0)
let label = UILabel(frame: CGRect(x: customView.frame.midX, y: customView.frame.midY, width: 150, height: 75))
label.text = "Text"
label.textAlignment = .center
label.font = UIFont(name: "HelveticaNeue-Light", size: 18)
label.textColor = UIColor.white
customView.addSubview(label)
label.center = customView.center
customView.layer.cornerRadius = 4.0
self.view.addSubview(customView)
customView.center = CGPoint(x: self.tableView.bounds.width/2, y: self.tableView.bounds.height/2)
UIView.animate(withDuration: 1.5, animations: {
customView.alpha = 0.0
}) { (success: Bool) in
customView.removeFromSuperview()
}
Any ideas on how to make this work? Thanks.
Add the customView in the tableView and not in the view.
self.tableView.addSubview(customView)

Update footer in UITableView

Have custom footer view in my UITableView:
public func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? { // custom view for footer. will be adjusted to default or specified footer height
return footer()
}
func footer() -> UILabel {
let label = UILabel(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.size.width, height: (navigationController?.navigationBar.bounds.size.height)!))
label.backgroundColor = AppColors.Bordo.color
label.font = UIFont.boldSystemFont(ofSize: 16)
label.textColor = .white
label.text = "Selected \(self.selectedGenres.count) of \(self.genres.count)"
label.textAlignment = .center
return label
}
When user select/deselect row in table view I want refresh my footer with info of selected rows. How I can do it without reloading whole tableview?
And what method footerView(forSection: indexPath.section) of UITableView does?
create a global object of label... and init it only when the label is nil... and you can access this label anywhere in code.
let globalLabel : UILabel ?
public func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? { // custom view for footer. will be adjusted to default or specified footer height
return footer()
}
func footer() -> UILabel {
if (globalLabel == nil) {
let label = UILabel(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.size.width, height: (navigationController?.navigationBar.bounds.size.height)!))
label.backgroundColor = AppColors.Bordo.color
label.font = UIFont.boldSystemFont(ofSize: 16)
label.textColor = .white
label.textAlignment = .center
globalLabel = label
}
globalLabel.text = "Selected \(self.selectedGenres.count) of \(self.genres.count)"
return globalLabel
}
Done it using Rajesh Choudhary proposal and computing property:
var selectedGenres: [Genre] = [] {
didSet {
self.footerForTableView.text = titleForFooter
}
}
var titleForFooter: String {
return "Selected \(self.selectedGenres.count) of \(self.genres.count)"
}
lazy var footerForTableView: UILabel = {
let label = UILabel(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.size.width, height: (self.navigationController?.navigationBar.bounds.size.height)!))
label.backgroundColor = AppColors.Bordo.color
label.font = UIFont.boldSystemFont(ofSize: 16)
label.textColor = .white
label.text = self.titleForFooter
label.textAlignment = .center
return label
}()