我在我的nib文件中添加了一个标签,然后需要对该标签进行左上角对齐。因为我在运行时提供文本所以它不确定有多少行。 因此,如果文本仅包含单行,则它显示为垂直居中对齐。这种对齐方式与我前面的标签不符。
例如:
看起来很奇怪:(
有什么方法可以将标签文本设置为左上角对齐吗?
答案 0 :(得分:64)
这很容易做到。使用UILabel
属性创建verticalAlignment
sublcass并覆盖textRectForBounds:limitedToNumberOfLines
以返回顶部,中间或底部垂直对齐的正确边界。这是代码:
<强> SOLabel.h 强>
#import <UIKit/UIKit.h>
typedef enum
{
VerticalAlignmentTop = 0, // default
VerticalAlignmentMiddle,
VerticalAlignmentBottom,
} VerticalAlignment;
@interface SOLabel : UILabel
@property (nonatomic, readwrite) VerticalAlignment verticalAlignment;
@end
<强> SOLabel.m 强>
@implementation SOLabel
-(id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (!self) return nil;
// set inital value via IVAR so the setter isn't called
_verticalAlignment = VerticalAlignmentTop;
return self;
}
-(VerticalAlignment) verticalAlignment
{
return _verticalAlignment;
}
-(void) setVerticalAlignment:(VerticalAlignment)value
{
_verticalAlignment = value;
[self setNeedsDisplay];
}
// align text block according to vertical alignment settings
-(CGRect)textRectForBounds:(CGRect)bounds
limitedToNumberOfLines:(NSInteger)numberOfLines
{
CGRect rect = [super textRectForBounds:bounds
limitedToNumberOfLines:numberOfLines];
CGRect result;
switch (_verticalAlignment)
{
case VerticalAlignmentTop:
result = CGRectMake(bounds.origin.x, bounds.origin.y,
rect.size.width, rect.size.height);
break;
case VerticalAlignmentMiddle:
result = CGRectMake(bounds.origin.x,
bounds.origin.y + (bounds.size.height - rect.size.height) / 2,
rect.size.width, rect.size.height);
break;
case VerticalAlignmentBottom:
result = CGRectMake(bounds.origin.x,
bounds.origin.y + (bounds.size.height - rect.size.height),
rect.size.width, rect.size.height);
break;
default:
result = bounds;
break;
}
return result;
}
-(void)drawTextInRect:(CGRect)rect
{
CGRect r = [self textRectForBounds:rect
limitedToNumberOfLines:self.numberOfLines];
[super drawTextInRect:r];
}
@end
答案 1 :(得分:59)
不是重新解释,我将链接到相当广泛的&amp;评价很高的问题/答案:
Vertically align text to top within a UILabel
简短的回答是否定的,Apple并没有这么简单,但可以通过改变框架大小来实现。
答案 2 :(得分:37)
SOLabel为我工作。
class UIVerticalAlignLabel: UILabel {
enum VerticalAlignment : Int {
case VerticalAlignmentTop = 0
case VerticalAlignmentMiddle = 1
case VerticalAlignmentBottom = 2
}
var verticalAlignment : VerticalAlignment = .VerticalAlignmentTop {
didSet {
setNeedsDisplay()
}
}
required init(coder aDecoder: NSCoder){
super.init(coder: aDecoder)
}
override func textRectForBounds(bounds: CGRect, limitedToNumberOfLines: Int) -> CGRect {
let rect = super.textRectForBounds(bounds, limitedToNumberOfLines: limitedToNumberOfLines)
switch(verticalAlignment) {
case .VerticalAlignmentTop:
return CGRectMake(bounds.origin.x, bounds.origin.y, rect.size.width, rect.size.height)
case .VerticalAlignmentMiddle:
return CGRectMake(bounds.origin.x, bounds.origin.y + (bounds.size.height - rect.size.height) / 2, rect.size.width, rect.size.height)
case .VerticalAlignmentBottom:
return CGRectMake(bounds.origin.x, bounds.origin.y + (bounds.size.height - rect.size.height), rect.size.width, rect.size.height)
default:
return bounds
}
}
override func drawTextInRect(rect: CGRect) {
let r = self.textRectForBounds(rect, limitedToNumberOfLines: self.numberOfLines)
super.drawTextInRect(r)
}
}
此版本已从原版更新,以支持RTL语言:
public class VerticalAlignLabel: UILabel {
enum VerticalAlignment {
case top
case middle
case bottom
}
var verticalAlignment : VerticalAlignment = .top {
didSet {
setNeedsDisplay()
}
}
override public func textRect(forBounds bounds: CGRect, limitedToNumberOfLines: Int) -> CGRect {
let rect = super.textRect(forBounds: bounds, limitedToNumberOfLines: limitedToNumberOfLines)
if UIView.userInterfaceLayoutDirection(for: .unspecified) == .rightToLeft {
switch verticalAlignment {
case .top:
return CGRect(x: self.bounds.size.width - rect.size.width, y: bounds.origin.y, width: rect.size.width, height: rect.size.height)
case .middle:
return CGRect(x: self.bounds.size.width - rect.size.width, y: bounds.origin.y + (bounds.size.height - rect.size.height) / 2, width: rect.size.width, height: rect.size.height)
case .bottom:
return CGRect(x: self.bounds.size.width - rect.size.width, y: bounds.origin.y + (bounds.size.height - rect.size.height), width: rect.size.width, height: rect.size.height)
}
} else {
switch verticalAlignment {
case .top:
return CGRect(x: bounds.origin.x, y: bounds.origin.y, width: rect.size.width, height: rect.size.height)
case .middle:
return CGRect(x: bounds.origin.x, y: bounds.origin.y + (bounds.size.height - rect.size.height) / 2, width: rect.size.width, height: rect.size.height)
case .bottom:
return CGRect(x: bounds.origin.x, y: bounds.origin.y + (bounds.size.height - rect.size.height), width: rect.size.width, height: rect.size.height)
}
}
}
override public func drawText(in rect: CGRect) {
let r = self.textRect(forBounds: rect, limitedToNumberOfLines: self.numberOfLines)
super.drawText(in: r)
}
}
答案 3 :(得分:36)
我在StoryBoard中找到了使用AutoLayout的解决方案。
1)将行号设置为0,将文本对齐设置为左。
2)设置高度约束。
3)高度约束应该是关系 - 小于或等于
4)
select a.id_a,
a.textdata,
listagg(c.textdata, ', ') within group (order by c.id_c) data_c
from table_a a
inner join table_b b on (a.id_a = b.id_a)
inner join table_c c on (b.id_c = c.id_c)
where listagg(c.textdata, ', ') like :data
group by a.id_a, a.textdata;
我得到的结果如下:
答案 4 :(得分:12)
在您的代码中
label.text = @"some text";
[label sizeToFit];
请注意,如果您在表格单元格或其他使用不同数据回收的视图中使用它,则需要将原始帧存储在某处并在调用sizeToFit之前重置它。
答案 5 :(得分:7)
我找到了针对同一问题的另一种解决方案。我使用UITextView
代替UILabel
并将editable()
函数切换为false
。
答案 6 :(得分:6)
我也遇到了这个问题,但我发现你设置UILabel属性和方法的顺序很重要!
如果您在[label sizeToFit]
之前拨打label.font = [UIFont fontWithName:@"Helvetica" size:14];
,那么该文字就不会与顶部对齐,但如果您将它们交换,那么它就会出现!
我还注意到,首先设置文本也会产生影响。
希望这有帮助。
答案 7 :(得分:4)
在使用界面构建器时,请设置标签的约束(确保也设置高度和宽度)。然后在“大小”检查器中,检查标签的高度。在那里你会希望它读取&gt; =而不是=。然后在该视图控制器的实现中,将行数设置为0(也可以在IB中完成)并设置标签[label sizeToFit];当您的文字获得长度时,标签将在高度上增长,并将文字保持在左上角。
答案 8 :(得分:3)
SoLabel的解决方案有效,谢谢。
Bellow我添加了monotouch版本:
public class UICustomLabel : UILabel
{
private UITextVerticalAlignment _textVerticalAlignment;
public UICustomLabel()
{
TextVerticalAlignment = UITextVerticalAlignment.Top;
}
public UITextVerticalAlignment TextVerticalAlignment
{
get
{
return _textVerticalAlignment;
}
set
{
_textVerticalAlignment = value;
SetNeedsDisplay();
}
}
public override void DrawText(RectangleF rect)
{
var bound = TextRectForBounds(rect, Lines);
base.DrawText(bound);
}
public override RectangleF TextRectForBounds(RectangleF bounds, int numberOfLines)
{
var rect = base.TextRectForBounds(bounds, numberOfLines);
RectangleF resultRect;
switch (TextVerticalAlignment)
{
case UITextVerticalAlignment.Top:
resultRect = new RectangleF(bounds.X, bounds.Y, rect.Size.Width, rect.Size.Height);
break;
case UITextVerticalAlignment.Middle:
resultRect = new RectangleF(bounds.X,
bounds.Y + (bounds.Size.Height - rect.Size.Height)/2,
rect.Size.Width, rect.Size.Height);
break;
case UITextVerticalAlignment.Bottom:
resultRect = new RectangleF(bounds.X,
bounds.Y + (bounds.Size.Height - rect.Size.Height),
rect.Size.Width, rect.Size.Height);
break;
default:
resultRect = bounds;
break;
}
return resultRect;
}
}
public enum UITextVerticalAlignment
{
Top = 0, // default
Middle,
Bottom
}
答案 9 :(得分:3)
就我而言,这是bottom space
约束问题。我已将其设置为= 16
。
当我将其设置为bottom to >= 16
时,此问题已解决。
此外,如果标签中有任何高度限制,则需要将其删除。
这是尺寸检查器中我标签的约束视图:
答案 10 :(得分:2)
在totiG的精彩答案的基础上,我创建了一个IBDesignable类,可以非常轻松地从StoryBoard自定义UILabel的垂直对齐。只需确保从StoryBoard身份检查器将UILabel的类设置为“VerticalAlignLabel”。如果垂直对齐没有生效,请转到编辑器 - >刷新所有视图,这应该可以解决问题。
工作原理: 一旦正确设置了UILabel类,故事板就会显示一个带整数的输入字段(对齐代码)。
更新:我添加了对居中标签 ~Sev
的支持输入0作为顶部对齐
为中间对齐输入1
输入2作为底部对齐
@IBDesignable class VerticalAlignLabel: UILabel {
@IBInspectable var alignmentCode: Int = 0 {
didSet {
applyAlignmentCode()
}
}
func applyAlignmentCode() {
switch alignmentCode {
case 0:
verticalAlignment = .top
case 1:
verticalAlignment = .topcenter
case 2:
verticalAlignment = .middle
case 3:
verticalAlignment = .bottom
default:
break
}
}
override func awakeFromNib() {
super.awakeFromNib()
self.applyAlignmentCode()
}
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
self.applyAlignmentCode()
}
enum VerticalAlignment {
case top
case topcenter
case middle
case bottom
}
var verticalAlignment : VerticalAlignment = .top {
didSet {
setNeedsDisplay()
}
}
override public func textRect(forBounds bounds: CGRect, limitedToNumberOfLines: Int) -> CGRect {
let rect = super.textRect(forBounds: bounds, limitedToNumberOfLines: limitedToNumberOfLines)
if #available(iOS 9.0, *) {
if UIView.userInterfaceLayoutDirection(for: .unspecified) == .rightToLeft {
switch verticalAlignment {
case .top:
return CGRect(x: self.bounds.size.width - rect.size.width, y: bounds.origin.y, width: rect.size.width, height: rect.size.height)
case .topcenter:
return CGRect(x: self.bounds.size.width - (rect.size.width / 2), y: bounds.origin.y, width: rect.size.width, height: rect.size.height)
case .middle:
return CGRect(x: self.bounds.size.width - rect.size.width, y: bounds.origin.y + (bounds.size.height - rect.size.height) / 2, width: rect.size.width, height: rect.size.height)
case .bottom:
return CGRect(x: self.bounds.size.width - rect.size.width, y: bounds.origin.y + (bounds.size.height - rect.size.height), width: rect.size.width, height: rect.size.height)
}
} else {
switch verticalAlignment {
case .top:
return CGRect(x: bounds.origin.x, y: bounds.origin.y, width: rect.size.width, height: rect.size.height)
case .topcenter:
return CGRect(x: (self.bounds.size.width / 2 ) - (rect.size.width / 2), y: bounds.origin.y, width: rect.size.width, height: rect.size.height)
case .middle:
return CGRect(x: bounds.origin.x, y: bounds.origin.y + (bounds.size.height - rect.size.height) / 2, width: rect.size.width, height: rect.size.height)
case .bottom:
return CGRect(x: bounds.origin.x, y: bounds.origin.y + (bounds.size.height - rect.size.height), width: rect.size.width, height: rect.size.height)
}
}
} else {
// Fallback on earlier versions
return rect
}
}
override public func drawText(in rect: CGRect) {
let r = self.textRect(forBounds: rect, limitedToNumberOfLines: self.numberOfLines)
super.drawText(in: r)
}
}
答案 11 :(得分:2)
最简单,最简单的方法是在StackView中嵌入Label,并在Storyboard like shown here中将StackView的Axis设置为Horizontal,Alignment to Top in Attribute Inspector。
答案 12 :(得分:2)
如果您需要的是不可编辑的文本,默认情况下从左上角开始,您只需使用文本视图而不是标签,然后将其状态设置为不可编辑,如下所示:
textview.isEditable = false
比弄乱标签更容易......
干杯!
答案 13 :(得分:1)
您也可以只将UILabel更改为UITextView,因为它们基本上可以做相同的事情,除了UITextView的优点是文本自动对齐到左上角
答案 14 :(得分:1)
使用 UITextView 而不是 UILabel。它也适用于 UITableViewCell 宽度自动行高
将 isScrollEnabled 和 isEditable 设置为 false。为 TextView 添加最小高度约束
final class TestVC: UIViewController {
lazy var testTextLabel: UITextView = {
$0.isScrollEnabled = false
$0.isEditable = false
$0.font = .systemFont(ofSize: 17, weight: .medium)
$0.textColor = .black
$0.layer.borderWidth = 1
$0.layer.borderColor = UIColor.black.cgColor
$0.layer.cornerRadius = 5
return $0
}(UITextView())
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
testTextLabel.text = "Your text"
view.addSubview(testTextLabel)
testTextLabel.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
testTextLabel.topAnchor.constraint(equalTo: testTextLabel.superview!.safeAreaLayoutGuide.topAnchor, constant: 12),
testTextLabel.leadingAnchor.constraint(equalTo: testTextLabel.superview!.leadingAnchor, constant: 12),
testTextLabel.widthAnchor.constraint(equalToConstant: 250),
testTextLabel.heightAnchor.constraint(greaterThanOrEqualToConstant: 70)
])
}
}
答案 15 :(得分:0)
快捷键5
很简单,属性的顺序就是一切。
titleLabel.frame = CGRect(x: 20, y: 20, width: 374, height: 291.2)
titleLabel.backgroundColor = UIColor.clear //set a light color to see the frame
titleLabel.textAlignment = .left
titleLabel.lineBreakMode = .byTruncatingTail
titleLabel.numberOfLines = 4
titleLabel.font = UIFont(name: "HelveticaNeue-Bold", size: 35)
titleLabel.text = "Example"
titleLabel.sizeToFit()
self.view.addSubview(titleLabel)
答案 16 :(得分:0)
@totiG的答案是正确的,并解决了我的问题。但是我在实施这种方法时发现了一个问题,在较小的设备(如5s,SE)中,这对我不起作用。我必须在label.sizeToFit()
override func layoutSubViews()
override func layoutSubViews() {
super.layoutSubViews()
// Do other works if needed
label.sizeToFit()
}
答案 17 :(得分:0)
使用 textRect(forBounds:limitedToNumberOfLines:)
class TopAlignedLabel: UILabel {
override func drawText(in rect: CGRect) {
let textRect = super.textRect(forBounds: bounds, limitedToNumberOfLines: numberOfLines)
super.drawText(in: textRect)
}
}
答案 18 :(得分:0)
我遇到了这个问题,但是我的标签位于UITableViewCell中,并且解决该问题的最简单方法是创建一个空的UIView,并在其中将标签设置为仅在顶部和左侧具有约束,启用关闭诅咒将行数设置为0
答案 19 :(得分:0)
@ totiG的答案的Swift 3版本
class UIVerticalAlignLabel: UILabel {
enum VerticalAlignment : Int {
case VerticalAlignmentTop = 0
case VerticalAlignmentMiddle = 1
case VerticalAlignmentBottom = 2
}
@IBInspectable var verticalAlignment : VerticalAlignment = .VerticalAlignmentTop {
didSet {
setNeedsDisplay()
}
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func textRect(forBounds bounds: CGRect, limitedToNumberOfLines: Int) -> CGRect {
let rect = super.textRect(forBounds: bounds, limitedToNumberOfLines: limitedToNumberOfLines)
switch(verticalAlignment) {
case .VerticalAlignmentTop:
return CGRect(x: bounds.origin.x, y: bounds.origin.y, width: rect.size.width, height: rect.size.height)
case .VerticalAlignmentMiddle:
return CGRect(x: bounds.origin.x, y: bounds.origin.y + (bounds.size.height - rect.size.height) / 2, width: rect.size.width, height: rect.size.height)
case .VerticalAlignmentBottom:
return CGRect(x: bounds.origin.x, y: bounds.origin.y + (bounds.size.height - rect.size.height), width: rect.size.width, height: rect.size.height)
}
}
override func drawText(in rect: CGRect) {
let r = self.textRect(forBounds: rect, limitedToNumberOfLines: self.numberOfLines)
super.drawText(in: r)
}
}
答案 20 :(得分:0)
Swift 2.0::使用UILabel扩展程序
在空的Swift文件中创建常量枚举值。
// AppRef.swift
import UIKit
import Foundation
enum UILabelTextPositions : String {
case VERTICAL_ALIGNMENT_TOP = "VerticalAlignmentTop"
case VERTICAL_ALIGNMENT_MIDDLE = "VerticalAlignmentMiddle"
case VERTICAL_ALIGNMENT_BOTTOM = "VerticalAlignmentBottom"
}
使用UILabel扩展:
创建一个空的Swift类并命名它。添加以下内容。
// AppExtensions.swift
import Foundation
import UIKit
extension UILabel{
func makeLabelTextPosition (sampleLabel :UILabel?, positionIdentifier : String) -> UILabel
{
let rect = sampleLabel!.textRectForBounds(bounds, limitedToNumberOfLines: 0)
switch positionIdentifier
{
case "VerticalAlignmentTop":
sampleLabel!.frame = CGRectMake(bounds.origin.x+5, bounds.origin.y, rect.size.width, rect.size.height)
break;
case "VerticalAlignmentMiddle":
sampleLabel!.frame = CGRectMake(bounds.origin.x+5,bounds.origin.y + (bounds.size.height - rect.size.height) / 2,
rect.size.width, rect.size.height);
break;
case "VerticalAlignmentBottom":
sampleLabel!.frame = CGRectMake(bounds.origin.x+5, bounds.origin.y + (bounds.size.height - rect.size.height),rect.size.width, rect.size.height);
break;
default:
sampleLabel!.frame = bounds;
break;
}
return sampleLabel!
}
}
用法:
myMessageLabel.makeLabelTextPosition(messageLabel, positionIdentifier: UILabelTextPositions.VERTICAL_ALIGNMENT_TOP.rawValue)
答案 21 :(得分:0)
对于iOS 7,这就是我为我制作和工作的
@implementation UILabel (VerticalAlign)
- (void)alignTop
{
CGSize boundingRectSize = CGSizeMake(self.frame.size.width, CGFLOAT_MAX);
NSDictionary *attributes = @{NSFontAttributeName : self.font};
CGRect labelSize = [self.text boundingRectWithSize:boundingRectSize options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading
attributes:attributes
context:nil];
int numberOfLines= ceil(labelSize.size.height / self.font.lineHeight);
CGRect newFrame = self.frame;
newFrame.size.height = numberOfLines * self.font.lineHeight;
self.frame = newFrame;
}
- (void)alignBottom
{
CGSize boundingRectSize = CGSizeMake(self.frame.size.width, CGFLOAT_MAX);
NSDictionary *attributes = @{NSFontAttributeName : self.font};
CGRect labelSize = [self.text boundingRectWithSize:boundingRectSize options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading
attributes:attributes
context:nil];
int numberOfLines= ceil(labelSize.size.height / self.font.lineHeight);
int numberOfNewLined = (self.frame.size.height/self.font.lineHeight) - numberOfLines;
NSMutableString *newLines = [NSMutableString string];
for(int i=0; i< numberOfNewLined; i++){
[newLines appendString:@"\n"];
}
[newLines appendString:self.text];
self.text = [newLines mutableCopy];
}
答案 22 :(得分:-1)