LTMorphingLabel icon indicating copy to clipboard operation
LTMorphingLabel copied to clipboard

Autoshrink for Label doesn't work.

Open kenhama opened this issue 11 years ago • 13 comments

It's very cool label. but I have a problem, Autoshrink(minimumFontScale) doesn't work. It shows fixed font size.

kenhama avatar Oct 15 '14 01:10 kenhama

Thanks. It's a must have feature. I'll implement it asap.

lexrus avatar Oct 15 '14 03:10 lexrus

+1

borut-t avatar Nov 02 '15 20:11 borut-t

Is this feature implemented in some other branch or is still in TODO list?

borut-t avatar Nov 16 '15 12:11 borut-t

Sorry, I'm not working on this. Maybe next month. :smile:

lexrus avatar Nov 16 '15 13:11 lexrus

@lexrus That would be nice. Please let me know. Thanks!

borut-t avatar Nov 22 '15 21:11 borut-t

Yeah this is a great little project I want to use in my app but can't because of the lack of sizing change. I'm fairly competent, what are people's thoughts on the matter? I tried doing something like

let size: CGSize = (myLabel.text! as String).boundingRectWithSize(
    CGSize(width: self.view.frame.size.width, height: 999999.0),
    options: NSStringDrawingOptions.UsesLineFragmentOrigin,
    attributes: [NSFontAttributeName: self.myLabel.font],
    context: nil).size

if (size.width > self.myLabel.bounds.size.width) {

    print("Yep")
}

And this works (the code with do with some tweaking); It checks whether the size of the string is larger than the frame to be putting it in. How to change the font until it's small enough to fit is a bit trickier. I tried using a for loop to constantly check but this gets rid of the animation for some reason. Hopefully this speeds up the process ;) and thanks again for making this, really cool project!

Edit: The above is wrong, should be comparing against height with infinite width, not this way round! And what was I thinking with 999999.0 😂

SunburstEnzo avatar Nov 23 '15 22:11 SunburstEnzo

@SunburstEnzo Thank you for your advice. But how does the OS figure out which FontScale value properly fit in current rect? I guess we can take the advantage of CoreText which has some great functions to deal with properties of each character of a attributed string. But it'll be a breaking change.

See also: https://github.com/overboming/ZCAnimatedLabel/blob/master/ZCAnimatedLabel/ZCAnimatedLabel/ZCCoreTextLayout.m

lexrus avatar Nov 24 '15 05:11 lexrus

Any progress on this issue?

borut-t avatar Feb 04 '16 17:02 borut-t

Forgot about this so gave it another go just now

            var size: CGSize = myLabel.text.boundingRectWithSize(CGSize(width: CGFloat.max, height: myLabel.bounds.height), options: NSStringDrawingOptions.UsesLineFragmentOrigin, attributes: [NSFontAttributeName: myLabel.font], context: nil).size

            if (size.width > myLabel.bounds.width) {

                print("Yep")

                while size.width > myLabel.bounds.width {

                    myLabel.font = myLabel.font.fontWithSize(myLabel.font.pointSize - 1)

                    size = myLabel.text.boundingRectWithSize(
                    CGSize(width: CGFloat.max, height: myLabel.bounds.height),
                    options: NSStringDrawingOptions.UsesLineFragmentOrigin,
                    attributes: [NSFontAttributeName: myLabel.font],
                    context: nil).size

                    myLabel.setNeedsLayout()
                }
            }
            else {

                print("No")

                 while size.width < myLabel.bounds.width {

                    myLabel.font = myLabel.font.fontWithSize(myLabel.font.pointSize + 1)

                    size = myLabel.text.boundingRectWithSize(
                    CGSize(width: CGFloat.max, height: myLabel.bounds.height),
                    options: NSStringDrawingOptions.UsesLineFragmentOrigin,
                    attributes: [NSFontAttributeName: myLabel.font],
                    context: nil).size

                    myLabel.setNeedsLayout()
                }
            }

So what this does is reduce the font size so that it fits inside the label's width. This should get you by for now. It could also be made way more efficient and more Swift like probably.

SunburstEnzo avatar Feb 04 '16 19:02 SunburstEnzo

I'm still waiting that "label.adjustsFontSizeToFitWidth = true" is working with LTMorphingLabel :dancers:

dungi avatar Feb 08 '16 18:02 dungi

+1

undsoft avatar Apr 23 '16 12:04 undsoft

Okay this is what I ended up temporarily doing. This doesn't support shrinking space between letters, and doesn't work correctly if you set text anywhere before viewDidLoad. I have only tested it with .Evaporate effect.

//
//  ShrinkingLTMortphingLabel.swift
//

import Foundation
import LTMorphingLabel


// LTMorphingLabel doens't support autoshrink natively.
// BUG: https://github.com/lexrus/LTMorphingLabel/issues/14
// Emulate the behaviour manually.
// Will take minimumScaleFactor in consideration.
class ShrinkingLTMortphingLabel: LTMorphingLabel {

    // MARK: - Properties

    /// Original font for the label before any adjustment took place
    var originalFont: UIFont? = nil

    /// Trigger font-resize on text change
    override var text: String? {
        get {
            return super.text
        }
        set {

            // You do not want to change the order of next two strings
            if newValue != nil {
                adjustFontSizeToFitText(newValue!)
            }

            super.text = newValue
        }
    }

    // MARK: - Init
    // Save original font size.

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


        originalFont = font
    }

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

        originalFont = font
    }

    // MARK: - View Lifecycle
    override func layoutSubviews() {
        super.layoutSubviews()

        if text != nil {
            adjustFontSizeToFitText(text!)
        }
    }

    // MARK: - Methods

    /**
    Does the actual adjustment work.
    */
    private func adjustFontSizeToFitText(newText: String){

        guard adjustsFontSizeToFitWidth, let originalFont = originalFont else { return }

        let desiredWidth = getDesiredWidthForText(newText)

        if frame.width < desiredWidth {
            // The text does not fit!
            let scaleFactor = max(frame.width / desiredWidth, minimumScaleFactor)

            font = UIFont(name: originalFont.fontName, size: originalFont.pointSize * scaleFactor)
        }
        else{
            // Revert to normal
            font = originalFont
        }
    }

    /**
    Calculates what the width of the label should be to fit the text.

    - parameter text:   Text to fit.
    */
    private func getDesiredWidthForText(text: String) -> CGFloat {
        let size = text.boundingRectWithSize(
            CGSize(width: CGFloat.max, height: frame.height),
            options: [NSStringDrawingOptions.UsesLineFragmentOrigin],
            attributes: [NSFontAttributeName: originalFont!],
            context: nil).size

        return ceil(size.width)
    }
}

undsoft avatar Apr 24 '16 17:04 undsoft

+1 ~~~waiting too

SenorSamuel avatar Jun 08 '18 14:06 SenorSamuel