UIButton Action doesn't call in Swift? - ios

In my project I have create the Left View and Right View, its dynamically show two different Views, Left View side create firstView and the FirstView inside show Title, Comments, Image and Video. And Also RightView side create secondView inside show Title,Comments, Image and Video. Image and Video show only some of the Views. The design is fully created programmatically, my design is given below,
My problem is play button(UIButton) Action not Called why?
I don't know,
my code is give below, UIButton Name: btnPlay, Action Name: buttonAction:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var scrollViewBase: UIScrollView!
var leftView = UIView()
var rightView = UIView()
var wholeYLeft = CGFloat()
var wholeYRight = CGFloat()
let btnPlay = UIButton()
var myArrayOfDict: NSArray = [
["Title": "MacBook", "Text": "Our goal with MacBook was to do the impossible: engineer a full-sized experience into the lightest and most compact Mac notebook ever. That meant reimagining every element to make it not only lighter and thinner but also better.", "Image":"MacBook1","video":""],
["Title": "OS X", "Text": "OS X is the operating system that makes it possible to do all the things you do on a Mac.", "Image":"","video":""],
["Title": "MacBook Pro", "Text": "Now with the force Touch trackpad,longer battery life and faster flash storage", "Image":"MacBookPro1","video":""],
["Title": "Mac Mini", "Text": "Mac mini is an affordable powerhouse that packs the entire Mac experience into a 19.7cm-square frame. Just connect your own display, keyboard and mouse, and you’re ready to make big things happen.", "Image":"Mini","video":""],
["Title": "iMac", "Text": "The idea behind iMac has never wavered: to craft the ultimate desktop experience. The best display, paired with high-performance processors, graphics and storage ", "Image":"","video":""],
["Title": "MacBook Air", "Text": "The 11-inch MacBook Air lasts up to 9 hours between charges and the 13-inch model lasts up to an incredible 12 hours. So from your morning coffee till your evening commute, you can work unplugged.", "Image":"VideoThumn","video":"Official Apple MacBook Air Video YouTube.mp4"]
]
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.title = "Dynamic Cell"
leftView.frame = CGRectMake(0, 0, self.view.frame.width/2, self.view.frame.height)
rightView.frame = CGRectMake(self.view.frame.width/2, 0, self.view.frame.width/2, self.view.frame.height)
// leftView.backgroundColor = UIColor.lightGrayColor()
// rightView.backgroundColor = UIColor.grayColor()
self.scrollViewBase.addSubview(leftView)
self.scrollViewBase.addSubview(rightView)
self.callViewMethod()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func callViewMethod() {
var yFloatLeft : CGFloat! = 5
var yFloatRight : CGFloat! = 5
wholeYLeft = 0
wholeYRight = 0
for var i = 0; i < myArrayOfDict.count; i++ {
let isCheckImage = myArrayOfDict[i].valueForKey("Image") as! String
let isCheckVideo = myArrayOfDict[i].valueForKey("video") as! String
let str = myArrayOfDict[i].valueForKey("Text") as? String
let boundingRectHeight = str!.boundingRectWithSize(CGSizeMake(self.leftView.frame.width-10, CGFloat.max),
options:NSStringDrawingOptions.UsesLineFragmentOrigin,
attributes: [NSFontAttributeName: UIFont(name: "Arial", size: 14.0)!], context:nil).size.height + 60.0
if(i%2 == 0) {
let firstView = UIView()
print(yFloatLeft)
if(isCheckImage == "") {
firstView.frame = CGRectMake(5, yFloatLeft, self.leftView.frame.width-10, 30 + boundingRectHeight)
} else {
firstView.frame = CGRectMake(5, yFloatLeft, self.leftView.frame.width-10, 180 + boundingRectHeight)
}
// firstView.backgroundColor = UIColor.redColor()
firstView.layer.borderWidth = 2.0
firstView.layer.borderColor = UIColor.lightGrayColor().CGColor
leftView.addSubview(firstView)
let lblTitle = UILabel()
lblTitle.frame = CGRectMake(0, 0, self.leftView.frame.width-10, 30)
lblTitle.textAlignment = NSTextAlignment.Center
lblTitle.text = myArrayOfDict[i].valueForKey("Title") as? String
let lblText = lblInset()
lblText.frame = CGRectMake(0, 30, self.leftView.frame.width-10, boundingRectHeight)
lblText.text = myArrayOfDict[i].valueForKey("Text") as? String
lblText.numberOfLines = 0
lblText.lineBreakMode = .ByWordWrapping
lblText.font = UIFont(name: "Arial", size: 16)
lblText.textAlignment = NSTextAlignment.Justified
let mainImageView = UIImageView()
if(isCheckImage == "") {
mainImageView.hidden = true
yFloatLeft = yFloatLeft + 30 + boundingRectHeight + 10
} else {
mainImageView.hidden = false
mainImageView.frame = CGRectMake(0, 30 + boundingRectHeight, self.leftView.frame.width-10, 150)
mainImageView.image = UIImage(named: (myArrayOfDict[i].valueForKey("Image") as? String)!)
if(isCheckVideo == "") {
btnPlay.hidden = true
} else {
btnPlay.hidden = false
btnPlay.frame = CGRectMake((mainImageView.frame.width/2)-10, (mainImageView.frame.height/2)-10, 30, 30)
btnPlay.backgroundColor = UIColor.blackColor()
btnPlay.userInteractionEnabled = true
btnPlay.addTarget(self, action: "buttonAction:", forControlEvents: .TouchUpInside)
btnPlay.setImage(UIImage(named: "Play"), forState: .Normal)
mainImageView.addSubview(btnPlay)
}
yFloatLeft = yFloatLeft + 30 + boundingRectHeight + 160
}
firstView.addSubview(lblTitle)
firstView.addSubview(lblText)
firstView.addSubview(mainImageView)
firstView.bringSubviewToFront(btnPlay)
} else {
let secondView = UIView()
if(isCheckImage == "") {
secondView.frame = CGRectMake(5, yFloatRight, self.rightView.frame.width-10, 30 + boundingRectHeight)
} else {
secondView.frame = CGRectMake(5, yFloatRight, self.rightView.frame.width-10, 180 + boundingRectHeight)
}
// secondView.backgroundColor = UIColor.purpleColor()
secondView.layer.borderWidth = 2.0
secondView.layer.borderColor = UIColor.lightGrayColor().CGColor
rightView.addSubview(secondView)
let lblTitle = UILabel()
lblTitle.frame = CGRectMake(0, 0, self.leftView.frame.width-10, 30)
lblTitle.textAlignment = NSTextAlignment.Center
lblTitle.text = myArrayOfDict[i].valueForKey("Title") as? String
let lblText = lblInset()
lblText.frame = CGRectMake(0, 30, self.leftView.frame.width-10, boundingRectHeight)
lblText.text = myArrayOfDict[i].valueForKey("Text") as? String
lblText.numberOfLines = 0
lblText.lineBreakMode = .ByWordWrapping
lblText.font = UIFont(name: "Arial", size: 16)
lblText.textAlignment = NSTextAlignment.Justified
let mainImageView = UIImageView()
if(isCheckImage == "") {
mainImageView.hidden = true
yFloatRight = yFloatRight + 30 + boundingRectHeight + 10
} else {
mainImageView.hidden = false
mainImageView.frame = CGRectMake(0, 30 + boundingRectHeight, self.leftView.frame.width-10, 150)
mainImageView.image = UIImage(named: (myArrayOfDict[i].valueForKey("Image") as? String)!)
if(isCheckVideo == "") {
btnPlay.hidden = true
} else {
btnPlay.hidden = false
btnPlay.frame = CGRectMake((mainImageView.frame.width/2)-10, (mainImageView.frame.height/2)-10, 30, 30)
btnPlay.userInteractionEnabled = true
btnPlay.backgroundColor = UIColor.blackColor()
btnPlay.setImage(UIImage(named: "Play"), forState: .Normal)
btnPlay.addTarget(self, action: Selector("buttonAction:"), forControlEvents: .TouchUpInside)
mainImageView.addSubview(btnPlay)
}
yFloatRight = yFloatRight + 30 + boundingRectHeight + 160
}
secondView.addSubview(lblTitle)
secondView.addSubview(lblText)
secondView.addSubview(mainImageView)
secondView.bringSubviewToFront(btnPlay)
}
wholeYLeft = yFloatLeft
wholeYRight = yFloatRight
}
print(wholeYLeft)
print(wholeYRight)
leftView.frame = CGRectMake(0, 0, self.view.frame.width/2, wholeYLeft)
rightView.frame = CGRectMake(self.view.frame.width/2, 0, self.view.frame.width/2, wholeYRight)
if(wholeYRight > wholeYLeft) {
self.scrollViewBase.contentSize = CGSize(width:self.view.frame.width, height: wholeYRight)
} else {
self.scrollViewBase.contentSize = CGSize(width:self.view.frame.width, height: wholeYLeft)
}
}
func buttonAction(sender:UIButton!) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let controller = storyboard.instantiateViewControllerWithIdentifier("PlayViewController") as! PlayViewController
controller.lblTitle.text = myArrayOfDict[5].valueForKey("Title") as? String
controller.lblComments.text = myArrayOfDict[5].valueForKey("Text") as? String
self.presentViewController(controller, animated: true, completion: nil)
}
}

I got an Answer, In UIButton (btnPlay) add subview give UIImageView, my problem is mainImageView.addSubview(btnPlay), so change the subView to UIView instead of UIImageView correct code is
secondView.addSubview(btnPlay)
secondView.bringSubviewToFront(btnPlay)
its working for me

You have to enable user interaction for dynamically created Imageview, so write one more line after,
let mainImageView = UIImageView()
mainImageView.userInteractionEnabled = true
Hope this will work.

You have to tag the button then only it can recognise which button is that
btnPlay.tag = 1

Related

iOS spreadsheetview not able to display multiple blocks in cell

I’m using Spreadsheetview library in order to show case Jobber functionality.
There is one critical issues which is blocking project release. This is mentioned below:
Problem: Not able to display multi block content in custom cell.
Scenario: Suppose userA has task1 from 10:00 AM to 12:00 AM, userB has task2 from 10:00 AM to 11:00 AM, userC has task3 from 10:00 AM to 11:30 AM so these three task should be displayed in merged cell with one after another.
Refer below screenshot.
Code:
func spreadsheetView(_ spreadsheetView: SpreadsheetView, cellForItemAt indexPath: IndexPath) -> Cell? {
if self.jobDetails == nil {
return nil
}
. . .
//other cases handled like displaying time, date, visit person name which is not having any issue
. . .
else if case (1...(calenderData.count + 1), 2...(Constants.timeIntervals.count + 1)) = (indexPath.column, indexPath.row) {
let cell = spreadsheetView.dequeueReusableCell(withReuseIdentifier: String(describing: ScheduleCell1.self), for: indexPath) as! ScheduleCell1
if(cell.firstBlockLabel.text != nil) || (cell.secondBlockLabel.text != nil) || (cell.thirdBlockLabel.text != nil) {
return nil
}
let visits = calenderData[indexPath.column - 1].calendarRows
for visit in visits {
let diff = findTimeDifference(firstTime: cellTime,secondTime: visit.startTime)
print("startTime: \(visit.startTime) endTime \(visit.endTime) title \(visit.title) totalBlocks \(visit.totalBlocks)")
if(diff >= -30 && diff <= 30 && diff != -1) {
switch visit.totalBlocks {
case 0,1:
cell.firstBlockLabel.isHidden = false
cell.secondBlockLabel.isHidden = true
cell.thirdBlockLabel.isHidden = true
cell.firstBlockLabel.text = "1 - case 1"
if visit.blockSerialNo == 1 {
if(visit.statusCode.caseInsensitiveCompare("completed") == .orderedSame){
cell.firstBlockLabel.attributedText = "\(visit.title)".strikeThrough()
} else {
cell.firstBlockLabel.text = "\(visit.title)"
}
cell.firstBlockLabel.backgroundColor = hexStringToUIColor(hex: visit.statusTagProp.background)
cell.firstBlockLabel.textColor = hexStringToUIColor(hex: visit.statusTagProp.text)
}
case 2:
cell.firstBlockLabel.isHidden = false
cell.secondBlockLabel.isHidden = false
cell.thirdBlockLabel.isHidden = true
cell.firstBlockLabel.text = "1 - case 2"
cell.secondBlockLabel.text = "2 - case 2"
if visit.blockSerialNo == 2 {
if(visit.statusCode.caseInsensitiveCompare("completed") == .orderedSame){
cell.secondBlockLabel.attributedText = "\(visit.title)".strikeThrough()
} else {
cell.secondBlockLabel.text = "\(visit.title)"
}
cell.secondBlockLabel.backgroundColor = hexStringToUIColor(hex: visit.statusTagProp.background)
cell.secondBlockLabel.textColor = hexStringToUIColor(hex: visit.statusTagProp.text)
}
case 3:
cell.firstBlockLabel.isHidden = false
cell.secondBlockLabel.isHidden = false
cell.thirdBlockLabel.isHidden = false
cell.firstBlockLabel.text = "1 - case 3"
cell.secondBlockLabel.text = "2 - case 3"
cell.thirdBlockLabel.text = "3 - case 3"
if visit.blockSerialNo == 3 {
if(visit.statusCode.caseInsensitiveCompare("completed") == .orderedSame){
cell.thirdBlockLabel.attributedText = "\(visit.title)".strikeThrough()
} else {
cell.thirdBlockLabel.text = "\(visit.title)"
}
cell.thirdBlockLabel.backgroundColor = hexStringToUIColor(hex: visit.statusTagProp.background)
cell.thirdBlockLabel.textColor = hexStringToUIColor(hex: visit.statusTagProp.text)
}
default:
break
}
break
}
}
return cell
}
return nil
}
class ScheduleCell1: Cell {
let firstBlockLabel = UILabel()
let secondBlockLabel = UILabel()
let thirdBlockLabel = UILabel()
let stackview = UIStackView()
let lineLabel = UILabel()
var lineYPosition: Int = 0
override var frame: CGRect {
didSet {
firstBlockLabel.frame = CGRect(x: 0, y: 0, width: 500, height: 500)
secondBlockLabel.frame = CGRect(x: 0, y: 0, width: 500, height: 500)
thirdBlockLabel.frame = CGRect(x: 0, y: 0, width: 500, height: 500)
lineLabel.frame = bounds.insetBy(dx: 0, dy: 0)
lineLabel.frame = CGRect(x: 0, y: lineYPosition, width: 300, height: 1)
}
}
override init(frame: CGRect) {
super.init(frame: frame)
lineLabel.frame = bounds
lineLabel.backgroundColor = .red
firstBlockLabel.textAlignment = .center
//firstBlockLabel.text = "firstBlockLabel"
firstBlockLabel.numberOfLines = 0
firstBlockLabel.lineBreakMode = .byTruncatingTail
firstBlockLabel.translatesAutoresizingMaskIntoConstraints = false
secondBlockLabel.textAlignment = .center
//secondBlockLabel.text = "secondBlockLabel"
secondBlockLabel.numberOfLines = 0
secondBlockLabel.lineBreakMode = .byTruncatingTail
secondBlockLabel.translatesAutoresizingMaskIntoConstraints = false
thirdBlockLabel.textAlignment = .center
//thirdBlockLabel.text = "thirdBlockLabel"
thirdBlockLabel.numberOfLines = 0
thirdBlockLabel.lineBreakMode = .byTruncatingTail
thirdBlockLabel.translatesAutoresizingMaskIntoConstraints = false
stackview.frame = bounds
stackview.axis = .horizontal
stackview.spacing = .leastNonzeroMagnitude
stackview.contentMode = .scaleToFill
stackview.translatesAutoresizingMaskIntoConstraints = false
stackview.alignment = .fill
stackview.distribution = .fill
stackview.distribution = .fillProportionally
stackview.addArrangedSubview(firstBlockLabel)
stackview.addArrangedSubview(secondBlockLabel)
stackview.addArrangedSubview(thirdBlockLabel)
firstBlockLabel.backgroundColor = .yellow
secondBlockLabel.backgroundColor = .purple
thirdBlockLabel.backgroundColor = .green
stackview.backgroundColor = .magenta
//contentView.backgroundColor = .magenta
contentView.addSubview(lineLabel)
contentView.bringSubviewToFront(lineLabel)
contentView.addSubview(stackview)
stackview.leadingAnchor.constraint(equalTo: contentView.leadingAnchor).isActive = true
stackview.trailingAnchor.constraint(equalTo: contentView.trailingAnchor).isActive = true
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
So I’ve added two property totalBlocks (determines how may blocks to be displayed) and BlockSrNo (determines which serial number of block). Logic for this is mentioned below:
func determineMultiBlocks() {
for data in calenderData {
let visits = data.calendarRows
for var i in 0..<visits.count {
let visit = visits[i]
for var j in (i+1)..<visits.count {
let nextVisit = visits[j]
let timeOverlapExists = CheckIfTimeExistBetweenTwoTimeInterval(withStartTime: visit.startTime.timeInSeconds, withEndTime: visit.endTime.timeInSeconds, withTimeToCheck: nextVisit.startTime.timeInSeconds)
if timeOverlapExists {
visit.totalBlocks = visit.totalBlocks + 1
nextVisit.totalBlocks = 0 //nextVisit.totalBlocks - 1
nextVisit.blockSerialNo = visit.totalBlocks
j = j + 1
}
}
break
}
Can help me where am I going wrong? If there is any other solution instead of using totalBlocks/blockSerialNo then let me know.
Appreciate all solutions!

UITapGestureRecognizer doesn't work properly

I made the function updateItems() which create, from an array, many UIView's in a UIScrollView :
Here is the file where this function is :
class MainViewController: UIViewController {
#IBOutlet weak var body: UIScrollView!
#IBOutlet weak var edit: UIButton!
var _title: String = "Title"
var _isEditing: Bool = false
var firstItems: [UISectionView] = []
override func viewDidLoad() {
super.viewDidLoad()
navigationController?.navigationBar.prefersLargeTitles = true
navigationController?.navigationBar.topItem?.title = self._title
navigationController?.navigationItem.largeTitleDisplayMode = .automatic
body.contentSize = CGSize(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height + 100)
self.updateItems(self.firstItems)
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
public func updateItems(_ s: [UISectionView]) {
let topMargin = 10
let rightMargin = 10
let leftMargin = 10
let space = 5
let heightItem = 60
var b = topMargin
for i in body.subviews {
i.removeFromSuperview()
}
for t in s {
if t.isHidden == true {
continue
}
if t.title != nil {
let f = UIFont(name: "Helvetica", size: 20)
let l = UILabel(frame: CGRect(x: rightMargin, y : b, width: Int(UIScreen.main.bounds.width) - (rightMargin + leftMargin), height: Int(f!.lineHeight)))
l.font = f
l.text = t.title
body.addSubview(l)
b = b + Int(f!.lineHeight) + space
}
for i in t.items{
body.addSubview(i.getView(frame: CGRect(x: rightMargin, y: b, width: Int(UIScreen.main.bounds.width) - (rightMargin + leftMargin), height: heightItem), view: self))
b = b + heightItem + space
}
}
}
}
TIPS : UISectionView is an object which contains an array of UIItemView
The object UIItemView looks like :
class UIItemView {
var icon: UIImage = UIImage();
var line1: rString = rString("")!;
var line2: rString = rString("")!;
var leftline: Any = String();
var background: String = "white"
var onItemTap: (_ sender: UITapGestureRecognizer?) -> () = {sender in }
var onItemLongPress: (_ sender: UILongPressGestureRecognizer?) -> () = {sender in }
var id: String
init?(_ id: String) {
self.id = id
}
public func getView(frame: CGRect, view: UIViewController) -> UIView {
let width = Int(frame.width)
let height = Int(frame.height)
let rightMargin = 20
let leftMargin = 10
let topMargin = 10
let bottomMargin = 10
let iconSide = height - (topMargin + bottomMargin)
let marginLine = leftMargin + iconSide + 10
let v = UIView(frame: frame)
//Background & shape
if self.background == "white" {
v.backgroundColor = UIColor.white;
} else if self.background == "blur" {
let bEV = UIVisualEffectView(effect: UIBlurEffect(style: UIBlurEffectStyle.extraLight))
bEV.frame = v.bounds
bEV.autoresizingMask = [.flexibleWidth, .flexibleHeight]
v.addSubview(bEV)
}
v.layer.cornerRadius = 10.0
//Icon
let i = UIImageView()
i.image = self.icon;
i.frame = CGRect(x: leftMargin, y: topMargin, width: iconSide, height: iconSide)
v.addSubview(i)
//First Line
let l1 = self.line1.getLabel()
l1.frame = CGRect(x: marginLine, y: topMargin, width: width - (marginLine + leftMargin), height: Int(self.line1.getFont().lineHeight))
v.addSubview(l1)
//Seconde Line
let l2 = self.line2.getLabel()
l2.frame = CGRect(x: marginLine, y: height - (bottomMargin + Int(self.line1.getFont().lineHeight)), width: width - (marginLine + leftMargin), height: Int(self.line1.getFont().lineHeight))
v.addSubview(l2)
//Left Line
if type(of: self.leftline) == type(of: SpinnerView()) {
let sv = (self.leftline as! SpinnerView)
sv.frame = CGRect(x: width - (rightMargin + iconSide), y: height/2 - iconSide/2, width: iconSide, height: iconSide)
v.addSubview(sv)
} else if type(of: self.leftline) == type(of: rString("")) {
let rS = (self.leftline as! rString)
if rS.text != "" {
rS.fontName = "HelveticaNeue-Bold"
rS.size = 15
rS.color = UIColor(red:0.01, green:0.48, blue:1.00, alpha:1.0)
let l3 = rS.getLabel()
l3.frame = CGRect(x: width - (rightMargin + Int(rS.getFont().lineWidth(rS.text)) + 15), y: height/2 - (Int(rS.getFont().lineHeight) + 10)/2, width: Int(rS.getFont().lineWidth(rS.text)) + 15, height: Int(rS.getFont().lineHeight) + 10)
l3.backgroundColor = UIColor(red:0.94, green:0.94, blue:0.97, alpha:1.0)
l3.layer.masksToBounds = true
l3.layer.borderWidth = 2
l3.layer.borderColor = UIColor(red:0.94, green:0.94, blue:0.97, alpha:1.0).cgColor
l3.layer.cornerRadius = rS.getFont().lineHeight/1.2
l3.textAlignment = .center
v.addSubview(l3)
}
}
//GestureRecognizer
v.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.oIT(_:))))
v.addGestureRecognizer(UILongPressGestureRecognizer(target: self, action: #selector(self.oILP(_:))))
v.restorationIdentifier = self.id
return v;
}
#objc func oIT(_ sender: UITapGestureRecognizer) {
print("Tap")
self.onItemTap(sender)
}
#objc func oILP(_ sender: UILongPressGestureRecognizer) {
print("LongPress")
self.onItemLongPress(sender)
}
static func ==(lhs: UIItemView, rhs: UIItemView) -> Bool {
return lhs === rhs
}
}
TIPS : UIItemView contains the function getView() which returns a specific UIView
The problem :
Everything work properly, when I load the ViewController (where there is the UIScrollView) every UIView's are build like I want, and I can interact with the UIView by the UITapGestureRecognizer or the UILongPressGestureRecognizer (the function is called as expected)
BUT
When I call the function updateItems() a second time, without reload the ViewController, the items change as expected but the UITapGestureRecognizer and the UILongPressGestureRecognizer don't work any more.
I hope you can help me :D
If information are missing for you to understand the problem, please let me know ;)

how to define a label by a tag

i try a make a cloud of tag, and i have trouble with how to determine which label was pressed, for to the change color it. if i use like viewq.viewWithTag(1) it work but how i can understand what a label i press ? for change value. Maybe i need a make class ? because i want (if u press once, set color red and some action, if again it set blue color again and make some action)
//
// ViewController.swift
// weqddwqd
//
// Created by Jacket on 4/2/18.
// Copyright © 2018 TryFit. All rights reserved.
//
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var viewq: UIView!
var arrq: [String] = ["Hello", "World", "of", "Tags"]
var tags: [Int] = Array()
override func viewDidLoad() {
super.viewDidLoad()
createTagsLabel(arrq)
}
}
extension ViewController {
func createTagsLabel(_: [String]) {
var xPos:CGFloat = 15.0
var ypos: CGFloat = 130.0
var tag: Int = 0
for word in arrq {
let width = word.widthOfString(usingFont: UIFont(name:"verdana", size: 13.0)!)
let checkWholeWidth = CGFloat(xPos) + CGFloat(width) + CGFloat(13.0) + CGFloat(25.5)
if checkWholeWidth > UIScreen.main.bounds.size.width - 30.0 {
xPos = 15.0
ypos = ypos + 29.0 + 8.0
}
let textlable = UILabel(frame: CGRect(x: xPos, y: ypos, width: width + 18, height: 18))
textlable.layer.borderWidth = 1.8
textlable.layer.cornerRadius = 8
textlable.layer.borderColor = UIColor(red:0.00, green:0.48, blue:1.00, alpha:1.0).cgColor
textlable.textColor = UIColor(red:0.00, green:0.48, blue:1.00, alpha:1.0)
textlable.text = word
textlable.font = UIFont(name: "verdana", size: 13.0)
textlable.textAlignment = .center
textlable.isUserInteractionEnabled = true
ypos = ypos + 25
textlable.tag = tag
tags.append(tag)
tag = tag + 1
let tap = UITapGestureRecognizer(target: self, action: #selector(self.tapFunction(_:)))
//textlable.addTarget(self, action: #selector(tapFunction(_:)), for: .touchUpInside)
textlable.addGestureRecognizer(tap)
viewq.addSubview(textlable)
}
}
func tapFunction(_ recognizer: UITapGestureRecognizer) {
print(viewq.viewWithTag(1))
let tag = viewq.viewWithTag(1) as! UILabel
tag.layer.borderColor = UIColor .red.cgColor
tag.textColor = UIColor .red
print("Added")
}
}
extension String {
func widthOfString(usingFont font: UIFont) -> CGFloat {
let fontAttributes = [NSFontAttributeName: font]
let size = self.size(attributes: fontAttributes)
return size.width
}
func heightOfString(usingFont font: UIFont) -> CGFloat {
let fontAttributes = [NSFontAttributeName: font]
let size = self.size(attributes: fontAttributes)
return size.height
}
}
Your tapFunction can easily get the tapped view from the gesture. No tags required:
func tapFunction(_ recognizer: UITapGestureRecognizer) {
if let tappedLabel = recognizer.view as? UILabel {
tappedLabel.layer.borderColor = UIColor.red.cgColor
tappedLabel.textColor = .red
print("Added")
}
}

How to add small red dot in UITabBarItem

How to add red dot on the top right side of the UITabBarItem.
I have searched a while and some guys said this can be done setting Badge Value of the UITabBarItem.But when I give it a try and set badge value to empty space " ",the red dot is somewhat big.How can I get a proper one?Big thanks.
If you want to avoid traversing subviews & potentially dangerous hacks in general, what I've done is set the badge's background colour to clear and used a styled bullet point to appear as a badge:
tabBarItem.badgeValue = "●"
tabBarItem.badgeColor = .clear
tabBarItem.setBadgeTextAttributes([NSAttributedStringKey.foregroundColor.rawValue: UIColor.red], for: .normal)
This seems more future-proof than the other answers.
you can try this method:
func addRedDotAtTabBarItemIndex(index: Int) {
for subview in tabBarController!.tabBar.subviews {
if let subview = subview as? UIView {
if subview.tag == 1314 {
subview.removeFromSuperview()
break
}
}
}
let RedDotRadius: CGFloat = 5
let RedDotDiameter = RedDotRadius * 2
let TopMargin:CGFloat = 5
let TabBarItemCount = CGFloat(self.tabBarController!.tabBar.items!.count)
let HalfItemWidth = CGRectGetWidth(view.bounds) / (TabBarItemCount * 2)
let xOffset = HalfItemWidth * CGFloat(index * 2 + 1)
let imageHalfWidth: CGFloat = (self.tabBarController!.tabBar.items![index] as! UITabBarItem).selectedImage.size.width / 2
let redDot = UIView(frame: CGRect(x: xOffset + imageHalfWidth, y: TopMargin, width: RedDotDiameter, height: RedDotDiameter))
redDot.tag = 1314
redDot.backgroundColor = UIColor.redColor()
redDot.layer.cornerRadius = RedDotRadius
self.tabBarController?.tabBar.addSubview(redDot)
}
set the badgeValue for your desired UITabBarItem as follow:
// for first tab
(tabBarController!.tabBar.items!.first! as! UITabBarItem).badgeValue = "1"
//for second tab
(tabBarController!.tabBar.items![1] as! UITabBarItem).badgeValue = "2"
// for last tab
(tabBarController!.tabBar.items!.last! as! UITabBarItem).badgeValue = "final"
for remove a badge from the UITabBarItem just assign nil
(tabBarController!.tabBar.items!.first! as! UITabBarItem).badgeValue = nil
you can get the output Like
for additional information please ref this link
Choice --2
var lbl : UILabel = UILabel(frame: CGRectMake(225, 5, 20, 20))
lbl.layer.borderColor = UIColor.whiteColor().CGColor
lbl.layer.borderWidth = 2
lbl.layer.cornerRadius = lbl.bounds.size.height/2
lbl.textAlignment = NSTextAlignment.Center
lbl.layer.masksToBounds = true
lbl.font = UIFont(name: hereaddyourFontName, size: 13)
lbl.textColor = UIColor.whiteColor()
lbl.backgroundColor = UIColor.redColor()
lbl.text = "1" //if you no need remove this
// add subview to tabBarController?.tabBar
self.tabBarController?.tabBar.addSubview(lbl)
the output is
That is very simple in current iOS versions
tabBarItem.badgeValue = " "
it shows the red dot on the top of the tabbar item
Swift 5+
This goes into the controller that belongs to the tab
alt. you just need to grab the right tabBarItem
func updateTabBarBadge(showDot: Bool) {
guard let tbi = tabBarItem else {
return
}
if showDot {
tbi.setBadgeTextAttributes([.font: UIFont.systemFont(ofSize: 6), .foregroundColor:UIColor(named: "Primary")!], for: .normal)
tbi.badgeValue = "⬤"
tbi.badgeColor = UIColor.clear
} else {
tbi.badgeValue = nil
}
}
I have figured out a hack solution.
func addRedDotAtTabBarItemIndex(index: Int,dotRadius: CGFloat) {
var tabBarButtons = [UIView]()
// find the UITabBarButton instance.
for subview in tabBarController!.tabBar.subviews.reverse() {
if subview.isKindOfClass(NSClassFromString("UITabBarButton")) {
tabBarButtons.append(subview as! UIView)
}
}
if index >= tabBarButtons.count {
println("out of bounds")
return
}
let tabBar = tabBarButtons[index]
var selectedImageWidth: CGFloat!
var topMargin: CGFloat!
for subview in tabBar.subviews {
if subview.isKindOfClass(NSClassFromString("UITabBarSwappableImageView")) {
selectedImageWidth = (subview as! UIView).frame.size.width
topMargin = (subview as! UIView).frame.origin.y
}
}
// remove existing red dot.
for subview in tabBar.subviews {
if subview.tag == 999 {
subview.removeFromSuperview()
}
}
let redDot = UIView(frame: CGRect(x: CGRectGetMidX(tabBar.bounds) + selectedImageWidth / 2 + dotRadius, y: topMargin, width: dotRadius * 2, height: dotRadius * 2))
redDot.backgroundColor = UIColor.redColor()
redDot.layer.cornerRadius = dotRadius // half of the view's height.
redDot.tag = 999
tabBar.addSubview(redDot)
}
Works both for iPad and iPhone.
Be able to hide and calculate index automatically.
Call self.setTabBarDotVisible(visible:true) if self is not an UITabBarController.
Call self.setTabBarDotVisible(visible:true, index:2) if self is an UITabBarController.
import UIKit
public extension UIViewController {
func setTabBarDotVisible(visible:Bool,index: Int? = nil) {
let tabBarController:UITabBarController!
if self is UITabBarController
{
tabBarController = self as! UITabBarController
}
else
{
if self.tabBarController == nil
{
return
}
tabBarController = self.tabBarController!
}
let indexFinal:Int
if (index != nil)
{
indexFinal = index!
}
else
{
let index3 = tabBarController.viewControllers?.index(of: self)
if index3 == nil
{
return;
}
else
{
indexFinal = index3!
}
}
guard let barItems = tabBarController.tabBar.items else
{
return
}
//
let tag = 8888
var tabBarItemView:UIView?
for subview in tabBarController.tabBar.subviews {
let className = String(describing: type(of: subview))
guard className == "UITabBarButton" else {
continue
}
var label:UILabel?
var dotView:UIView?
for subview2 in subview.subviews {
if subview2.tag == tag {
dotView = subview2;
}
else if (subview2 is UILabel)
{
label = subview2 as? UILabel
}
}
if label?.text == barItems[indexFinal].title
{
dotView?.removeFromSuperview()
tabBarItemView = subview;
break;
}
}
if (tabBarItemView == nil || !visible)
{
return
}
let barItemWidth = tabBarItemView!.bounds.width
let x = barItemWidth * 0.5 + (barItems[indexFinal].selectedImage?.size.width ?? barItemWidth) / 2
let y:CGFloat = 5
let size:CGFloat = 10;
let redDot = UIView(frame: CGRect(x: x, y: y, width: size, height: size))
redDot.tag = tag
redDot.backgroundColor = UIColor.red
redDot.layer.cornerRadius = size/2
tabBarItemView!.addSubview(redDot)
}
}
i test this question's answer. but not work on iPad.
now i found that, when u add this on iPhone, tabBarItem left and right margin is 2, and each items margin is 4. Code as below:
NSInteger barItemCount = self.tabBar.items.count;
UITabBarItem *barItem = (UITabBarItem *)self.tabBar.items[index];
CGFloat imageHalfWidth = barItem.image.size.width / 2.0;
CGFloat barItemWidth = (BXS_WINDOW_WIDTH - barItemCount * 4) / barItemCount;
CGFloat barItemMargin = 4;
CGFloat redDotXOffset = barItemMargin / 2 + barItemMargin * index + barItemWidth * (index + 0.5);
and iPad as below:
barItemWidth = 76;
barItemMargin = 34;
redDotXOffset = (BXS_WINDOW_WIDTH - 76 * barItemCount - 34 * (barItemCount - 1)) / 2.0 + 76 * (index + 0.5) + 34 * index;
Hope this is useful.
This it Swift 4 solution:
1) Add BaseTabBar custom class to your project:
import UIKit
class BaseTabBar: UITabBar {
static var dotColor: UIColor = UIColor.red
static var dotSize: CGFloat = 4
static var dotPositionX: CGFloat = 0.8
static var dotPositionY: CGFloat = 0.2
var dotMap = [Int: Bool]()
func resetDots() {
dotMap.removeAll()
}
func addDot(tabIndex: Int) {
dotMap[tabIndex] = true
}
func removeDot(tabIndex: Int) {
dotMap[tabIndex] = false
}
override func draw(_ rect: CGRect) {
super.draw(rect)
if let items = items {
for i in 0..<items.count {
let item = items[i]
if let view = item.value(forKey: "view") as? UIView, let dotBoolean = dotMap[i], dotBoolean == true {
let x = view.frame.origin.x + view.frame.width * BaseTabBar.dotPositionX
let y = view.frame.origin.y + view.frame.height * BaseTabBar.dotPositionY
let dotPath = UIBezierPath(ovalIn: CGRect(x: x, y: y, width: BaseTabBar.dotSize, height: BaseTabBar.dotSize))
BaseTabBar.dotColor.setFill()
dotPath.fill()
}
}
}
}
}
2) Change the custom class of UITabBar inside your UITabBarController to BaseTabBar.
3) Manage the dots in the place where you can access the tabBarController
func updateNotificationCount(count: Int) {
if let tabBar = navigationController?.tabBarController?.tabBar as? BaseTabBar {
if count > 0 {
tabBar.addDot(tabIndex: 0)
} else {
tabBar.removeDot(tabIndex: 0)
}
tabBar.setNeedsDisplay()
}
}
I added 5 tab bar indexes and add the dot points according to the notification occurs. First, create Dots view array.
var Dots = [UIView](repeating: UIView(), count: 5)
func addRedDotAtTabBarItemIndex(index: Int) {
if self.Dots[index].tag != index {
let RedDotRadius: CGFloat = 7
let RedDotDiameter = RedDotRadius
let TopMargin:CGFloat = 2
let tabSize = self.tabBarController.view.frame.width / CGFloat(5)
let xPosition = tabSize * CGFloat(index - 1)
let tabHalfWidth: CGFloat = tabSize / 2
self.Dots[index] = UIView(frame: CGRect(x: xPosition + tabHalfWidth - 2 , y: TopMargin, width: RedDotDiameter, height: RedDotDiameter))
self.Dots[index].tag = index
self.Dots[index].backgroundColor = UIColor.red
self.Dots[index].layer.cornerRadius = RedDotRadius
self.tabBarController.tabBar.addSubview(self.Dots[index])
}
}
If you want to remove the dot from selected index, use this code:
func removeRedDotAtTabBarItemIndex(index: Int) {
self.Dots[index].removeFromSuperview()
self.Dots[index].tag = 0
}
simple solution
set space in storyboard tabbaritem badge value.
if we add space below output you can get:
In Swift 5:
tabBarItem.badgeValue = "1"
to change from default color use:
tabBarItem.badgeColor = UIColor.systemBlue
From iOS 13, use UITabBarAppearance and UITabBarItemAppearance
let appearance = UITabBarAppearance()
let itemAppearance = UITabBarItemAppearance(style: .stacked)
itemAppearance.normal.badgeBackgroundColor = .clear
itemAppearance.normal.badgeTextAttributes = [.foregroundColor: UIColor.red]
profileViewController.tabBarItem.badgeValue = "●"

Performing a segue from a button called from NSObject

I have 2 ViewControllers :
1) MainViewController
2) WebViewController
and a segue with identifier ShowWeb.
MainViewController Contain Multiple NSObjects instances initiated from one class Name AppView: NSObject
inside each NSObject there is a UIButton that I want it to perform the segue of type show.
How to perform the segue?
sorry if my question is repeated but i searched yesterday for about 4 hours all the site and didn't find the exact manner, and to know I am using swift.
I Will explain more clearly:
class MainViewController: {
var appviews = [AppView]()
override func viewDidLoad() {
super.viewDidLoad()
for i = 0; i < MyApps.count ; ++i{
var appview = AppView()
appview = AppView(sourceView: AppsScrollView, AppIconURLString: AppPicture,AppName: "MyAppName", LoadedDescription:"Very Good Application", ObjectNo: i, LinkButtonString: "http://stackoverflow.com/posts/28288611")
appviews.append(appview)
}
}
//
// AppView.swift
// Arabic Apps
//
// Created by d-point on 3/24/1436 AH.
// Copyright (c) 1436 e-Dever. All rights reserved.
//
import UIKit
class AppView: NSObject {
var BackView = UIView()
var AppIconView = UIImageView()
var TitleLabel = UILabel()
var DescriptionLabel = UILabel()
var LinkIcon = UIImageView()
var AppNo:Int!
var DescriptionText:String!
var AppTitleName:String!
let originView:UIView!
let LinkImage = UIImage(named: "HyperLink.png")
var LinkButton = UIButton.buttonWithType(UIButtonType.System) as UIButton
let TitleHeight:CGFloat = 20.0
let DescHeight:CGFloat = 40.0
let BackViewHeight:CGFloat = 100.0
let AppIconSize:CGFloat = 80.0
let Inset:CGFloat = 10.0
let BackgroundAlpha:CGFloat = 0.5
let LinkButtonSize:CGFloat = 35.0
var LinkButtonPath = String()
var MyViewController = UIViewController()
override init() {
super.init ()
}
init(sourceView:UIView, AppIconURLString: String? , AppName: String,LoadedDescription: String , ObjectNo: Int , LinkButtonString: NSString){
super.init()
originView = sourceView
AppIconView.image = UIImage(named: "App-Icon-Copy.png")
if var Icon = AppIconURLString {
ImagesLoader.downloadImage(NSURL(string: Icon), handler: {image, error in
self.AppIconView.image = image
})}
AppTitleName = AppName
DescriptionText = LoadedDescription
AppNo = ObjectNo
LinkButtonPath = LinkButtonString
setupAppView()
}
func setupAppView() {
//SetupBackView
BackView.frame = CGRectMake(Inset,
Inset + (CGFloat(AppNo) * (BackViewHeight + 15)),
originView.bounds.size.width - (Inset * 2),
BackViewHeight)
BackView.backgroundColor = UIColor.whiteColor().colorWithAlphaComponent(BackgroundAlpha)
BackView.layer.cornerRadius = 20.0
BackView.clipsToBounds = false
originView.addSubview(BackView)
//SetupAppIconView
AppIconView.frame = CGRectMake(BackView.bounds.size.width - AppIconSize - Inset, Inset, AppIconSize, AppIconSize)
AppIconView.layer.cornerRadius = 15.0
AppIconView.layer.borderWidth = 2.0
AppIconView.layer.borderColor = UIColor.whiteColor().CGColor
AppIconView.clipsToBounds = true
BackView.addSubview(AppIconView)
//SetupTitleView
TitleLabel.frame = CGRectMake(Inset, Inset, BackView.bounds.size.width - AppIconSize - Inset*6, TitleHeight)
TitleLabel.text = AppTitleName
TitleLabel.textColor = UIColor.blackColor()
TitleLabel.textAlignment = NSTextAlignment.Center
//TitleLabel.font = UIFont(name: TitleLabel.font.fontName, size: 18.0)
TitleLabel.font = UIFont.boldSystemFontOfSize(16.0)
BackView.addSubview(TitleLabel)
//SetupDescriptionLabel
DescriptionLabel.frame = CGRectMake(Inset, TitleHeight, BackView.bounds.size.width - AppIconSize - Inset*6, DescHeight)
DescriptionLabel.text = DescriptionText
DescriptionLabel.textColor = UIColor.blackColor()
DescriptionLabel.textAlignment = NSTextAlignment.Justified
BackView.addSubview(DescriptionLabel)
//SetupButtonView
//LinkButton
LinkButton.frame = BackView.bounds
LinkButton.addTarget(self, action:"GotoLinkURL:", forControlEvents:UIControlEvents.TouchUpInside)
LinkButton.tag = AppNo
BackView.addSubview(LinkButton)
}
func GotoLinkURL(sender:UIButton) {
var mainviewcontroller:MainViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("MainView") as MainViewController
mainviewcontroller.performSegueWithIdentifier("ShowWeb", sender: self)
}
}

Resources