J'ai ajouté une étiquette dans mon fichier nib, puis il est nécessaire d'avoir un alignement en haut à gauche pour cette étiquette. Comme je fournis du texte au moment de l’exécution, il n’est donc pas sûr de savoir combien il y a de lignes . Donc, si le texte ne contient qu’une seule ligne, il apparaît alors comme aligné verticalement au centre. Cet alignement ne correspond pas à mon label respectif devant lui.
Par exemple:
Qui cherche étrange :(
Y at-il un moyen où je peux définir le texte de l'étiquette propre à l'alignement en haut à gauche?
Plutôt que d’expliquer à nouveau, je vais vous renvoyer à cette question/réponse plutôt détaillée et hautement cotée:
Aligner verticalement le texte en haut dans un UILabel
La réponse courte est non, Apple n'a pas rendu cela facile, mais c'est possible en modifiant la taille du cadre.
C'est assez facile à faire. Créez une sous-classe UILabel
avec une propriété verticalAlignment
et remplacez textRectForBounds:limitedToNumberOfLines
pour renvoyer les limites correctes d'un alignement vertical supérieur, central ou inférieur. Voici le code:
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
La SOLabel travaille pour moi.
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)
}
}
Cette version a été mise à jour depuis l'original pour permettre la prise en charge des langues 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)
}
}
J'ai trouvé une solution utilisant AutoLayout dans StoryBoard.
1) Définissez le nombre de lignes sur 0 et l’alignement du texte sur Gauche.
2) Définir la contrainte de hauteur.
3) La contrainte de hauteur doit être en relation - inférieure ou égale
4)
override func viewWillLayoutSubviews() {
sampleLabel.sizeToFit()
}
J'ai eu le résultat comme suit:
Dans votre code
label.text = @"some text";
[label sizeToFit];
Attention, si vous utilisez cela dans des cellules de tableau ou d'autres vues recyclées avec des données différentes, vous devez stocker le cadre d'origine quelque part et le réinitialiser avant d'appeler sizeToFit.
Je rencontrais également ce problème, mais ce que j’ai trouvé, c’est l’ordre dans lequel vous définissez les propriétés et les méthodes d’UILabel qui compte!
Si vous appelez [label sizeToFit]
avant label.font = [UIFont fontWithName:@"Helvetica" size:14];
, le texte ne sera pas aligné en haut, mais si vous le permutez, il le fera!
J'ai également remarqué que le réglage du texte en premier fait également une différence.
J'espère que cela t'aides.
J'ai trouvé une autre solution pour le même problème. J'ai utilisé UITextView
au lieu de UILabel
et ai changé la fonction editable()
en false
.
Lorsque vous utilisez le générateur d'interface, définissez les contraintes pour votre étiquette (veillez également à définir la hauteur et la largeur). Ensuite, dans l'inspecteur de taille, vérifiez la hauteur de l'étiquette. Là, vous voudrez qu'il lise> = au lieu de =. Ensuite, dans l'implémentation de ce contrôleur de vue, définissez le nombre de lignes sur 0 (vous pouvez également le faire dans IB) et définissez le libellé [label sizeToFit]; et à mesure que votre texte gagne en longueur, l'étiquette grandira en hauteur et conservera votre texte en haut à gauche.
La solution avec SoLabel fonctionne, merci.
J'ai ajouté la version monotouch ci-dessous:
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
}
En me basant sur la réponse impressionnante de totiG, j'ai créé une classe IBDesignable qui permet de personnaliser très facilement l'alignement vertical d'un UILabel à partir du StoryBoard. Assurez-vous simplement que vous avez défini la classe de votre UILabel sur 'VerticalAlignLabel' à partir de l'inspecteur d'identité StoryBoard. Si l'alignement vertical ne prend pas effet, accédez à Editeur -> Actualiser toutes les vues, ce qui devrait suffire.
Comment ça marche: Une fois que vous avez défini la classe de votre UILabel correctement, le storyboard devrait vous montrer un champ de saisie prenant un entier (code d'alignement).
Mise à jour: j'ai ajouté le support pour les étiquettes centrées ~ Sev
Entrez 0 pour l'alignement supérieur
Entrez 1 pour l'alignement moyen
Entrez 2 pour l'alignement du bas
@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)
}
}
Si ce dont vous avez besoin est un texte non modifiable qui commence par défaut dans le coin supérieur gauche, vous pouvez simplement utiliser une vue texte au lieu d'une étiquette, puis définir son état sur non modifiable, comme ceci:
textview.isEditable = false
Bien plus facile que de jouer avec les étiquettes ...
À votre santé!
Le moyen le plus simple et le plus simple consiste à incorporer Label dans StackView et à définir Axis de StackView sur Horizontal, Alignement sur le haut dans l'Inspecteur des attributs de Storyboard comme illustré ici .
Dans mon cas, c’était un problème de contrainte bottom space
. Je l'avais mis à = 16
.
Lorsque je l'ai défini sur bottom to >= 16
, le problème a été résolu.
De plus, si l'étiquette contient une contrainte de hauteur, vous devez la supprimer.
Voici la vue des contraintes de mon étiquette dans l'inspecteur de taille:
Swift 3 version de la réponse de @ totiG
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)
}
}
Swift 2.0: : Utilisation de l'extension UILabel
Définissez des valeurs d'énumération constantes dans un fichier Swift vide.
// AppRef.Swift
import UIKit
import Foundation
enum UILabelTextPositions : String {
case VERTICAL_ALIGNMENT_TOP = "VerticalAlignmentTop"
case VERTICAL_ALIGNMENT_MIDDLE = "VerticalAlignmentMiddle"
case VERTICAL_ALIGNMENT_BOTTOM = "VerticalAlignmentBottom"
}
Utiliser l'extension UILabel:
Créez une classe Swift vide et nommez-la. Ajoutez ce qui suit.
// 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!
}
}
Utilisation:
myMessageLabel.makeLabelTextPosition(messageLabel, positionIdentifier: UILabelTextPositions.VERTICAL_ALIGNMENT_TOP.rawValue)
Pour iOS 7 c'est ce que j'ai fait et travaillé pour moi
@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];
}
vous pouvez aussi simplement changer votre UILabel en UITextView, car ils font essentiellement la même chose, à la différence que l'avantage de UITextView est que le texte est automatiquement aligné en haut à gauche.