Ich habe eine Reihe von Beispielen zur Änderung der Größe eines UILabels gesehen.
Folgendes möchte ich tun: Ändern Sie die Schriftgröße so, dass der Text innerhalb der neuen Höhe so groß wie möglich ist.
Irgendwelche Hinweise?
Edit: Check out Joel Fischers tolle Antwort um programmgesteuert die richtige Größe zu erhalten!
Sie können festlegen, dass die Schriftart automatisch die Etikettengröße ausfüllt und optional eine Mindestschriftgröße nicht unterschreitet. Setzen Sie einfach adjustsFontSizeToFitWidth
auf YES.
. Überprüfen Sie die UILabel-Klassenreferenz , wenn Sie weitere Informationen benötigen.
Obwohl der Boolesche Wert "adjustsFontSizeToFitWidth" genannt wird, bedeutet dies wirklich die größte Größe für die Höhe der Beschriftung, die in einer Zeile der Beschriftung bleibt (oder wie viele Zeilen Sie angeben).
Ich hatte das gleiche Problem und dank dieses Threads und Joels Algorithmus konnte ich das Problem beheben. :-)
Unten ist mein Code in Swift. Ich bin in iOS 8 + Autolayout.
Problem:
Nach dem Update:
Genau das hatte der Designer vor Augen ... :)
Ich habe UILabel subclassed und layoutSubviews
überschrieben. Jedes Mal, wenn die Größe des UILabels geändert wird, wird die Schriftgröße neu berechnet:
//
// LabelWithAdaptiveTextHeight.Swift
// 123
//
// Created by https://github.com/backslash-f on 12/19/14.
//
/*
Designed with single-line UILabels in mind, this subclass 'resizes' the label's text (it changes the label's font size)
everytime its size (frame) is changed. This 'fits' the text to the new height, avoiding undesired text cropping.
Kudos to this Stack Overflow thread: bit.ly/setFontSizeToFillUILabelHeight
*/
import Foundation
import UIKit
class LabelWithAdaptiveTextHeight: UILabel {
override func layoutSubviews() {
super.layoutSubviews()
font = fontToFitHeight()
}
// Returns an UIFont that fits the new label's height.
private func fontToFitHeight() -> UIFont {
var minFontSize: CGFloat = DISPLAY_FONT_MINIMUM // CGFloat 18
var maxFontSize: CGFloat = DISPLAY_FONT_BIG // CGFloat 67
var fontSizeAverage: CGFloat = 0
var textAndLabelHeightDiff: CGFloat = 0
while (minFontSize <= maxFontSize) {
fontSizeAverage = minFontSize + (maxFontSize - minFontSize) / 2
// Abort if text happens to be nil
guard text?.characters.count > 0 else {
break
}
if let labelText: NSString = text {
let labelHeight = frame.size.height
let testStringHeight = labelText.sizeWithAttributes(
[NSFontAttributeName: font.fontWithSize(fontSizeAverage)]
).height
textAndLabelHeightDiff = labelHeight - testStringHeight
if (fontSizeAverage == minFontSize || fontSizeAverage == maxFontSize) {
if (textAndLabelHeightDiff < 0) {
return font.fontWithSize(fontSizeAverage - 1)
}
return font.fontWithSize(fontSizeAverage)
}
if (textAndLabelHeightDiff < 0) {
maxFontSize = fontSizeAverage - 1
} else if (textAndLabelHeightDiff > 0) {
minFontSize = fontSizeAverage + 1
} else {
return font.fontWithSize(fontSizeAverage)
}
}
}
return font.fontWithSize(fontSizeAverage)
}
}
So habe ich es gemacht, da die Antwort von DGund für mich nicht funktionierte, sie auf die Breite passte, aber ich wollte, dass sie auf die Höhe passt.
+ (UIFont *)findAdaptiveFontWithName:(NSString *)fontName forUILabelSize:(CGSize)labelSize withMinimumSize:(NSInteger)minSize
{
UIFont *tempFont = nil;
NSString *testString = @"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
NSInteger tempMin = minSize;
NSInteger tempMax = 256;
NSInteger mid = 0;
NSInteger difference = 0;
while (tempMin <= tempMax) {
mid = tempMin + (tempMax - tempMin) / 2;
tempFont = [UIFont fontWithName:fontName size:mid];
difference = labelSize.height - [testString sizeWithFont:tempFont].height;
if (mid == tempMin || mid == tempMax) {
if (difference < 0) {
return [UIFont fontWithName:fontName size:(mid - 1)];
}
return [UIFont fontWithName:fontName size:mid];
}
if (difference < 0) {
tempMax = mid - 1;
} else if (difference > 0) {
tempMin = mid + 1;
} else {
return [UIFont fontWithName:fontName size:mid];
}
}
return [UIFont fontWithName:fontName size:mid];
}
Dies erfordert einen Schriftnamen, eine Größe (theoretisch muss es kein UILabel sein, aber ich habe ihn immer mit einem UILabel verwendet) und eine minimale Größe (Sie können auch eine maximale Größe verwenden, ersetzen Sie einfach die 256 durch der maximale Größenparameter). Dies testet im Wesentlichen jede Schriftgröße zwischen der minimalen und maximalen Schriftgröße und gibt die Schriftgröße zurück, die sich auf oder unterhalb der Zielhöhe befindet.
Die Verwendung ist selbsterklärend, sieht jedoch so aus:
self.myLabel.font = [self findAdaptiveFontWithName:@"HelveticaNeue-UltraLight" forUILabelSize:self.myLabel.frame.size withMinimumSize:30];
Sie können dies auch zu einer Klassenmethodenkategorie auf UIFont machen (was ich auch getan habe).
BEARBEITEN: Auf Vorschlag habe ich die for-Schleife entfernt und etwas Zeit damit verbracht, sie mit einer binären Suchroutine effizienter zu gestalten. Ich habe mehrere Überprüfungen durchgeführt, um absolut sicherzugehen, dass die Schrift am Ende in das Etikett passt. Im ersten Test scheint es zu funktionieren.
Es gibt eine einfachere Lösung. Fügen Sie einfach unterhalb der Zeilen und magisch hinzu, das Etikett passt die Schriftgröße an die Etikettenhöhe an:
Swift 3:
label.minimumScaleFactor = 0.1 //or whatever suits your need
label.adjustsFontSizeToFitWidth = true
label.lineBreakMode = .byClipping
label.numberOfLines = 0
um den Text an die Höhe meines Labels anzupassen, muss ich die Joel-Methode an Swift anpassen
func optimisedfindAdaptiveFontWithName(fontName:String, label:UILabel!, minSize:CGFloat,maxSize:CGFloat) -> UIFont!
{
var tempFont:UIFont
var tempHeight:CGFloat
var tempMax:CGFloat = maxSize
var tempMin:CGFloat = minSize
while (ceil(tempMin) != ceil(tempMax)){
let testedSize = (tempMax + tempMin) / 2
tempFont = UIFont(name:fontName, size:testedSize)
let attributedString = NSAttributedString(string: label.text!, attributes: [NSFontAttributeName : tempFont])
let textFrame = attributedString.boundingRectWithSize(CGSize(width: label.bounds.size.width, height: CGFloat.max), options: NSStringDrawingOptions.UsesLineFragmentOrigin , context: nil)
let difference = label.frame.height - textFrame.height
println("\(tempMin)-\(tempMax) - tested : \(testedSize) --> difference : \(difference)")
if(difference > 0){
tempMin = testedSize
}else{
tempMax = testedSize
}
}
//returning the size -1 (to have enought space right and left)
return UIFont(name: fontName, size: tempMin - 1)
}
und ich benutze es so:
myLabel.font = optimisedfindAdaptiveFontWithName("Helvetica", label: myLabel, minSize: 10, maxSize: 38)
println("\(myLabel.font)")
Gute Nachrichten,
Sie müssen nur (einige Male) mithilfe einer Ratio-Suche iterieren.
guess = guess * ( desiredHeight / guessHeight )
Hier ist eine vollständige IBDesignable
-Lösung.
Hinweis: Wenn Sie mit Designern oder Typographen arbeiten, müssen Sie das Tracking/Stretching für Schriftarten festlegen. (Es ist absurd, dass Apple dies nicht enthält.) StyledLabel
enthält auch Tracking/Stretching.
// the call fontToFitHeight FINDS THE POINT SIZE TO "FILL TO HEIGHT".
// Just use autolayout to make the frame THE ACTUAL HEIGHT
// you want the type ON ANY DEVICE
// ADDITIONALLY you can set:
// the tracking (that's the overall amount of space between all letters)
// and streching (actually squeeze or stretch the letters horizontally)
// Note: tracking and stretching IS SHOWN IN STORYBOARD LIVE
// WTT crazyrems http://stackoverflow.com/a/37300130/294884
import UIKit
@IBDesignable
class StyledLabel: UILabel
{
@IBInspectable var tracking:CGFloat = 0.8
// values between about 0.7 to 1.3. one means normal.
@IBInspectable var stretching:CGFloat = -0.1
// values between about -.5 to .5. zero means normal.
override func awakeFromNib()
{
Tweak()
}
override func prepareForInterfaceBuilder()
{
Tweak()
}
override func layoutSubviews()
{
super.layoutSubviews()
font = fontToFitHeight()
}
private func fontToFitHeight() -> UIFont
{
/* Apple have failed to include a basic thing needed in handling text: fitting the text to the height. Here's the simplest and fastest way to do that:
guess = guess * ( desiredHeight / guessHeight )
That's really all there is to it. The rest of the code in this routine is safeguards. Further, the routine iterates a couple of times, which is harmless, to take care of any theoretical bizarre nonlinear sizing issues with strange typefaces. */
guard text?.characters.count > 0 else { return font }
let desiredHeight:CGFloat = frame.size.height
guard desiredHeight>1 else { return font }
var guess:CGFloat
var guessHeight:CGFloat
print("searching for... ", desiredHeight)
guess = font.pointSize
if (guess>1&&guess<1000) { guess = 50 }
guessHeight = sizeIf(guess)
if (guessHeight==desiredHeight)
{
print("fluke, exact match within float math limits, up front")
return font.fontWithSize(guess)
}
var iterations:Int = 4
/* It is incredibly unlikely you would need more than four iterations, "two" would rarely be needed. You could imagine some very strange glyph handling where the relationship is non-linear (or something weird): That is the only theoretical reason you'd ever need more than one or two iterations. Note that when you watch the output of the iterations, you'll sometimes/often see same or identical values for the result: this is correct and expected in a float iteration. */
while(iterations>0)
{
guess = guess * ( desiredHeight / guessHeight )
guessHeight = sizeIf(guess)
if (guessHeight==desiredHeight)
{
print("unbelievable fluke, exact match within float math limits while iterating")
return font.fontWithSize(guess)
}
iterations -= 1
}
print("done. Shame Apple doesn't do this for us!")
return font.fontWithSize(guess)
}
private func sizeIf(pointSizeToTry:CGFloat)->(CGFloat)
{
let s:CGFloat = text!.sizeWithAttributes(
[NSFontAttributeName: font.fontWithSize(pointSizeToTry)] )
.height
print("guessing .. ", pointSizeToTry, " .. " , s)
return s
}
private func Tweak()
{
let ats = NSMutableAttributedString(string: self.text!)
let rg = NSRange(location: 0, length: self.text!.characters.count)
ats.addAttribute(
NSKernAttributeName, value:CGFloat(tracking), range:rg )
ats.addAttribute(
NSExpansionAttributeName, value:CGFloat(stretching), range:rg )
self.attributedText = ats
}
}
Eine in viewWillAppear aufgerufene Zeile macht den Trick:
testLabel.font = testLabel.font.fontWithSize(testLabel.frame.height * 2/3)
Im Storyboard habe ich alle meine Etikettenhöhen relativ zur Gesamthöhe der Ansicht festgelegt. Dadurch kann die Schriftgröße dynamisch an sie angepasst werden.
Beachten Sie, dass die Schriftgröße 2/3 der Etikettenhöhe beträgt. Wenn die Schriftart, die Sie verwenden, unter der Linie liegt (wie in y, g, q, p oder j), sollten Sie die Schriftgröße als Verhältnis der Etikettenhöhe festlegen, damit diese Enden nicht geschnitten werden aus. 2/3 funktioniert gut für Helvetica Neue, aber probieren Sie andere Verhältnisse abhängig von der verwendeten Schriftart. Für Schriften ohne Zahl, Zahl oder Text mit Großbuchstaben kann ein Verhältnis von 1: 1 ausreichen.
Basierend auf der großartigen Antwort von @ Conaaando habe ich sie auf eine Version mit IBDesignable-Parametern aktualisiert, die es ermöglicht, sie im Interface-Builder zu bearbeiten:
Und der Code:
//
// TIFFitToHeightLabel.Swift
//
import Foundation
import UIKit
@IBDesignable class TIFFitToHeightLabel: UILabel {
@IBInspectable var minFontSize:CGFloat = 12 {
didSet {
font = fontToFitHeight()
}
}
@IBInspectable var maxFontSize:CGFloat = 30 {
didSet {
font = fontToFitHeight()
}
}
override func layoutSubviews() {
super.layoutSubviews()
font = fontToFitHeight()
}
// Returns an UIFont that fits the new label's height.
private func fontToFitHeight() -> UIFont {
var minFontSize: CGFloat = self.minFontSize
var maxFontSize: CGFloat = self.maxFontSize
var fontSizeAverage: CGFloat = 0
var textAndLabelHeightDiff: CGFloat = 0
while (minFontSize <= maxFontSize) {
fontSizeAverage = minFontSize + (maxFontSize - minFontSize) / 2
if let labelText: NSString = text {
let labelHeight = frame.size.height
let testStringHeight = labelText.sizeWithAttributes(
[NSFontAttributeName: font.fontWithSize(fontSizeAverage)]
).height
textAndLabelHeightDiff = labelHeight - testStringHeight
if (fontSizeAverage == minFontSize || fontSizeAverage == maxFontSize) {
if (textAndLabelHeightDiff < 0) {
return font.fontWithSize(fontSizeAverage - 1)
}
return font.fontWithSize(fontSizeAverage)
}
if (textAndLabelHeightDiff < 0) {
maxFontSize = fontSizeAverage - 1
} else if (textAndLabelHeightDiff > 0) {
minFontSize = fontSizeAverage + 1
} else {
return font.fontWithSize(fontSizeAverage)
}
}
}
return font.fontWithSize(fontSizeAverage)
}
}
Dies geht stark auf die Antwort von Joel Fischer zurück. Seine Antwort berücksichtigt nur die Etikettenhöhe. Ich habe einige Änderungen vorgenommen, um auch die Etikettenbreite zu berücksichtigen (bei Eingabe einer Zeichenfolge), die ich wollte:
typedef enum
{
kDimensionHeight,
kDimensionWidth,
} DimensionType;
@implementation UIFont (AdaptiveFont)
+ (UIFont *)_adaptiveFontWithName:(NSString *)fontName minSize:(NSInteger)minSize labelDimension:(CGFloat)labelDimension testString:(NSString *)testString dimension:(DimensionType)dimension
{
UIFont *tempFont = nil;
NSInteger tempMin = minSize;
NSInteger tempMax = 256;
NSInteger mid = 0;
NSInteger difference = 0;
CGFloat testStringDimension = 0.0;
while (tempMin <= tempMax) {
@autoreleasepool {
mid = tempMin + (tempMax - tempMin) / 2;
tempFont = [UIFont fontWithName:fontName size:mid];
// determine dimension to test
if (dimension == kDimensionHeight) {
testStringDimension = [testString sizeWithFont:tempFont].height;
} else {
testStringDimension = [testString sizeWithFont:tempFont].width;
}
difference = labelDimension - testStringDimension;
if (mid == tempMin || mid == tempMax) {
if (difference < 0) {
return [UIFont fontWithName:fontName size:(mid - 1)];
}
return [UIFont fontWithName:fontName size:mid];
}
if (difference < 0) {
tempMax = mid - 1;
} else if (difference > 0) {
tempMin = mid + 1;
} else {
return [UIFont fontWithName:fontName size:mid];
}
}
}
return [UIFont fontWithName:fontName size:mid];
}
+ (UIFont *)adaptiveFontWithName:(NSString *)fontName minSize:(NSInteger)minSize labelSize:(CGSize)labelSize string:(NSString *)string
{
UIFont *adaptiveFont = nil;
NSString *testString = nil;
// get font, given a max height
testString = @"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
UIFont *fontConstrainingHeight = [UIFont _adaptiveFontWithName:fontName minSize:minSize labelDimension:labelSize.height testString:testString dimension:kDimensionHeight];
CGSize boundsConstrainingHeight = [string sizeWithFont:fontConstrainingHeight];
CGSize boundsConstrainingWidth = CGSizeZero;
// if WIDTH is fine (while constraining HEIGHT), return that font
if (boundsConstrainingHeight.width <= labelSize.width) {
adaptiveFont = fontConstrainingHeight;
} else {
// get font, given a max width
// i.e., fontConstrainingWidth
testString = string;
adaptiveFont = [UIFont _adaptiveFontWithName:fontName minSize:minSize labelDimension:labelSize.width testString:testString dimension:kDimensionWidth];
// TEST comparison
boundsConstrainingWidth = [string sizeWithFont:adaptiveFont];
}
return adaptiveFont;
}
Auf die Antwort von @Joe Blow eingegangen, ist hier eine Objective-C-Kategorie UILabel+FitToHeight
, mit der Sie eine adjustsFontSizeToFitHeight
auf einfache Weise importieren und umschalten können, ähnlich wie Sie bereits adjustsFontSizeToFitWidth
können.
UILabel + FitToHeight.h
#import <UIKit/UIKit.h>
@interface UILabel (FitToHeight)
@property (nonatomic, assign) BOOL adjustsFontSizeToFitHeight;
@end
UILabel + FitToHeight.m
#import "UILabel+FitToHeight.h"
#import <objc/runtime.h>
@implementation UILabel (FitToHeight)
-(BOOL)adjustsFontSizeToFitHeight {
NSNumber *number = objc_getAssociatedObject(self, @selector(adjustsFontSizeToFitHeight));
return [number boolValue];
}
-(void)setAdjustsFontSizeToFitHeight:(BOOL)adjustsFontSizeToFitHeight {
NSNumber *number = [NSNumber numberWithBool:adjustsFontSizeToFitHeight];
objc_setAssociatedObject(self, @selector(adjustsFontSizeToFitHeight), number, OBJC_ASSOCIATION_ASSIGN);
}
-(UIFont *)fontToFitHeight {
float desiredHeight = [self frame].size.height;
float guess;
float guessHeight;
guess = [[self font] pointSize];
guessHeight = [self sizeIf:guess];
if(guessHeight == desiredHeight) {
return [[self font] fontWithSize:guess];
}
int attempts = 4;
while(attempts > 0) {
guess = guess * (desiredHeight / guessHeight);
guessHeight = [self sizeIf:guess];
if(guessHeight == desiredHeight) {
return [[self font] fontWithSize:guess];
}
attempts--;
}
return [[self font] fontWithSize:guess];
}
-(float)sizeIf:(float)sizeToTry {
CGSize size = [[self text] sizeWithAttributes:@{ NSFontAttributeName : [[self font] fontWithSize:sizeToTry] }];
return size.height;
}
-(void)layoutSubviews {
[super layoutSubviews];
if([self adjustsFontSizeToFitHeight]) {
[self setFont:[self fontToFitHeight]];
}
}
Importieren Sie wie jede andere Kategorie ...
#import "UILabel+FitToHeight.h"
und wie folgt verwenden ...
UILabel *titleLabel = [[UILabel alloc] init];
[titleLabel setAdjustsFontSizeToFitHeight:YES];
[titleLabel setAdjustsFontSizeToFitWidth:YES];
Es ist erwähnenswert, dass still mit [titleLabel setAdjustsFontSizeToFitWidth:YES];
zusammenarbeitet, so dass die Verwendung der beiden in Verbindung möglich ist.
Es gibt eine viel einfachere Möglichkeit, dies zu tun. Berechnen Sie einfach den Punkt pro Pixel des Bildschirms und multiplizieren Sie ihn mit der Höhe Ihres Etiketts, und Sie erhalten die gewünschte Schriftgröße.
Hier sind benutzerdefinierte Methoden dafür. Wählen Sie, was Sie wollen.
TYP 1. Hardodierte einzeilige Version:
- (CGFloat) fontSizeFromHeight:(CGFloat)height
{
return ceilf(height * (10.0 / [@"Tg" sizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:10.0]}].height));
}
TYP 2. Sauberere Version:
- (CGFloat)fontSizeFromHeight:(CGFloat)height
{
static CGFloat const testFontSize = 12.0;
static NSString * const testText = @"TestString";
UIFont *testFont = [UIFont systemFontOfSize:testFontSize];
CGFloat pixelHeight = [testText sizeWithAttributes:@{NSFontAttributeName:testFont}].height;
CGFloat pointPerPixel = testFontSize / pixelHeight;
CGFloat desiredFontSize = ceilf(height * pointPerPixel);
return desiredFontSize;
}
Anwendungsbeispiele:
myLabel.font = [UIFont systemFontOfSize:[self fontSizeFromHeight:myLabel.frame.size.height]];
myLabel.font = [myLabel.font fontWithSize:[self fontSizeFromHeight:myLabel.frame.size.height]];
Verzeihen Sie, wenn ich falsch liege, aber alles, was hier erwähnt wird, ist unnötig. Setzen Sie Ihre Schriftart unmittelbar nach der Änderung erneut mit einer neuen fontSize von yourLabel.height
Sie können auch nach einem bedingten Vergleich zwischen diesen Werten (yourLabel.height und fontSize) suchen, um unnötige Aktualisierungen zu vermeiden.
Alles was Sie tun müssen, ist:
[yourLabel setFont:[UIFont fontWithName:@"*your fontname*" size:yourLabel.frame.size.height]];
Die akzeptierte Antwort enthält einen Fehler. Der variable Abstand muss ein Float sein, oder er kann eine zu große Schriftgröße zurückgeben. Die Verwendung von "- (CGSize) sizeWithFont: (UIFont *) font;" ist veraltet. Hier ist der Code mit diesen 2 Problemen behoben.
+ (UIFont *)findAdaptiveFontWithName:(NSString *)fontName forUILabelSize:(float)maxHeight withMaxFontSize:(int)maxFontSize
{
UIFont *tempFont = nil;
NSString *testString = @"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
NSInteger tempMin = 0;
NSInteger tempMax = maxFontSize;
NSInteger mid = 0;
float difference = 0;
while (tempMin <= tempMax) {
mid = tempMin + (tempMax - tempMin) / 2;
tempFont = [UIFont fontWithName:fontName size:mid];
UILabel* dummyLabel = [[UILabel alloc] initWithFrame:CGRectZero];
dummyLabel.text = testString;
dummyLabel.font = tempFont;
[dummyLabel sizeToFit];
difference = maxHeight - dummyLabel.bounds.size.height;
if (mid == tempMin || mid == tempMax) {
if (difference < 0) {
return [UIFont fontWithName:fontName size:(mid - 1)];
}
return [UIFont fontWithName:fontName size:mid];
}
if (difference < 0) {
tempMax = mid - 1;
} else if (difference > 0) {
tempMin = mid + 1;
} else {
return [UIFont fontWithName:fontName size:mid];
}
}
return [UIFont fontWithName:fontName size:mid];
}
Schnelle Variation:
Ich habe es mit einer Erweiterung geschafft. Funktioniert gut, die minimale Schriftgröße ist 5. Ich subtrahiere 10 von der Höhe, daher lasse ich auch einen "Rand", aber Sie können ihn löschen oder ändern.
extension UILabel {
//Finds and sets a font size that matches the height of the frame.
//Use in case the font size is epic huge and you need to resize it.
func resizeToFitHeight(){
var currentfontSize = font.pointSize
let minFontsize = CGFloat(5)
let constrainedSize = CGSizeMake(frame.width, CGFloat.max)
while (currentfontSize >= minFontsize){
let newFont = font.fontWithSize(currentfontSize)
let attributedText: NSAttributedString = NSAttributedString(string: text!, attributes: [NSFontAttributeName: newFont])
let rect: CGRect = attributedText.boundingRectWithSize(constrainedSize, options: .UsesLineFragmentOrigin, context: nil)
let size: CGSize = rect.size
if (size.height < frame.height - 10) {
font = newFont
break;
}
currentfontSize--
}
//In case the text is too long, we still show something... ;)
if (currentfontSize == minFontsize){
font = font.fontWithSize(currentfontSize)
}
}
}
Ich entschuldige mich, wenn ich hier im Text etwas verpasst habe.
Ich folgte @Crazyrems-Vorschlägen zum automatischen Schrumpfen der Schriftart des Labels. Dies skaliert die Schriftart basierend auf der Breite, wie von anderen beobachtet.
Dann habe ich 'Lines' im UILabel-Schriftbereich von Xcode auf 0 gesetzt. Im Code sollte dies numberOfLines
sein. Das ist alles.
Dank geht an @Mikrasya, der in einem der obigen Kommentare auf diese Lösung hingewiesen hat.
Getestet mit Xcode 7.3 und iOS 9.3.2.
Dies schien für mich zu funktionieren, ich habe UILabel untergeordnet und in den layoutSubviews die tatsächliche Höhe überprüft und die Schriftgröße entsprechend angepasst.
import UIKit
class HeightAdjustableLabel: UILabel {
override func layoutSubviews() {
super.layoutSubviews()
if frame.height < font.pointSize + 2 {
font = font.withSize(frame.height - 2)
}
}
}
Aufbauend auf Joel Fishers epischer Antwort aber als Swift 4 -Erweiterung geschrieben:
extension String {
/// Attempts to return the font specified by name of the appropriate point
/// size for this string to fit within a particular container size and
/// constrained to a lower and upper bound point size.
/// - parameter name: of the font.
/// - parameter containerSize: that this string should fit inside.
/// - parameter lowerBound: minimum allowable point size of this font.
/// - parameter upperBound: maximum allowable point size of this font.
/// - returns: the font specified by name of the appropriate point
/// size for this string to fit within a particular container size and
/// constrained to a lower and upper bound point size; `nil` if no such
/// font exists.
public func font(named name: String,
toFit containerSize: CGSize,
noSmallerThan lowerBound: CGFloat = 1.0,
noLargerThan upperBound: CGFloat = 256.0) -> UIFont? {
let lowerBound = lowerBound > upperBound ? upperBound : lowerBound
let mid = lowerBound + (upperBound - lowerBound) / 2
guard let tempFont = UIFont(name: name, size: mid) else { return nil }
let difference = containerSize.height -
self.size(withAttributes:
[NSAttributedStringKey.font : tempFont]).height
if mid == lowerBound || mid == upperBound {
return UIFont(name: name, size: difference < 0 ? mid - 1 : mid)
}
return difference < 0 ? font(named: name,
toFit: containerSize,
noSmallerThan: mid,
noLargerThan: mid - 1) :
(difference > 0 ? font(named: name,
toFit: containerSize,
noSmallerThan: mid,
noLargerThan: mid - 1) :
UIFont(name: name, size: mid))
}
/// Returns the system font of the appropriate point size for this string
/// to fit within a particular container size and constrained to a lower
/// and upper bound point size.
/// - parameter containerSize: that this string should fit inside.
/// - parameter lowerBound: minimum allowable point size of this font.
/// - parameter upperBound: maximum allowable point size of this font.
/// - returns: the system font of the appropriate point size for this string
/// to fit within a particular container size and constrained to a lower
/// and upper bound point size.
public func systemFont(toFit containerSize: CGSize,
noSmallerThan lowerBound: CGFloat = 1.0,
noLargerThan upperBound: CGFloat = 256.0) -> UIFont {
let lowerBound = lowerBound > upperBound ? upperBound : lowerBound
let mid = lowerBound + (upperBound - lowerBound) / 2
let tempFont = UIFont.systemFont(ofSize: mid)
let difference = containerSize.height -
self.size(withAttributes:
[NSAttributedStringKey.font : tempFont]).height
if mid == lowerBound || mid == upperBound {
return UIFont.systemFont(ofSize: difference < 0 ? mid - 1 : mid)
}
return difference < 0 ? systemFont(toFit: containerSize,
noSmallerThan: mid,
noLargerThan: mid - 1) :
(difference > 0 ? systemFont(toFit: containerSize,
noSmallerThan: mid,
noLargerThan: mid - 1) :
UIFont.systemFont(ofSize: mid))
}
}
Verwendungszweck:
let font = "Test string".font(named: "Courier New",
toFit: CGSize(width: 150.0, height: 30.0),
noSmallerThan: 12.0,
noLargerThan: 20.0)
let sysfont = "Test string".systemFont(toFit: CGSize(width: 150.0, height: 30.0),
noSmallerThan: 12.0,
noLargerThan: 20.0)
Für UILabels, deren Größe für größere/kleinere Geräte proportional geändert wird:
Die effektivste Lösung für mich war es, die Punktgröße der Schrift auf ein Verhältnis der Höhe der Beschriftung +/- eines Anpassungsfaktors einzustellen. Unter der Annahme, dass Einschränkungen für das automatische Layout verwendet werden, positionieren Sie die Position um y vertikal am unteren Rand des Übersichtsobjekts, multipliziert mit einem Verhältnis. Auf ähnliche Weise beschränken Sie in IB die Breite des Etiketts auf einen Anteil der Bildschirmbreite.
Optional können Sie das Höhen-/Breitenverhältnis des Etiketts mit einer Seitenbeschränkung sperren. Dies kann jedoch zu Beschneidungen führen, wenn Sie die Berechnung der Punktgröße nicht richtig vornehmen. Der einzige Grund zum Sperren des Seitenverhältnisses ist, wenn die Positionen anderer Steuerelemente/Ansichten relativ zu dieser Bezeichnung sind. Ich empfehle jedoch dringend, solche Steuerelemente/Ansichten relativ zur Höhe/Breite des Superview zu platzieren, damit sie nicht von dieser Bezeichnung abhängig sind.
Ich verstehe, dass dies nicht gerade eine gekapselte Lösung ist, aber es hat mir immer die geringste Trauer gebracht. Die einzige andere Lösung, die nahe kam, nutzte While-Schleifen. In meinem Fall konnte ich jedoch nicht mit den Verzögerungen umgehen, die sie bei jedem Layout/Refresh-Systemaufruf verursachten.