way*_*neh 55 iphone xcode objective-c ios
我看过很多改变UILabel大小的例子.
这是我想要做的:更改字体大小,以便文本在新高度内尽可能大.
有线索吗?
bac*_*h-f 41
我有同样的问题,由于这个线程和Joel的算法,我可以解决它.:-)
下面是我在Swift中的代码.我在iOS 8 + Autolayout.
问题:


修复后:

这正是设计师的想法... :)

我将UILabel子类化并覆盖layoutSubviews.然后每次UILabel更改其大小时,都会重新计算字体大小:
//
// 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)
}
}
Run Code Online (Sandbox Code Playgroud)
Kas*_*hif 32
有一个更简单的解决方案.只需添加以下线条并且神奇地,标签也会调整其字体大小以适应标签的高度:
SWIFT 3:
label.minimumScaleFactor = 0.1 //or whatever suits your need
label.adjustsFontSizeToFitWidth = true
label.lineBreakMode = .byClipping
label.numberOfLines = 0
Run Code Online (Sandbox Code Playgroud)
Joe*_*her 31
这就是我如何做到的,因为DGund的答案对我来说不起作用,它适合宽度,但我希望它适合高度.
+ (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];
}
Run Code Online (Sandbox Code Playgroud)
这将采用字体名称,大小(理论上它不一定是UILabel,但我总是用UILabel)和最小尺寸(你也可以使用最大尺寸,只需用256替换最大尺寸参数).这将主要测试最小和最大字体大小之间的每个字体大小,并返回目标高度处或之下的字体大小.
用法是自解释的,但看起来像这样:
self.myLabel.font = [self findAdaptiveFontWithName:@"HelveticaNeue-UltraLight" forUILabelSize:self.myLabel.frame.size withMinimumSize:30];
Run Code Online (Sandbox Code Playgroud)
您也可以在UIFont上创建一个类方法类别(这就是我所做的).
编辑:根据建议,我删除了for循环并花了一点时间使用二进制搜索例程提高效率.我做了几次检查,以确保字体最终适合标签.在初始测试中它似乎工作.
DGu*_*und 21
编辑:查看Joel Fischer的最佳答案,以编程方式获得正确的大小!
您可以将字体设置为自动填充标签的大小,也可以选择不低于最小字体大小.如果您需要更多信息adjustsFontSizeToFitWidth,YES.请设置为查看UILabel类参考.
虽然布尔值被称为"adjustsFontSizeToFitWidth",但它实际上意味着标签高度的最大尺寸,它将保留在标签的一行(或者指定的行数).
Fjo*_*ohn 13
根据我的标签高度调整文本我已经适应了Joel方法
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)
}
Run Code Online (Sandbox Code Playgroud)
我这样使用它:
myLabel.font = optimisedfindAdaptiveFontWithName("Helvetica", label: myLabel, minSize: 10, maxSize: 38)
println("\(myLabel.font)")
Run Code Online (Sandbox Code Playgroud)
好消息,
您只需要使用比率搜索进行迭代(几次).
guess = guess * ( desiredHeight / guessHeight )
Run Code Online (Sandbox Code Playgroud)
这是一个完整的整体IBDesignable解决方案.
注意:与设计师或印刷师合作时,您需要设置字体的跟踪/拉伸.(这是荒谬的苹果不包括这个.)StyledLabel 还包括跟踪/拉伸.
// 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
}
}
Run Code Online (Sandbox Code Playgroud)
基于@ Conaaando的出色答案,我已将其更新为包含IBDesignable参数的版本,这使得可以在整个"界面"构建器中对其进行编辑:

和代码:
//
// 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)
}
}
Run Code Online (Sandbox Code Playgroud)
在viewWillAppear中调用的一行可以解决这个问题:
testLabel.font = testLabel.font.fontWithSize(testLabel.frame.height * 2/3)
Run Code Online (Sandbox Code Playgroud)
在故事板中,我将所有标签高度设置为相对于视图的整体高度,这允许字体大小与它们动态缩放.
请注意,字体大小实际上是标签高度的2/3.如果您使用的字体的尾部低于线条(如y,g,q,p或j),则需要使字体大小为标签高度的比例,以使这些尾部不会被切断关闭.2/3适用于Helvetica Neue,但根据您使用的字体尝试其他比率.对于没有尾部,数字或全部大写文本的字体,1:1的比例可能就足够了.
| 归档时间: |
|
| 查看次数: |
37659 次 |
| 最近记录: |