特定のテキストから行数とUILabelの高さを動的に計算したいと思います。
これを試して
// UILabel *myLabel;
CGSize labelSize = [myLabel.text sizeWithFont:myLabel.font
constrainedToSize:myLabel.frame.size
lineBreakMode:NSLineBreakByWordWrapping];
CGFloat labelHeight = labelSize.height;
int lines = [myLabel.text sizeWithFont:myLabel.font
constrainedToSize:myLabel.frame.size
lineBreakMode:NSLineBreakByWordWrapping].height/16;
// '16' is font size
または
int lines = labelHeight/16;
NSLog(@"lines count : %i \n\n",lines);
または
int lines = [myLabel.text sizeWithFont:myLabel.font
constrainedToSize:myLabel.frame.size
lineBreakMode:UILineBreakModeWordWrap].height /myLabel.font.pointSize; //fetching font size from font
カテゴリを使用して、という名前のカテゴリクラスを作成します。
ILabel + UILabelDynamicHeight.h
ILabel + UILabelDynamicHeight.m
高さの計算についてこれ以上の緊張はありません。以下の実装を確認してください。
iOS7以上のアップデート、以下のiOS 7:UILabelの高さを動的に計算
#define SYSTEM_VERSION_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedSame)
#define SYSTEM_VERSION_GREATER_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedDescending)
#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedDescending)
#define iOS7_0 @"7.0"
ILabel + UILabelDynamicHeight.h
#import <UIKit/UIKit.h>
@interface UILabel (UILabelDynamicHeight)
#pragma mark - Calculate the size the Multi line Label
/*====================================================================*/
/* Calculate the size of the Multi line Label */
/*====================================================================*/
/**
* Returns the size of the Label
*
* @param aLabel To be used to calculte the height
*
* @return size of the Label
*/
-(CGSize)sizeOfMultiLineLabel;
@end
ILabel + UILabelDynamicHeight.m
#import "UILabel+UILabelDynamicHeight.h"
@implementation UILabel (UILabelDynamicHeight)
#pragma mark - Calculate the size,bounds,frame of the Multi line Label
/*====================================================================*/
/* Calculate the size,bounds,frame of the Multi line Label */
/*====================================================================*/
/**
* Returns the size of the Label
*
* @param aLabel To be used to calculte the height
*
* @return size of the Label
*/
-(CGSize)sizeOfMultiLineLabel{
//Label text
NSString *aLabelTextString = [self text];
//Label font
UIFont *aLabelFont = [self font];
//Width of the Label
CGFloat aLabelSizeWidth = self.frame.size.width;
if (SYSTEM_VERSION_LESS_THAN(iOS7_0)) {
//version < 7.0
return [aLabelTextString sizeWithFont:aLabelFont
constrainedToSize:CGSizeMake(aLabelSizeWidth, MAXFLOAT)
lineBreakMode:NSLineBreakByWordWrapping];
}
else if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(iOS7_0)) {
//version >= 7.0
//Return the calculated size of the Label
return [aLabelTextString boundingRectWithSize:CGSizeMake(aLabelSizeWidth, MAXFLOAT)
options:NSStringDrawingUsesLineFragmentOrigin
attributes:@{
NSFontAttributeName : aLabelFont
}
context:nil].size;
}
return [self bounds].size;
}
@end
UILabelインスタンスで-sizeToFit
を呼び出すと、表示するテキストに合わせて自動的にサイズが変更され、計算は不要です。サイズが必要な場合は、その後ラベルのフレームプロパティからサイズを取得できます。
label.numberOfLines = 0; // allows label to have as many lines as needed
label.text = @"some long text";
[label sizeToFit];
NSLog(@"Label's frame is: %@", NSStringFromCGRect(label.frame));
要約すると、文字列を使用してboundingRectWithSize
を呼び出すことにより、ラベルの高さを計算できます。属性としてfont
を指定し、複数行ラベルに.usesLineFragmentOrigin
を含める必要があります。
let labelWidth = label.frame.width
let maxLabelSize = CGSize(width: labelWidth, height: CGFloat.greatestFiniteMagnitude)
let actualLabelSize = label.text!.boundingRect(with: maxLabelSize, options: [.usesLineFragmentOrigin], attributes: [.font: label.font], context: nil)
let labelHeight = actualLabelSize.height(withWidth:labelWidth)
それを行うための拡張機能:
extension UILabel {
func textHeight(withWidth width: CGFloat) -> CGFloat {
guard let text = text else {
return 0
}
return text.height(withWidth: width, font: font)
}
func attributedTextHeight(withWidth width: CGFloat) -> CGFloat {
guard let attributedText = attributedText else {
return 0
}
return attributedText.height(withWidth: width)
}
}
extension String {
func height(withWidth width: CGFloat, font: UIFont) -> CGFloat {
let maxSize = CGSize(width: width, height: CGFloat.greatestFiniteMagnitude)
let actualSize = self.boundingRect(with: maxSize, options: [.usesLineFragmentOrigin], attributes: [.font : font], context: nil)
return actualSize.height
}
}
extension NSAttributedString {
func height(withWidth width: CGFloat) -> CGFloat {
let maxSize = CGSize(width: width, height: CGFloat.greatestFiniteMagnitude)
let actualSize = boundingRect(with: maxSize, options: [.usesLineFragmentOrigin], context: nil)
return actualSize.height
}
}
ILabel + Utility.h
#import <UIKit/UIKit.h>
@interface UILabel (Utility)
- (CGFloat)textHeightForWidth:(CGFloat)width;
- (CGFloat)attributedTextHeightForWidth:(CGFloat)width;
@end
ILabel + Utility.m
@implementation NSString (Utility)
- (CGFloat)heightForWidth:(CGFloat)width font:(UIFont *)font {
CGSize maxSize = CGSizeMake(width, CGFLOAT_MAX);
CGSize actualSize = [self boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName : font} context:nil].size;
return actualSize.height;
}
@end
@implementation NSAttributedString (Utility)
- (CGFloat)heightForWidth:(CGFloat)width {
CGSize maxSize = CGSizeMake(width, CGFLOAT_MAX);
CGSize actualSize = [self boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin context:nil].size;
return actualSize.height;
}
@end
@implementation UILabel (Utility)
- (CGFloat)textHeightForWidth:(CGFloat)width {
return [self.text heightForWidth:width font:self.font];
}
- (CGFloat)attributedTextHeightForWidth:(CGFloat)width {
return [self.attributedText heightForWidth:width];
}
@end
現在のソリューションは、iOS 7で非推奨になりました。
更新されたソリューションは次のとおりです。
+ (CGFloat)heightOfCellWithIngredientLine:(NSString *)ingredientLine
withSuperviewWidth:(CGFloat)superviewWidth
{
CGFloat labelWidth = superviewWidth - 30.0f;
// use the known label width with a maximum height of 100 points
CGSize labelContraints = CGSizeMake(labelWidth, 100.0f);
NSStringDrawingContext *context = [[NSStringDrawingContext alloc] init];
CGRect labelRect = [ingredientLine boundingRectWithSize:labelContraints
options:NSStringDrawingUsesLineFragmentOrigin
attributes:nil
context:context];
// return the calculated required height of the cell considering the label
return labelRect.size.height;
}
ソリューションがこのように設定されている理由は、UITableViewCellを使用し、ラベルが占めるスペースに応じてセルのサイズを動的に変更しているためです。
SizeToFitを呼び出すことなく、非常にプラグアンドプレイのソリューションを使用してこれをすべて数値的に実行できます。
+ (CGFloat)heightForText:(NSString*)text font:(UIFont*)font withinWidth:(CGFloat)width {
CGSize size = [text sizeWithAttributes:@{NSFontAttributeName:font}];
CGFloat area = size.height * size.width;
CGFloat height = roundf(area / width);
return ceilf(height / font.lineHeight) * font.lineHeight;
}
高さを動的に割り当てられたUITableViewCellsでよく使用します。
@Salman Zaidiの属性の問題も解決します。
このメソッドをコピーして貼り付け、次のように使用します:
[lblText setFrame:CGRectMake(lblText.frame.Origin.x, lblText.frame.Origin.y, width, [self getLabelHeight:lblText])];
- (CGFloat)getLabelHeight:(UILabel*)label
{
CGSize constraint = CGSizeMake(label.frame.size.width, CGFLOAT_MAX);
CGSize size;
NSStringDrawingContext *context = [[NSStringDrawingContext alloc] init];
CGSize boundingBox = [label.text boundingRectWithSize:constraint
options:NSStringDrawingUsesLineFragmentOrigin
attributes:@{NSFontAttributeName:label.font}
context:context].size;
size = CGSizeMake(ceil(boundingBox.width), ceil(boundingBox.height));
return size.height;
}
CGSize maxSize = CGSizeMake(lbl.frame.size.width, CGFLOAT_MAX);
CGSize requiredSize = [lbl sizeThatFits:maxSize];
CGFloat height=requiredSize.height
Stringの拡張を作成し、このメソッドを呼び出す必要があります
func height(withConstrainedWidth width: CGFloat, font: UIFont) -> CGFloat {
let constraintRect = CGSize(width: width, height: .greatestFiniteMagnitude)
let boundingBox = self.boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, attributes: [NSFontAttributeName: font], context: nil)
return ceil(boundingBox.height)
}
ラベルの幅を送信する必要があります
Swift 4NSAttributedString の高さを取得するには、以下のこの関数を使用します。 wherewidth- ILabel または ITextView の幅
func getHeight(for attributedString: NSAttributedString, font: UIFont, width: CGFloat) -> CGFloat {
let textStorage = NSTextStorage(attributedString: attributedString)
let textContainter = NSTextContainer(size: CGSize(width: width, height: CGFloat.greatestFiniteMagnitude))
let layoutManager = NSLayoutManager()
layoutManager.addTextContainer(textContainter)
textStorage.addLayoutManager(layoutManager)
textStorage.addAttribute(NSAttributedStringKey.font, value: font, range: NSMakeRange(0, textStorage.length))
textContainter.lineFragmentPadding = 0.0
layoutManager.glyphRange(for: textContainter)
return layoutManager.usedRect(for: textContainter).size.height
}
String の高さを取得するには、この関数を使用します。前の方法とほぼ同じです。
func getHeight(for string: String, font: UIFont, width: CGFloat) -> CGFloat {
let textStorage = NSTextStorage(string: string)
let textContainter = NSTextContainer(size: CGSize(width: width, height: CGFloat.greatestFiniteMagnitude))
let layoutManager = NSLayoutManager()
layoutManager.addTextContainer(textContainter)
textStorage.addLayoutManager(layoutManager)
textStorage.addAttribute(NSAttributedStringKey.font, value: font, range: NSMakeRange(0, textStorage.length))
textContainter.lineFragmentPadding = 0.0
layoutManager.glyphRange(for: textContainter)
return layoutManager.usedRect(for: textContainter).size.height
}
これは、複数行のUILabelの高さを計算するために使用する拡張機能であり、以前のスタックオーバーフローの投稿からの調整済みのスニペットです。
extension UILabel {
func estimatedHeight(forWidth: CGFloat, text: String, ofSize: CGFloat) -> CGFloat {
let size = CGSize(width: forWidth, height: CGFloat(MAXFLOAT))
let options = NSStringDrawingOptions.usesFontLeading.union(.usesLineFragmentOrigin)
let attributes = [NSFontAttributeName: UIFont.systemFont(ofSize: ofSize)]
let rectangleHeight = String(text).boundingRect(with: size, options: options, attributes: attributes, context: nil).height
return ceil(rectangleHeight)
}
}
属性付きのUILabelを使用している場合は、textRect(forBounds:limitedToNumberOfLines)
メソッドを試すことができます。
これは私の例です:
let label = UILabel(frame: CGRect(x: 0, y: 0, width: 100, height: 30))
label.numberOfLines = 0
label.text = "Learn how to use RxSwift and RxCocoa to write applications that can react to changes in your underlying data without you telling it to do so."
let rectOfLabel = label.textRect(forBounds: CGRect(x: 0, y: 0, width: 100, height: CGFloat.greatestFiniteMagnitude), limitedToNumberOfLines: 0)
let rectOfLabelOneLine = label.textRect(forBounds: CGRect(x: 0, y: 0, width: 100, height: CGFloat.greatestFiniteMagnitude), limitedToNumberOfLines: 1)
let heightOfLabel = rectOfLabel.height
let heightOfLine = rectOfLabelOneLine.height
let numberOfLines = Int(heightOfLabel / heightOfLine)
プレイグラウンドでの私の結果:
私の場合、各セクションで固定サイズヘッダーを使用していましたが、各ヘッダーで動的にセルサイズを使用していました。セルの高さは、ラベルの高さに依存します。
と協力する、〜と連携する:
tableView.estimatedRowHeight = SomeNumber
tableView.rowHeight = UITableViewAutomaticDimension
動作ただし使用時:
tableView.reloadSections(IndexSet(integer: sender.tag) , with: .automatic)
多くのヘッダーが折りたたまれていない場合、ヘッダーの複製(ヘッダータイプxが同じタイプの下にある)や、フレームワークがアニメーションでリロードすると、.none
(FYI、固定ヘッダーの高さとセルの高さが機能します)。
解決策は、heightForRowAt
コールバックを使用して、ラベルの高さを自分で計算することです(さらに、アニメーションはalotになります)。高さがfirstと呼ばれていることに注意してください。
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
{
let object = dataDetailsController.getRowObject(forIndexPath: indexPath)
let label = UILabel(frame: tableView.frame)
let font = UIFont(name: "HelveticaNeue-Bold", size: 25)
label.text = object?.name
label.font = font
label.numberOfLines = 0
label.textAlignment = .center
label.sizeToFit()
let size = label.frame.height
return Float(size) == 0 ? 34 : size
}