Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

icon + text = text becomes icon if text match icon name #258

Open
Slodin opened this issue Jun 23, 2020 · 5 comments
Open

icon + text = text becomes icon if text match icon name #258

Slodin opened this issue Jun 23, 2020 · 5 comments

Comments

@Slodin
Copy link

Slodin commented Jun 23, 2020

Hi,

In my toolbar item, I have set everything according to the doc page, it was working fine because I was making my app in a different language than English. However, now my app requires English as an alternative language option and this problem occurred.

`let barItemFontAttr = [
NSAttributedString.Key.font: UIFont.fontAwesome(ofSize: 15, style: .solid)
]

refreshOrders.setTitleTextAttributes(barItemFontAttr, for: .normal)
refreshOrders.setTitleTextAttributes(barItemFontAttr, for: .selected)
refreshOrders.title = "(String.fontAwesomeIcon(name: .sync)) Sync" //Don't work
refreshOrders.title = "(String.fontAwesomeIcon(name: .sync)) 同步" //Works`

Expected:
Sync Icon + "Sync"

Got:
Sync Icon + Sync Icon

How am I suppose to do this?

@MatrixSenpai
Copy link
Collaborator

This is another problem I'm attempting to solve. When typing the name of an icon in English, the font auto-translates it to the appropriate icon, rather than just using Unicode. I have not yet been able to figure out why.

Are you initializing your UIBarButtonItem in Storyboard or inside a class?

@Slodin
Copy link
Author

Slodin commented Jun 24, 2020

This is another problem I'm attempting to solve. When typing the name of an icon in English, the font auto-translates it to the appropriate icon, rather than just using Unicode. I have not yet been able to figure out why.

Are you initializing your UIBarButtonItem in Storyboard or inside a class?

It is a UIBarButtonItem in the Storyboard, but used in a viewcontroller class.
I thought String.fontAwesomeIcon(name) is used to translate the icon into a string, but it seems to affect the entire title anyways with or without calling that function. It's almost as if it's matching anything that contains certain key words. I was trying to write "Routes Prev", it became: route Icon + "s Prev".

@MatrixSenpai
Copy link
Collaborator

MatrixSenpai commented Jun 25, 2020

You're correct, and this is a source of investigation at the moment. I have yet to determine what it is about the font that causes actual text to be translated into an FA icon.
Currently, when using String.fontAwesomeIcon(name:), it's basically just the same as using FontAwesome.x_icon_name.unicode
Until I can solve this issue, my recommendations are:

  • Use NSAttributedString where available. UILabel and UIButton both have attributed title options.
  • Use only an icon otherwise

Here's a short code snippet to get you started with FA+NSAttributedString

let button = UIButton() // or link to one defined in your Storyboard
let label = UILabel()

// Note this MUST be Mutable for us to be able to apply an attribute
let string = NSMutableAttributedString(string: "Sync " + .fontAwesomeIcon(name: .chevronRight))

// If your icon is the first char in the text, use range: NSRange(location: 0, length: 1)
string.addAttribute(.font, value: UIFont.fontAwesome(ofSize: 18, style: .regular), 
                           range: NSRange(location: string.length - 1, length: 1))

button.setAttributedTitle(string, for: .normal)
label.attributedText = string

Hope this helps!

@Slodin
Copy link
Author

Slodin commented Jun 26, 2020

Thanks for your reply, I did figure out a similar thing to yours for labels and buttons. However, UIBarButtonItem is a different story since it doesn't take attributed strings. Then I realized I can just stuff a button or label into the UIBarButtonItem...

So I figured a workaround for UIBarButtonItem, I didn't look into this problem until earlier since I had to do many more translations and this problem only happens at a few places for my project...I hate IOS localization lol.
It's a super roundabout way...But I don't have any better ideas rn

View Controller

let routePreviewButton = UIBarButtonItem()! //linked from storyboard
let routeButton = UIButton()
//Add your button target, users will touch this instead of the UIBarButtonItem now in my testing
routeButton.addTarget(self, action: #selector(navToRoutes), for: .touchUpInside)
let routeIconTextAttr = generalHelper.getFAIconWithText(name: .map, size: 15, style: .solid, text: "Routes Prev.")
routeButton.setAttributedTitle(routeIconTextAttr, for: .normal)
routeButton.setAttributedTitle(routeIconTextAttr, for: .selected)
routeButton.sizeToFit()
routePreviewButton.customView = routeButton

GeneralHelper.getFAIconWithText

let icon = NSMutableAttributedString(string: String.fontAwesomeIcon(name: name), attributes: [.font: UIFont.fontAwesome(ofSize: CGFloat(size), style: style)])
let textToAppend = NSAttributedString(string: text, attributes: [.font: UIFont.systemFont(ofSize: CGFloat(size))])
icon.append(textToAppend)
return icon

This approach still requires coders to adjust the button's appearance, but it's a basic start for me to at least get the bar buttons working.

@Slodin
Copy link
Author

Slodin commented Jul 11, 2020

So If anyone needs this. Here is a BarButtonItem that works with this library in its current state.
I'm still new to swift as I just came from Android development since our company is short-handed in the swift side. So there might be better ways to do this, but this works for me.

import UIKit
import FontAwesome_swift

@IBDesignable class FAIconBarButtonItem: UIBarButtonItem {
    //MARK: - Variable Declearation
    private let button = UIButton(type: .system)
    
    @IBInspectable private var size: CGFloat = 15 {
        didSet {
            button.titleLabel?.font = UIFont.systemFont(ofSize: size)
            setButtonIcon(icon: icon)
        }
    }
    
    @IBInspectable private var text: String? = "Default" {
        didSet {setButtonTitle(title: text)}
    }
    
    @IBInspectable private var normalColor: UIColor = .systemBlue {
        didSet {
            setButtonTitleColor(normalColor: normalColor)
            setButtonIcon(icon: icon)
        }
    }
    
    private var icon: FontAwesome = .powerOff {
        didSet {setButtonIcon(icon: icon)}
    }
    
    @IBInspectable private var iconAdapter: String {
        get {
            return self.icon.rawValue
        }
        set(iconString) {
            self.icon = FontAwesome(rawValue: iconString) ?? .powerOff
        }
    }

    //Used to provide addTarget action
    var touchUpInside: ((_ button: UIButton)->())?
    
    //MARK: - Init
    private override init(){
        super.init()
        target = self
        customView = setup()
    }
    
    required init?(coder aDecorder: NSCoder) {
        super.init(coder: aDecorder)
        customView = setup()
    }
    
    //MARK: - Private Functions
    private func setup() -> UIButton {
        button.isEnabled = true
        button.isUserInteractionEnabled = true
        button.titleLabel?.font = UIFont.systemFont(ofSize: size)
        setButtonTitleColor(normalColor: normalColor)
        setButtonIcon(icon: icon)
        setButtonTitle(title: text)
        button.tintColor = normalColor
        button.addTarget(self, action: #selector(touchUpInside(_:)), for: .touchUpInside)
        button.sizeToFit()
        return button
    }
    
    private func setButtonTitle(title: String?){
        button.setTitle(title?.localized(), for: .normal)
    }
    
    private func setButtonTitleColor(normalColor: UIColor){
        button.setTitleColor(normalColor, for: .normal)
    }
    
    private func setButtonIcon(icon: FontAwesome){
        //All changes of icon, color, and size is made in this
        let normalIconImage = UIImage.fontAwesomeIcon(name: icon, style: .solid, textColor: normalColor, size: CGSize(width: size, height: size))
        button.tintColor = normalColor
        button.setImage(normalIconImage, for: .normal)
    }
    
    @objc private func touchUpInside(_ sender: UIButton){
        touchUpInside?(sender)
    }
    
    //MARK: - Exposed Functions
    func setTitleAndIcon(title: String, icon: FontAwesome) {
        setIcon(icon: icon)
        setTitle(title: title)
    }
    
    func setTitle(title: String){
        self.text = title
    }
    
    func setIcon(icon: FontAwesome){
        self.icon = icon
    }
    
    func setColor(color: UIColor){
        self.normalColor = color
    }
}

Usage:

  1. Make your barButtonItem in your storyboard
  2. Use this FAIconBarButtonItem class
  3. You can customize a few things in the inspector

How to get button's action when pressed after linking your FABarButtonItem outlet
In your ViewConroller

barButtonItem.touchUpInside = {
   //whatever you want to do
   //If you need other interaction methods, modify FABarButtonItem and use "touchUpInside" as an example.
}
//Change title
setTitle(title: String)

//Change icon
setIcon(icon: FontAwesome)

//Change title and icon
setTitleAndIcon(title: String, icon: FontAwesome)

//Change color
setColor(color: UIColor)

It should also work with code init but it's not in my use case so I didn't care, you can modify my code to get it working if it's not already.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants