web-dev-qa-db-ja.com

AutoLayout + RTL + UILabelテキストの配置

私はようやく自動レイアウトと格闘し始めており、右から左へ(RTL)をサポートする方法を期待どおりに機能させる方法を理解できないようです...

以下のようにInterface Builderでビューを設計しました。

IB

英語を使用すると、結果として得られるアプリが期待どおりに実行されます。

English

ただし、RTL言語(この場合はアラビア語)に切り替えると、ビュー全体が反転します(これは素晴らしい)が、UILabelのテキストは左揃えのままです。 UIImageViewに対応するために、正しく調整されると思います。

Arabic

明らかに何かが足りない、および/またはこれは自動レイアウトの対象外です。

RTL言語を使用する場合、textAlignmentを手動で設定する必要がありますか?

26
Steve Wilford

NSTextAlignmentNaturalが必要です。これは、読み込まれたアプリケーション言語からテキストの配置を推測します(スクリプトからnot)。

IOS 9以降(Xcode 7を使用)では、ストーリーボードでこれを設定できます(---配置オプションを選択)。以前のリリースをターゲットにする必要がある場合は、ラベルへのアウトレットを作成し、awakeFromNibに配置を設定する必要があります。

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

私にとってこれらの解決策は役に立たず、結局醜いことをすることになりましたが、それが私にとってトリックを作った唯一のものです。 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

私が使用した言語を検出するために this SO answer

11
Aviel Gross

ケンの答えからフォローアップ

textAlignmentNSTextAlignmentNaturalに設定することは、UILabelでは不可能であり、例外がスローされます。

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

属性付きテキストを使用する場合、これは機能します。これは、次のようにInterface Builderで設定できます。

attributed text natural alignment

ただし、ストーリーボードをローカライズすると、属性付きテキストが取得されないように見えます。

これを回避するには、UILabelをInterface Builderでプレーンとして構成したままにし、ラベルのテキストでNSAttributedStringを作成し、属性付き文字列に配置を設定して、ラベルの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;
}

これはこの単純なケースでは問題なく機能しますが、より複雑な属性付き文字列スタイリングが必要な場合は、うまく機能します。しかし、明らかにその場合、NSLocalizedStringを作成するときに、おそらくNSAttributedStringまたは同等のものを使用するだけでしょう。

4
Steve Wilford

@Avielの回答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
        }
    }
}

使い方は?

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

この場合、ラベルにテキストの配置を使用したくないと思います。

あなただけの幅がintrinsicContentSizeによって決定されるようにして、ラベルの幅の制約を取り除くことができます。ビューに位置合わせされたラベルテキストの望ましい効果が得られます。

X軸の場合、ラベルとイメージビューの間にのみこの制約が必要です:[imageview]-[label]

これは、水平方向の間隔の制約にすぎません。スーパービューの先頭または末尾はありません。

4
DarthMike

MyLinearLayout を使用すると、RTLおよびLRTを簡単にサポートできます。

0
欧阳大哥

Swift 4 UILabel拡張としての@Avielの回答

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
        }
    }
}

使用法

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

これが私のバージョンです。よりシンプルで、ソースドキュメント内の複数の言語も処理します。

主なポイントは、dominantLanguageを使用することです。

let lang = tagger.dominantLanguage

コードスニペット:

 extension UILabel {
    func determineTextDirection () {
        guard self.text != nil else {return}

        let tagger = NSLinguisticTagger(tagSchemes: [.language], options: 0)
        tagger.string = self.text

        let lang = tagger.dominantLanguage

        let rtl = lang == "he" || lang == "ar"

        self.textAlignment = rtl ? .right : .left
    }
}

使用法:

titleLabel.text = "UILabel היפוך שפה עבור"
titleLabel.determineTextDirection()

最後に:アプリがローカライズされていて、電話の言語に依存している場合があることに注意してください-解決策は、「RTLのナチュラルテキスト配置」です。

titleLabel.textAlignment = .natural

enter image description here

アプリが異なる言語で複数の行を表示する場合は、NSLinguisticTaggerを使用します。または、ローカルに関係なく、任意の言語での無料検索を許可する場合。

0
TomerBu

この機能は私を助けました

-(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