Access subview controls of a UIButton - ios

I added a UILabel as subview of a UIButton as
var actLabel = UILabel(frame: CGRectMake(35, 0, 90, favHeight))
actLabel.font = UIFont(name: "Helvetica", size: 14)
actLabel.text = "Actions"
actLabel.textColor = darkBlueColor
actLabel.textAlignment = NSTextAlignment.Center
actPanel.addSubview(actLabel)
where actPanel is a UIButton
On action of this UIButton I want to access the controls of this UILabel. How can I do that?

Subclass UIButton
class ActionButton : UIButton {
var actionLabel: UILabel!
}
var actLabel = UILabel(frame: CGRectMake(35, 0, 90, favHeight))
actLabel.font = UIFont(name: "Helvetica", size: 14)
actLabel.text = "Actions"
actLabel.textColor = darkBlueColor
actLabel.textAlignment = NSTextAlignment.Center
actPanel.addSubview(actLabel)
actPanel.actionLabel = actLabel
Or build the smarts into the class
class ActionButton : UIButton {
var favoriteHeight: CGFloat = 80 // Or whatever default you want.
var darkBlueColor: UIColor = UIColor(red: 0, green: 0, blue: 0.75, alpha: 1) // Or whatever
#IBOutlet var actionLabel: UILabel! {
get {
if _actionLabel == nil {
var actLabel = UILabel(frame: CGRectMake(35, 0, 90, favoriteHeight))
actLabel.font = UIFont(name: "Helvetica", size: 14)
actLabel.textColor = darkBlueColor
actLabel.textAlignment = NSTextAlignment.Center
addSubview(actLabel)
_actionLabel = actLabel
}
return _actionLabel
}
set {
_actionLabel?.removeFromSuperview()
_actionLabel = newValue
if let label = _actionLabel {
addSubview(label)
}
}
}
override func willMoveToSuperview(newSuperview: UIView?) {
// Ensure actionLabel exists and the text has a value.
if actionLabel.text == nil || actionLabel.text!.isEmpty {
actionLabel.text = "Action" // Provide a default value
}
}
private var _actionLabel: UILabel!
}

You can access all subviews by
var subviews = actPanel.subviews()
Then you can iterate through that array and find your label.
But if you have this label as title of the button, UIButton already has its own titleLabel.

If you created a class for the actPanel and added the label as property you can access it with actPanel.actLabel.text = "Actions" else you can access it like you already did: actLabel.text = "Actions"

Related

Search Bar textfield cursor color not changing in mac Catalyst it's showing black color ios swift

i also try to change with "searchController.searchBar.searchTextField.tintColor = .white"
but it's not working issue facing after xcode 13 update.
Try to create a custom searchController and into the setup to change the tintColor of all the subviews that are different of UIButton .
Here an example :
class CustomSearchController: UISearchController {
var placeHolder:String?
private var catalogSearchBar = CatalogSearchBar()
override public var searchBar: UISearchBar {
get {
catalogSearchBar.placeholder = placeHolder
return catalogSearchBar
}
}
}
class CatalogSearchBar: UISearchBar {
init() {
super.init(frame: .zero)
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
override func layoutSubviews() {
super.layoutSubviews()
setup()
}
private func setup() {
backgroundColor = Constants.shared.navigationBar.lightModeBgColor
// text field
let textField = searchTextField
textField.subviews.forEach { (view) in
if ((view as? UIButton) != nil) {
view.tintColor = UIColor.white
}
}
textField.frame.size.height = 35
self.searchTextPositionAdjustment = UIOffset(horizontal: 4, vertical: 0)
textField.layer.cornerRadius = 15
textField.placeholder = self.placeholder
textField.attributedPlaceholder = NSAttributedString(string: self.placeholder != nil ? self.placeholder! : "", attributes: [NSAttributedString.Key.foregroundColor: UIColor.white])
textField.layer.masksToBounds = true
textField.layer.backgroundColor = UIColor.white.withAlphaComponent(0.25).cgColor
if let view = textField.value(forKey: "backgroundView") as? UIView {
view.removeFromSuperview()
}
textField.font = UIFont(name: "Montserrat-Regular", size: 15)
textField.textColor = UIColor.white
textField.tintColor = UIColor.white
// search icon
let leftView: UIView = {
let image = UIImage(named: "search")
let padding = 8
let size = 20
let outerView = UIView(frame: CGRect(x: 0, y: 0, width: size + padding, height: size) )
let iconView = UIImageView(frame: CGRect(x: padding, y: 0, width: size, height: size))
iconView.tintColor = UIColor.white
iconView.image = image
outerView.addSubview(iconView)
return outerView
}()
textField.leftView = leftView
}
}

How to change the text attribute of a UILabel in Swift?

I've set up a UILabel programmatically and I'm attempting to change the text attribute via a function I call later on in the ViewController however when that function is called the questionLabel.text stays the default value "Welcome".
Essentially what I'm trying to accomplish is:
func changeLabelText() {
questionLabel.text = "New label text"
print(questionLabel.text!)
}
changeLabelText()
// prints "New label text"
however what I'm actually getting is:
func changeLabelText() {
questionLabel.text = "New label text"
print(questionLabel.text!)
}
changeLabelText()
// prints "Welcome"
This is how my label is setup:
class ViewController: UIViewController, AVCaptureVideoDataOutputSampleBufferDelegate {
#IBOutlet var cameraView: UIView!
var questionLabel: UILabel {
let label = UILabel()
label.lineBreakMode = .byWordWrapping
label.backgroundColor = .white
label.textColor = .black
label.text = "Welcome"
label.textAlignment = .center
label.frame = CGRect(x: 65, y: 100, width: 300, height: 65)
return label
}
Any suggestions? Greatly appreciated!
The current
var questionLabel: UILabel {
let label = UILabel()
label.lineBreakMode = .byWordWrapping
label.backgroundColor = .white
label.textColor = .black
label.text = "Welcome"
label.textAlignment = .center
label.frame = CGRect(x: 65, y: 100, width: 300, height: 65)
return label
}
is a computed property so every access gets a new separate instance
questionLabel.text = "New label text" // instance 1
print(questionLabel.text!) // instance 2
instead you need a closure
var questionLabel: UILabel = {
let label = UILabel()
label.lineBreakMode = .byWordWrapping
label.backgroundColor = .white
label.textColor = .black
label.text = "Welcome"
label.textAlignment = .center
label.frame = CGRect(x: 65, y: 100, width: 300, height: 65)
return label
}()
Change your computed variable to a lazy initializer like so:
lazy var questionLabel: UILabel = {
let label = UILabel()
label.lineBreakMode = .byWordWrapping
label.backgroundColor = .white
label.textColor = .black
label.text = "Welcome"
label.textAlignment = .center
label.frame = CGRect(x: 65, y: 100, width: 300, height: 65)
return label
}()
Klamont,
You can try this.
Suppose you want to change the some text of your label you always create two labels for that but it's a wrong approach of changing text color of label. You can use the NSMutableAttributedString for changing the some text color of your label.Firstly, you have to find the the range of text, which you want to change the color of that text and then set the range of your text to the NSMutableAttributedString object as compared to full string and then set your label attributedText with the NSMutableAttributedString object.
Example:
let strNumber: NSString = "Hello Test" as NSString // you must set your
let range = (strNumber).range(of: "Test")
let attribute = NSMutableAttributedString.init(string: strNumber)
attribute.addAttribute(NSForegroundColorAttributeName, value: UIColor.red , range: range)
yourLabel.attributedText = attribute
If you want to use this in many times in your application you can just create the extension of the UILabel and it will make more simple :-
extension UILabel {
func halfTextColorChange (fullText : String , changeText : String ) {
let strNumber: NSString = fullText as NSString
let range = (strNumber).range(of: changeText)
let attribute = NSMutableAttributedString.init(string: fullText)
attribute.addAttribute(NSForegroundColorAttributeName, value: UIColor.red , range: range)
self.attributedText = attribute
}
}
Use your label:-
yourLabel = "Hello Test"
yourLabel.halfTextColorChange(fullText: totalLabel.text!, changeText: "Test")

how to put badge on UIBarButtonItem in swift 4?

I want put badge on UIBarButtonItem. for that I use the following reference
Add badge alert in right bar button item in swift
in this I create the 'UIBarButtonItem+Badge.swift' file and put that code in it. In my viewcontroller I take the outlet of the UIBarButtonItem. And call the function but it didn't work for me. my viewcontroller file is this
My UIBarButtonItem+Badge.swift file is
extension CAShapeLayer {
func drawRoundedRect(rect: CGRect, andColor color: UIColor, filled: Bool) {
fillColor = filled ? color.cgColor : UIColor.white.cgColor
strokeColor = color.cgColor
path = UIBezierPath(roundedRect: rect, cornerRadius: 7).cgPath
}
}
private var handle: UInt8 = 0;
extension UIBarButtonItem {
private var badgeLayer: CAShapeLayer? {
if let b: AnyObject = objc_getAssociatedObject(self, &handle) as AnyObject? {
return b as? CAShapeLayer
} else {
return nil
}
}
func setBadge(text: String?, withOffsetFromTopRight offset: CGPoint = CGPoint.zero, andColor color:UIColor = UIColor.red, andFilled filled: Bool = true, andFontSize fontSize: CGFloat = 11)
{
badgeLayer?.removeFromSuperlayer()
if (text == nil || text == "") {
return
}
addBadge(text: text!, withOffset: offset, andColor: color, andFilled: filled)
}
func addBadge(text: String, withOffset offset: CGPoint = CGPoint.zero, andColor color: UIColor = UIColor.red, andFilled filled: Bool = true, andFontSize fontSize: CGFloat = 11)
{
guard let view = self.value(forKey: "view") as? UIView else { return }
var font = UIFont.systemFont(ofSize: fontSize)
if #available(iOS 9.0, *) { font = UIFont.monospacedDigitSystemFont(ofSize: fontSize, weight: UIFont.Weight.regular) }
let badgeSize = text.size(withAttributes: [NSAttributedString.Key.font: font])
// Initialize Badge
let badge = CAShapeLayer()
let height = badgeSize.height;
var width = badgeSize.width + 2 /* padding */
//make sure we have at least a circle
if (width < height) {
width = height
}
//x position is offset from right-hand side
let x = view.frame.width - width + offset.x
let badgeFrame = CGRect(origin: CGPoint(x: x, y: offset.y), size: CGSize(width: width, height: height))
badge.drawRoundedRect(rect: badgeFrame, andColor: color, filled: filled)
view.layer.addSublayer(badge)
// Initialiaze Badge's label
let label = CATextLayer()
label.string = text
label.alignmentMode = CATextLayerAlignmentMode.center
label.font = font
label.fontSize = font.pointSize
label.frame = badgeFrame
label.foregroundColor = filled ? UIColor.white.cgColor : color.cgColor
label.backgroundColor = UIColor.clear.cgColor
label.contentsScale = UIScreen.main.scale
badge.addSublayer(label)
// Save Badge as UIBarButtonItem property
objc_setAssociatedObject(self, &handle, badge, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
private func removeBadge() {
badgeLayer?.removeFromSuperlayer()
}
}
my viewcontroller file is this
import UIKit
#IBOutlet weak var notificationLabel: UIBarButtonItem!
in view didload function
notificationLabel.addBadge(text: "4")
Here is a swift 4 solution of #VishalPethani with small convenient changes.
Add this UIBarButtonItem to you code:
class BadgedButtonItem: UIBarButtonItem {
public func setBadge(with value: Int) {
self.badgeValue = value
}
private var badgeValue: Int? {
didSet {
if let value = badgeValue,
value > 0 {
lblBadge.isHidden = false
lblBadge.text = "\(value)"
} else {
lblBadge.isHidden = true
}
}
}
var tapAction: (() -> Void)?
private let filterBtn = UIButton()
private let lblBadge = UILabel()
override init() {
super.init()
setup()
}
init(with image: UIImage?) {
super.init()
setup(image: image)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
}
private func setup(image: UIImage? = nil) {
self.filterBtn.frame = CGRect(x: 0, y: 0, width: 30, height: 30)
self.filterBtn.adjustsImageWhenHighlighted = false
self.filterBtn.setImage(image, for: .normal)
self.filterBtn.addTarget(self, action: #selector(buttonPressed), for: .touchUpInside)
self.lblBadge.frame = CGRect(x: 20, y: 0, width: 15, height: 15)
self.lblBadge.backgroundColor = .red
self.lblBadge.clipsToBounds = true
self.lblBadge.layer.cornerRadius = 7
self.lblBadge.textColor = UIColor.white
self.lblBadge.font = UIFont.systemFont(ofSize: 10)
self.lblBadge.textAlignment = .center
self.lblBadge.isHidden = true
self.lblBadge.minimumScaleFactor = 0.1
self.lblBadge.adjustsFontSizeToFitWidth = true
self.filterBtn.addSubview(lblBadge)
self.customView = filterBtn
}
#objc func buttonPressed() {
if let action = tapAction {
action()
}
}
}
And then you can use it like that:
class ViewController: UIViewController {
let btn = BadgedButtonItem(with: UIImage(named: "your_image"))
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.rightBarButtonItem = btn
btn.tapAction = {
self.btn.setBadge(with: 1)
}
}
}
Here is a repository for that with some customisation
https://github.com/Syngmaster/BadgedBarButtonItem
Here it is a simple solution for putting the badge on a navigation bar
let filterBtn = UIButton.init(frame: CGRect.init(x: 0, y: 0, width: 30, height: 30))
filterBtn.setImage(UIImage.fontAwesomeIcon(name: .filter, style: .solid,
textColor: UIColor.white,
size: CGSize(width: 25, height: 25)), for: .normal)
filterBtn.addTarget(self, action: #selector(filterTapped), for: .touchUpInside)
let lblBadge = UILabel.init(frame: CGRect.init(x: 20, y: 0, width: 15, height: 15))
self.lblBadge.backgroundColor = COLOR_GREEN
self.lblBadge.clipsToBounds = true
self.lblBadge.layer.cornerRadius = 7
self.lblBadge.textColor = UIColor.white
self.lblBadge.font = FontLatoRegular(s: 10)
self.lblBadge.textAlignment = .center
filterBtn.addSubview(self.lblBadge)
self.navigationItem.rightBarButtonItems = [UIBarButtonItem.init(customView: filterBtn)]
In your case
self.navigationItem.rightBarButtonItems = [notificationLabel.init(customView: filterBtn)]
import Foundation
import UIKit
extension UIBarButtonItem {
convenience init(icon: UIImage, badge: String, _ badgeBackgroundColor: UIColor = #colorLiteral(red: 0.9156965613, green: 0.380413115, blue: 0.2803866267, alpha: 1), target: Any? = self, action: Selector? = nil) {
let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 24, height: 24))
imageView.image = icon
let label = UILabel(frame: CGRect(x: -8, y: -5, width: 18, height: 18))
label.text = badge
label.backgroundColor = badgeBackgroundColor
label.adjustsFontSizeToFitWidth = true
label.textAlignment = .center
label.font = UIFont.boldSystemFont(ofSize: 10)
label.clipsToBounds = true
label.layer.cornerRadius = 18 / 2
label.textColor = .white
let buttonView = UIView(frame: CGRect(x: 0, y: 0, width: 24, height: 24))
buttonView.addSubview(imageView)
buttonView.addSubview(label)
buttonView.addGestureRecognizer(UITapGestureRecognizer.init(target: target, action: action))
self.init(customView: buttonView)
}
}
Use:
item = UIBarButtonItem(icon: UIImage(), badge: "\(Test)", target: self, action: nil)
self.navigationItem.rightBarButtonItems = [item]
extension UIBarButtonItem {
func setBadge(with value: Int) {
guard let lblBadge = customView?.viewWithTag(100) as? UILabel else { return }
if value > 0 {
lblBadge.isHidden = false
lblBadge.text = "\(value)"
} else {
lblBadge.isHidden = true
}
}
func setup(image: UIImage? = nil) {
customView?.frame = CGRect(x: 0, y: 0, width: 30, height: 30)
let lblBadge = UILabel()
lblBadge.frame = CGRect(x: 20, y: 0, width: 15, height: 15)
lblBadge.backgroundColor = .red
lblBadge.tag = 100
lblBadge.clipsToBounds = true
lblBadge.layer.cornerRadius = 7
lblBadge.textColor = UIColor.white
lblBadge.font = UIFont.systemFont(ofSize: 10)
lblBadge.textAlignment = .center
lblBadge.isHidden = true
lblBadge.minimumScaleFactor = 0.1
lblBadge.adjustsFontSizeToFitWidth = true
customView?.addSubview(lblBadge)
}
}
Steps:
Drag an drop an UIButton in navigation/toolbar or add it programmatically using customView initializer.
Call setup method in view didload:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
itemsButton.setup(image: UIImage(named: "image_name"))
}
Connect an #IBOutlet/or programmatically and call setBadge method everywhere you need:
badgeButton.setBadge(with: 10)

Not seeing all views in views using views.addSubviews

I am running into a basic problem with views on iPad. I have a viewController. The view is using a UIImageView with a full screen image as a background image. I am trying to overlay labels on the top. If I set labels individually, both views show up. If I call a function with the same information only one view shows up. I need to extend it many labels. Here is the code:
class ViewController: UIViewController {
#IBOutlet weak var backGroundImageView: UIImageView!
var cFrame:[CGRect?] = [CGRect?](repeating: nil, count: 13)
var offsets:[CGRect?] = [CGRect?](repeating: nil, count: 13)
var labels: [UILabel?] = [UILabel?](repeating:UILabel(), count:13)
override func viewDidLoad() {
super.viewDidLoad()
cFrame[0] = CGRect(x:450,y:530,width:251,height:68)
cFrame[1] = CGRect(x:147,y:676,width:222,height:24)
loadFrameValues()
var frame = CGRect(x: 450, y: 520, width: 251, height: 68)
let label0 = UILabel(frame: frame)
label0.backgroundColor = .white
label0.numberOfLines = 0
label0.lineBreakMode = .byWordWrapping
label0.textAlignment = .center
label0.text = "Text 1"
frame = CGRect(x: 152, y: 686, width: 210, height: 16)
let label1 = UILabel(frame: frame)
label1.backgroundColor = .cyan
label1.lineBreakMode = .byWordWrapping
label1.textAlignment = .left
label1.text = "Text 2"
label1.font = label1.font.withSize(12)
backGroundImageView.addSubview(label0)
backGroundImageView.addSubview(label1)
// showView(label: labels[0]!, frame: cFrame[0]!)
// showView(label: labels[1]!, frame: cFrame[1]!)
// }
}
func showView(label: UILabel, frame:CGRect) {
label.frame = frame
label.backgroundColor = .white
label.numberOfLines = 0
label.lineBreakMode = .byWordWrapping
label.textAlignment = .center
label.text = "Syed Tariq"
backGroundImageView.addSubview(label)
}
You can't add subview (label in your case) to UIImageView. So add label as subview to the superview of your image view.
override func viewDidLoad() {
cFrame[0] = CGRect(x:50,y:130,width:151,height:68)
cFrame[1] = CGRect(x:114,y:276,width:122,height:24)
showView(frame: cFrame[0]!)
showView(frame: cFrame[1]!)
}
func showView(frame:CGRect) {
let label = UILabel(frame: frame)
label.backgroundColor = .green
label.numberOfLines = 0
label.lineBreakMode = .byWordWrapping
label.textAlignment = .center
label.text = "Syed Tariq"
self.view.addSubview(label)
}

Swift add Gesture to UIImageView?

Now i am working on IOS project with Swift!
I already made coverflow object.
And now i want some function to run when i click on each images in that coverflow.
I tried to add some gesture on it but seems didn't work.
This is my code below.
func carousel(carousel: iCarousel!, viewForItemAtIndex index: Int, var reusingView view: UIView!) -> UIView!
{
var label: UILabel! = nil
var labelSecond: UILabel! = nil
var labelVol: UILabel! = nil
var viewRec: UITapGestureRecognizer! = nil
var itemsVol = [itemsInside01.count,itemsInside02.count,itemsInside03.count,itemsInside04.count,itemsInside05.count]
println(itemsVol[2])
//create new view if no view is available for recycling
if (view == nil)
{
//don't do anything specific to the index within
//this `if (view == nil) {...}` statement because the view will be
//recycled and used with other index values later
view = UIImageView(frame:CGRectMake(0, 0, 200, 156))
(view as UIImageView!).image = UIImage(named: "coverFlowBg.png")
view.contentMode = .Center
var wBounds = view.bounds.width
var hBounds = view.bounds.height
var labelSize = CGRect(x: 0, y: hBounds, width: wBounds, height: 52)
var labelSmallSize = CGRect(x: 0, y: hBounds + 30, width: wBounds, height: 24)
label = UILabel()
label.frame = labelSize
label.backgroundColor = UIColor.clearColor()
label.textAlignment = .Center
label.textColor = UIColor.whiteColor()
label.font = UIFont(name: "supermarket" , size: 18)
label.tag = 1
labelSecond = UILabel()
labelSecond.frame = labelSize
labelSecond.backgroundColor = UIColor.clearColor()
labelSecond.textAlignment = .Center
labelSecond.textColor = UIColor.whiteColor()
labelSecond.font = UIFont(name: "supermarket" , size: 18)
labelSecond.tag = 1
labelVol = UILabel()
labelVol.frame = labelSmallSize
labelVol.backgroundColor = UIColor.clearColor()
labelVol.textAlignment = .Center
labelVol.textColor = UIColor.whiteColor()
labelVol.font = UIFont(name: "supermarket" , size: 12)
labelVol.tag = 1
imageTypeIcon = UIImage(named: cardTypeImageSrc[index])
imageTypeIconView = UIImageView(image: imageTypeIcon)
imageTypeIconView.contentMode = .Center
imageTypeIconView.frame = CGRect(x: 0, y: 0, width: wBounds, height: hBounds)
viewRec = UITapGestureRecognizer()
viewRec.addTarget(self, action: "viewIsClicked:")
imageTypeIconView.addGestureRecognizer(viewRec)
imageTypeIconView.userInteractionEnabled = true
view.addSubview(label)
//view.addSubview(labelSecond)
view.addSubview(labelVol)
view.addSubview(imageTypeIconView)
}
else
{
//get a reference to the label in the recycled view
label = view.viewWithTag(1) as UILabel!
}
//set item label
//remember to always set any properties of your carousel item
//views outside of the `if (view == nil) {...}` check otherwise
//you'll get weird issues with carousel item content appearing
//in the wrong place in the carousel
label.text = "\(items[index])"
//labelSecond.text = "\(items[index])"
labelVol.text = "\(itemsVol[index]) " + "ชุดการ์ด"
return view
}
func carousel(carousel: iCarousel!, valueForOption option: iCarouselOption, withDefault value: CGFloat) -> CGFloat
{
if (option == .Spacing)
{
return value * 1
}
return value
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func goBackToIndex(sender: AnyObject) {
if let navController = self.navigationController {
navController.popViewControllerAnimated(true)
}
}
func viewIsClicked(){
println("uuteosuteo")
}
So if someone know why it didn't work please help me
Thanks!
Your function viewIsClicked() doesn't contain any parameters, but your selector contains a colon - "viewIsClicked:", so you probably getting runtime error.
Try to change:
viewRec.addTarget(self, action: "viewIsClicked:")
To:
viewRec.addTarget(self, action: "viewIsClicked")
Changing following snippet of code will do your work
viewRec = UITapGestureRecognizer(target: self, action: "viewIsClicked")
viewRec.numberOfTapsRequired = 1
viewRec.numberOfTouchesRequired = 1

Resources