テキストプロパティの設定後にUITextViewスタイルがリセットされる


145

私が持っているUITextView *_masterTextとcallメソッドの後のsetTextプロパティのフォントがリセットされています。SDK 7を変更した後に発生します。_masterTextis IBOutlet、global、およびプロパティはストーリーボードで設定されます。それは私だけですか、これは一般的なSDKバグですか?

@interface myViewController : UIViewController
{
  IBOutlet UITextView *_masterText;
}

@implementation myViewController

-(void)viewWillAppear:(BOOL)animated
{
    [_masterText setText:@"New text"];
}

回答:


450

これで何時間も座って、バグを見つけました。プロパティ "Selectable" = NOの場合、setTextを使用するとフォントとフォントカラーがリセットされます。

したがって、選択可能をオンにすると、バグがなくなります。


15
:これは一時的にセット選択= YESのsetTextを呼び出す前にあるのXcode 5.私の回避策でも、私に何が起こる
Rollin_s

8
うわー、とんでもないバグだ。洞察をありがとう!
ミカ

3
本当にありがとう !
Magurizio 14年

6
6.4にはまだこの問題があります
RndmTsk 2015

4
これはiOS 10で修正されたようで、iOS 9以下をターゲットにしている場合は、回避策を実行する必要があります。
user1184205 2016年

11

私は同じ問題に遭遇し(Xcode 6.1で)、John Coganの答えは私にとってはうまくいきましたが、UITextViewクラスをカテゴリで拡張することが私の特定のプロジェクトのより良い解決策であることがわかりました。

インターフェース

@interface UITextView (XcodeSetTextFormattingBugWorkaround)
    - (void)setSafeText:(NSString *)textValue;
@end

実装

@implementation UITextView (XcodeSetTextFormattingBugWorkaround)
- (void)setSafeText:(NSString *)textValue
{
    BOOL selectable = [self isSelectable];
    [self setSelectable:YES];
    [self setText:textValue];
    [self setSelectable:selectable];
}
@end

1
そして迅速で:extension UITextView { func setSafeText(text: String){ let originalSelectable = selectable selectable = true self.text = text selectable = originalSelectable } }
少し

8

テキストビューを「読み取り専用」にしたい場合は、編集可能と選択可能をオンにし、ユーザーインタラクションをオフにすることができます。これにより、UITextViewが希望どおりに動作しました。

ここに画像の説明を入力してください

ここに画像の説明を入力してください


3
これは表面的には実行可能なソリューションのようですが、最終的にはUITextViewの良いオプションではありません。スクロール可能なテキスト領域が必要なため、通常はUITextViewを選択します。ユーザー操作を無効にすると、スクロールビューも無効になります。私がUITextViewを選択したのは、その領域に収まりきらないほど多くのテキストを保持し、スクロールできる領域があったためです。
jhelzer、2015年

6

この問題が自分自身と上記の回答で解決した場合、次のようにラッパーをViewControllerコードに追加し、変更するuiviewインスタンスとテキストを渡すだけで、ラッパー関数がSelectable値をオンに切り替え、テキストを変更してから再びオフにします。デフォルトで常にuitextviewをオフにする必要がある場合に役立ちます。

/*
    We set the text views Selectable value to YES temporarily, change text and turn it off again.
    This is a known bug that if the selectable value = NO the view loses its formatting.
 */
-(void)changeTextOfUiTextViewAndKeepFormatting:(UITextView*)viewToUpdate withText:(NSString*)textValue
{
    if(![viewToUpdate isSelectable]){
        [viewToUpdate setSelectable:YES];
        [viewToUpdate setText:textValue];
        [viewToUpdate setSelectable:NO];
    }else{
        [viewToUpdate setText:textValue];
        [viewToUpdate setSelectable:NO];
    }
}

1
UITextViewをサブクラス化し、setTextをオーバーライドして、アプリでサブクラスを使用する方が良いかもしれません
powerj1984

2

編集:

iOS 7のUITextViewのフォント設定は、最初にテキストを設定し、その後フォントを設定した場合に機能します。

@property (nonatomic, weak) IBOutlet UITextView *masterText;

@implementation myViewController

-(void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    _myTextView.text = @"My Text";

    _myTextView.font = [UIFont fontWithName:@"Helvetica.ttf" size:16]; // Set Font

}

XIBファイルで、UITextViewにテキストを追加し、フォントまたは色を変更すると、機能します。


うーん..私はプロパティを使用しますが、変更はありません。
Błażej

忘れました[super viewWillAppear:animated];
ジョーダンモンテル2013

私はそれについて忘れてしまったが、それは:(影響を与えなかった
Błażej

XIBファイルからフォントを変更しても、「_ myTextView.font ...」という行がなくても問題なく動作するため、XCodeをクリーンアップして再起動します
Jordan Montel

クリーン、再開、効果なし。Project> iOS Deployment Target 7.0、Base SDK 7.0は同じ設定をターゲットにします。
Błażej

2

これは、この問題でよく使用する簡単なサブクラスソリューションです。

class WorkaroundTextView: UITextView {
    override var text: String! {
        get {
            return super.text
        }
        set {
            let originalSelectableValue = self.selectable
            self.selectable = true
            super.text = newValue
            self.selectable = originalSelectableValue
        }
    }
}

2

この問題はXcode 8で再発見されました。これが私が修正した方法です。

拡張子を次のように変更しました:

extension UITextView{
    func setTextAvoidXcodeIssue(newText : String, selectable: Bool){
        isSelectable = true
        text = newText
        isSelectable = selectable
    }
}

そして、Interface BuilderのSelectableオプションをチェックしました。

その「選択可能」パラメーターを使用することはあまりエレガントではありませんが、それは可能です。


1

iOS 8.3では、「選択可能」をsetTextの前にYESに設定し、その後にNOに設定するという回避策では、問題を解決できませんでした。

これが機能する前に、ストーリーボードでも "selectable"をYESに設定する必要があることもわかりました。


あなたは私の日を救った、これはCocoaTouchのもう1つのとんでもないバグであると信じています
Chris


0

属性付きテキストを使用する場合、フォントを独自のフィールドに設定するのではなく、属性ディクショナリにフォントを設定するだけで済みました。


0

私はこの問題を抱えています。@Ken Steeleの回答の迅速な解決策。UITextViewを拡張し、計算されたプロパティを追加します。

extension UITextView {
    // For older Swift version output should be NSString!
    public var safeText:String!
        {
        set {
            let selectable = self.selectable;
            self.selectable = true;
            self.text = newValue;
            self.selectable = selectable;
        }
        get {
            return self.text;
        }
    }
}

それが役に立てば幸い。


0

それは3年になりますが、バグはXcodeの最新の安定バージョン(7.3)にまだ存在しています。明らかに、Appleはすぐには修正せず、開発者に2つのオプションを残します。選択可能にすることと、UserInteractionEnabledをfalseに設定すること、またはメソッドの入れ替えです。

textViewにボタンがある場合は、前者では不十分です。

迅速なコード変更不要のソリューション:

import UIKit

extension UITextView {
    @nonobjc var text: String! {
        get {
            return performSelector(Selector("text")).takeUnretainedValue() as? String ?? ""
        } set {
            let originalSelectableValue = selectable
            selectable = true
            performSelector(Selector("setText:"), withObject: newValue)
            selectable = originalSelectableValue
        }
    }
}

Objective-C:

#import <objc/runtime.h>
#import <UIKit/UIKit.h>

@implementation UITextView (SetTextFix)

+ (void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        Class class = [self class];

        SEL originalSelector = @selector(setText:);
        SEL swizzledSelector = @selector(xxx_setText:);

        Method originalMethod = class_getInstanceMethod(class, originalSelector);
        Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);

        BOOL didAddMethod =
        class_addMethod(class,
                    originalSelector,
                    method_getImplementation(swizzledMethod),
                    method_getTypeEncoding(swizzledMethod));

        if (didAddMethod) {
            class_replaceMethod(class,
                            swizzledSelector,
                            method_getImplementation(originalMethod),
                            method_getTypeEncoding(originalMethod));
        } else {
            method_exchangeImplementations(originalMethod, swizzledMethod);
       }
   });
}

- (void)xxx_setText:(NSString *)text {
    BOOL originalSelectableValue = self.selectable;
    self.selectable = YES;
    [self xxx_setText:text];
    self.selectable = originalSelectableValue;
}

@end

0

この問題で説明されている回避策を使用して、UITextViewに対するこの拡張setTextInCurrentStyle()機能は機能を提供します。Alessandro Ranaldiによるソリューションに基づいていますが、現在のisSelectable値を関数に渡す必要はありません。

extension UITextView{
    func setTextInCurrentStyle(_ newText: String) {
        let selectablePreviously = self.isSelectable
        isSelectable = true
        text = newText
        isSelectable = selectablePreviously
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.