web-dev-qa-db-fra.com

AutoLayout + RTL + UILabel alignement du texte

J'arrive enfin à la lutte avec la mise en page automatique et n'arrive pas à comprendre comment obtenir un soutien de droite à gauche (RTL) pour fonctionner de la manière que j'attendais/souhaitais ...

J'ai conçu la vue dans Interface Builder comme indiqué:

IB

L'application résultante fonctionnant normalement lorsque vous utilisez l'anglais:

English

Cependant, lors du passage à une langue RTL (l'arabe en l'occurrence), la vue entière bascule (ce qui est excellent), mais le texte de la variable UILabel est toujours aligné à gauche. Je m'attendrais à ce qu'il soit parfaitement aligné pour le maintenir contre la UIImageView.

Arabic

Clairement, il me manque quelque chose et/ou cela n'est pas couvert par la mise en page automatique.

Suis-je censé définir la textAlignment manuellement lors de l'utilisation d'un langage RTL?

22
Steve Wilford

Vous voulez NSTextAlignmentNatural. Cela implique l'alignement du texte à partir de la langue de l'application chargée ( pas à partir du script). 

Pour iOS 9 et versions ultérieures (à l'aide de Xcode 7), vous pouvez définir cela dans le scénario (choisissez l'option --- alignement). Si vous devez cibler des versions antérieures, vous devez créer un point de vente pour l'étiquette et définir l'alignement dans awakeFromNib.

- (void)awakeFromNib {
    [[self label] setTextAlignment:NSTextAlignmentNatural];
}
25
Ken

Pour moi, ces solutions ne m'ont pas aidé et j'ai fini par faire quelque chose d'assez laid, mais c'est la seule qui a fait l'affaire. Je l'ai ajouté dans la catégorie NSString:

NSString + Extras.h:

#import <Foundation/Foundation.h>

@interface NSString (Extras)
- (NSTextAlignment)naturalTextAligment;
@end

NSString + Extras.m:

#import "NSString+Extras.h"

@implementation NSString (Extras)

- (NSTextAlignment)naturalTextAligment {
    NSArray *tagschemes = [NSArray arrayWithObjects:NSLinguisticTagSchemeLanguage, nil];
    NSLinguisticTagger *tagger = [[NSLinguisticTagger alloc] initWithTagSchemes:tagschemes options:0];
    [tagger setString:self];
    NSString *language = [tagger tagAtIndex:0 scheme:NSLinguisticTagSchemeLanguage tokenRange:NULL sentenceRange:NULL];
    if ([language rangeOfString:@"he"].location != NSNotFound || [language rangeOfString:@"ar"].location != NSNotFound) {
        return NSTextAlignmentRight;
    } else {
        return NSTextAlignmentLeft;
    }
}
@end

Pour détecter la langue que j'ai utilisée cette SO réponse .

11
Aviel Gross

Suivi de la réponse de Ken

Définir textAlignment sur NSTextAlignmentNatural n'est pas possible sur UILabel, une exception sera levée:

Terminating app due to uncaught exception 'NSInvalidArgumentException',
reason: 'textAlignment does not accept NSTextAlignmentNatural'

Cela fonctionne lors de l’utilisation de texte attribué et ceci peut être défini dans Interface Builder comme indiqué:

attributed text natural alignment

Cependant, il semblerait que le texte attribué ne soit pas pris en compte lors de la localisation du storyboard.

Pour résoudre ce problème, j'ai laissé la UILabel configurée en clair dans Interface Builder et créé une NSAttributedString avec le texte de l'étiquette, définissez l'alignement sur la chaîne attribuée et l'affectez à la propriété attributedText:

-(void)viewDidLoad
{
    [super viewDidLoad];

    NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
    paragraphStyle.alignment = NSTextAlignmentNatural;

    NSMutableAttributedString *string = [[NSMutableAttributedString alloc] initWithString:self.lbl.text];
    [string addAttribute:NSParagraphStyleAttributeName
                   value:paragraphStyle
                   range:NSMakeRange(0, string.length)];

    self.lbl.attributedText = string;
}

Cela fonctionne bien dans ce cas simple, mais je peux le voir tomber lorsque vous avez besoin d'un style de chaîne attribué plus complexe. Mais évidemment, dans ce cas, vous utiliseriez probablement simplement NSLocalizedString ou des équivalents lors de la création de NSAttributedString.

4
Steve Wilford

@Aviel répond en tant que extension Swift UILabel  

//MARK: UILabel extension
extension UILabel {
    func decideTextDirection () {
        let tagScheme = [NSLinguisticTagSchemeLanguage]
        let tagger    = NSLinguisticTagger(tagSchemes: tagScheme, options: 0)
        tagger.string = self.text
        let lang      = tagger.tagAtIndex(0, scheme: NSLinguisticTagSchemeLanguage,
            tokenRange: nil, sentenceRange: nil)

        if lang?.rangeOfString("he") != nil ||  lang?.rangeOfString("ar") != nil {
            self.textAlignment = NSTextAlignment.Right
        } else {
            self.textAlignment = NSTextAlignment.Left
        }
    }
}

Comment l'utiliser ?

label.text = "كتابة باللغة العربية" // Assign text
label.decideTextDirection()          // Decide direction
4
Husam

Je pense que vous ne voulez pas utiliser l'alignement du texte dans ce cas, pour une étiquette. 

Vous pouvez simplement laisser la largeur être déterminée par intrinsicContentSize et supprimer toutes les contraintes de largeur sur l'étiquette. Vous obtiendrez l'effet souhaité du texte de l'étiquette aligné sur la vue.

Pour l'axe x, vous n'avez besoin que de cette contrainte entre label et imageview: [Imageview] - [label]

Ce n'est qu'une contrainte d'espacement horizontal. Pas de tête ni de fuite vers Superview.

4
DarthMike

vous pouvez utiliser MyLayout pour faciliter l’aide RTL et LRT.

1
欧阳大哥

@Aviel répond comme une extension Swift 4 UILabel

extension UILabel {
    func decideTextDirection () {
        let tagScheme = [NSLinguisticTagScheme.language]
        let tagger    = NSLinguisticTagger(tagSchemes: tagScheme, options: 0)
        tagger.string = self.text
        let lang      = tagger.tag(at: 0, scheme: NSLinguisticTagScheme.language,
                                          tokenRange: nil, sentenceRange: nil)

        if lang?.rawValue.range(of: "he") != nil ||  lang?.rawValue.range(of: "ar") != nil {
            self.textAlignment = NSTextAlignment.right
        } else {
            self.textAlignment = NSTextAlignment.left
        }
    }
}

usage

label.text = "كتابة باللغة العربية" // Assign text
label.decideTextDirection()          // Decide direction
0
Hamid Shahsavari

Cette fonction m'a aidé 

-(void)fnForWritingDirection:(UILabel*)label textFor:(NSString *)stringForText{

    NSMutableAttributedString* attrStr = [[NSMutableAttributedString alloc] initWithString: [stringForText stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];

    NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];

    [paragraphStyle setBaseWritingDirection:NSWritingDirectionRightToLeft];

    [attrStr addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange(0, [attrStr length])];

    label.attributedText=attrStr;

}
0
Sukeshj