3

I have some UIbuttons in my app that have a number indicator before the text. Right now, I am just using string interpolation to display the number before the string as seen below.

fruitButton.setTitle("\(fruitCounter) Fruits", forState: UIControlState.Normal)

I need the number to stand out more, rather than just blending in with the title text. Something as simple as a circle surrounding it will do the trick, as seen in the design below: I need my buttons to have a styled number indicator like in the photo. .

I did some research on Attributed Strings in Swift. However, I am just seeing many examples on changing text properties. EG - changing the text color and size of the number indicator. I can't figure out how to add a circle behind.

I do not want this circle to be an image, simply for scalibility purposes. For instance, if that number ends up being 2 digits long, I need the circle to stretch to oval. My thought was using a small view behind the number, and then just applying a color / alpha / radius to achieve the look I need.

So to wrap this up: How can I add circles behind my number indicators using Attributed Strings in Swift?

Moin Shirazi
  • 4,372
  • 2
  • 26
  • 38
Joe
  • 3,772
  • 3
  • 33
  • 64
  • So you already have an idea / solution - did you try it? What went wrong? – Wain Apr 04 '16 at 22:19
  • How can you add circles behind numbers in a word processor? – Aaron Brager Apr 04 '16 at 22:26
  • The iOS text system doesn't support this natively. You should consider using a separate label/layer. – jtbandes Apr 04 '16 at 22:31
  • If the number will always be 9 or less, use the circled number Unicode characters such as ⑨ or ⓽ or ❾ etc. – rmaddy Apr 04 '16 at 22:47
  • @rmaddy - I thought about that, as it seems to be the easiest... but there's a good chance of 10+ – Joe Apr 04 '16 at 23:17
  • @Wain - What went wrong is I can't add a radius to a perfectly square background color behind a value using attributed text. I used this to get as close as I could: http://makeapppie.com/2014/10/20/swift-swift-using-attributed-strings-in-swift/ – Joe Apr 04 '16 at 23:23
  • @jtbandes - That sounds logical. Can you provide any documentation on how I can add a customized label to the text of a uibutton? – Joe Apr 04 '16 at 23:29

2 Answers2

2

You should create a UIView subclass that will contain these two elements. Create a corresponding .xib file that includes those entities or implement those entities in code. You can also implement touchesBegan so that this view can act like a button OR add a button instead of a text label and implement a protocol to fire every time the button is hit. I've started this for you with some semi-arbitrary numbers. You'll have to play with them to get them just right.

class UICoolButton: UIView {

    var labelText: NSString?
    var circledNumber: Int?
    var circleSubview: UIView?

    init(frame: CGRect, labelText: NSString, circledNumber: Int) {
        super.init(frame: frame);
        self.labelText = labelText;
        self.circledNumber = circledNumber;
        self.layer.cornerRadius = frame.height/3
        self.clipsToBounds = true
        addCircledNumber()
        addTextLabel(labelText)
    }

    func setColors(numberColor:UIColor, backgroundColor: UIColor) {
        self.backgroundColor = backgroundColor
        self.circleSubview?.backgroundColor = numberColor
    }

    override init(frame: CGRect) {
        super.init(frame: frame);
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder);
    }

    func addTextLabel(text: NSString) {
        let origin = CGPoint(x:self.frame.width * 0.4, y:self.frame.height/10)
        let size = CGSize(width: self.frame.width/2, height: self.frame.height * 0.8)
        let rect = CGRect(origin: origin, size: size)
        let label = UILabel(frame: rect)
        let attributes: [String : AnyObject] = [NSFontAttributeName : UIFont(name: "Verdana", size: 16.0)!,
        NSForegroundColorAttributeName : UIColor.whiteColor()]

        label.attributedText = NSAttributedString(string: text, attributes: attributes)

        self.addSubview(label)
    }

    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {

    }

    func addCircledNumber() {
        let height = self.frame.height * 0.4;
        let circleDimensions = CGSize(width: height , height:height)
        let origin = CGPointMake(self.frame.width * 0.15, self.frame.height - self.frame.height/1.5)
        let circleSubview = UIView(frame: CGRect(origin: origin, size: circleDimensions))
        circleSubview.layer.cornerRadius = height/2;
        circleSubview.backgroundColor = UIColor.darkGrayColor()

        let labelHeight = height * 0.8;

        let xPosition = circleSubview.bounds.origin.x + 3
        let yPosition = circleSubview.bounds.origin.y + 2

        let labelOrigin =  CGPoint(x: xPosition, y: yPosition)
        let labelRect = CGRect(origin: labelOrigin, size: CGSize(width: labelHeight, height: labelHeight))
        let numberLabel = UILabel(frame: labelRect);
        numberLabel.textAlignment = NSTextAlignment.Center

        let numberAsString = NSString(format: "%i", circledNumber!) as String
        let attributes: [String : AnyObject] = [NSFontAttributeName : UIFont(name: "Verdana", size: 16.0)!,
        NSForegroundColorAttributeName : UIColor.whiteColor()]
        numberLabel.attributedText = NSAttributedString(string: numberAsString, attributes: attributes)
        circleSubview.addSubview(numberLabel);
        self.circleSubview = circleSubview
        self.addSubview(circleSubview)
    }

Then in your View Controller, use the initilizer I wrote:

func addCoolButton() {
    let rect = CGRect() //choose the frame for your button here
    let button = UICoolButton(frame: rect, labelText: "Example", circledNumber: 10);

    let backgroundColor = UIColor(red: 243/255.0 , green: 93/255.0, blue: 118/255.0, alpha: 1.0)
    let numberColor = UIColor(red: 252/255.0, green: 118.0/255.0, blue: 135/255.0, alpha: 1.0)
    button.setColors(numberColor, backgroundColor: backgroundColor)

    self.view.addSubview(button)
}
BenJammin
  • 1,479
  • 13
  • 18
  • Thanks for your example above. I am having problems applying it to my project. Nothing is showing up in the storyboard. I created a view, gave it the UICoolButton class, set the frame with CGRectMake / set labelText, and set circled number. I must be missing something. – Joe Apr 05 '16 at 05:20
  • Check my edits. To use this class, use the initializer I wrote. There is no storyboard involved in my implementation. More info here (http://stackoverflow.com/questions/21898190/creating-a-reusable-uiview-with-xib-and-loading-from-storyboard) if you want to adapt this for Storyboard/IB use. – BenJammin Apr 05 '16 at 17:22
  • you rock! That did exactly what the question posed. I'm going to try deciphering that link you provided to get it to work with storyboard. In the app I am working on, the buttons are on the storyboard in a horizontal stackview. So I will need to get your awesome solution working with that layout. – Joe Apr 05 '16 at 19:47
-1

I did sample some thing like your purpose with autolayout

enter image description here

with code here:

@interface ViewController ()

@property (weak, nonatomic) IBOutlet UIView *content;
@property (weak, nonatomic) IBOutlet UILabel *label;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.content.layer.cornerRadius = MIN(self.content.bounds.size.width, self.content.bounds.size.height)/2;
    self.content.clipsToBounds = true;

}

@end

result with number is 1234:

enter image description here

result with number is 1:

enter image description here

larva
  • 4,687
  • 1
  • 24
  • 44
  • But the question is asking how to apply the circle to the number portion of the label of a `UIButton`. Your answer doesn't apply. – rmaddy Apr 05 '16 at 02:12
  • @A Báo - looks nice. But I need for that to be inside of a UIButton, not just its own entity as a label. And in Swift, vs. ObjC. – Joe Apr 05 '16 at 03:28