Styl UITextView jest resetowany po ustawieniu właściwości text

145

Mam UITextView *_masterTexti po wywołaniu metody setTextjest resetowana czcionka właściwości. Dzieje się to po zmianie sdk 7. _masterText jest IBOutletglobalne, a właściwości są ustawione w scenorysie. To tylko ja czy to ogólny błąd SDK?

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

@implementation myViewController

-(void)viewWillAppear:(BOOL)animated
{
    [_masterText setText:@"New text"];
}
Błażej
źródło

Odpowiedzi:

450

Siedząc z tym godzinami, znalazłem błąd. Jeśli właściwość „Selectable” = NO, zresetuje czcionkę i kolor czcionki, gdy zostanie użyta funkcja setText.

Więc włącz opcję Selectable, a błąd zniknie.

Bosse Nilsson
źródło
15
Dzieje się tak również w Xcode 5. Moje obejście polega na tymczasowym ustawieniu
selectable
8
Wow, co za śmieszny błąd. Dzięki za wgląd!
Micah
3
Dziękuje bardzo !
Magurizio,
6
6.4 nadal ma ten problem
RndmTsk
4
Wydaje się, że problem został rozwiązany w systemie iOS 10, jeśli nadal kierujesz reklamy na system iOS 9 lub starszy, musisz obejść ten problem.
user1184205
11

Natknąłem się na ten sam problem (na Xcode 6.1) i podczas odpowiedzi Johna Cogana zadziałała dla mnie, stwierdziłem, że rozszerzenie klasy UITextView o kategorię było lepszym rozwiązaniem dla mojego konkretnego projektu.

berło

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

realizacja

@implementation UITextView (XcodeSetTextFormattingBugWorkaround)
- (void)setSafeText:(NSString *)textValue
{
    BOOL selectable = [self isSelectable];
    [self setSelectable:YES];
    [self setText:textValue];
    [self setSelectable:selectable];
}
@end
Ken Steele
źródło
1
I szybko:extension UITextView { func setSafeText(text: String){ let originalSelectable = selectable selectable = true self.text = text selectable = originalSelectable } }
mały
8

Jeśli chcesz, aby Twój widok tekstu był „tylko do odczytu”, możesz zaznaczyć Edytowalne i Wybieralne oraz odznaczyć opcję Interakcja z użytkownikiem Włączona, z tym UITextView zachowywał się tak, jak chciałem

wprowadź opis obrazu tutaj

wprowadź opis obrazu tutaj

Chuy47
źródło
3
Wydaje się, że jest to realne rozwiązanie, ale ostatecznie nie jest dobrą opcją dla UITextView. Zwykle wybierasz UITextView, ponieważ potrzebujesz przewijalnego obszaru tekstowego. wyłączenie interakcji użytkownika wyłącza również widok przewijania. Dla mnie wybór użycia UITextView był spowodowany tym, że miałem obszar, który musiał pomieścić więcej tekstu, niż mogłoby się zmieścić w tym obszarze i móc przewijać.
jhelzer
6

Gdyby ten problem i powyższa odpowiedź pomogły, ale dodałem otokę do mojego kodu ViewController w następujący sposób i po prostu przekazałem wystąpienie uiview i tekst do zmiany, a funkcja opakowania włącza wartość Selectable, zmienia tekst, a następnie wyłącza ją ponownie. Przydatne, gdy chcesz, aby uitextview był domyślnie wyłączony przez cały czas.

/*
    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];
    }
}
John Cogan
źródło
1
Może lepiej będzie podklasować UITextView i przesłonić setText i użyć swojej podklasy w aplikacji
powerj1984
2

EDYTOWAĆ :

Ustawienie czcionki dla UITextView w iOS 7 działa dla mnie, jeśli najpierw ustawisz tekst, a następnie ustawisz czcionkę:

@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

}

W pliku XIB, jeśli dodasz tekst w swoim UITextView i zmienisz czcionkę lub kolor, to zadziała.

Jordan Montel
źródło
hmm .. Używam nieruchomości, ale bez zmian.
Błażej
zapomniałem [super viewWillAppear: animated];
Jordan Montel,
Zapomniałem o tym, ale to nie miało wpływu :(
Błażej
wyczyść i zrestartuj XCode, ponieważ dla mnie działa dobrze bez wiersza "_myTextView.font ...", nawet jeśli zmienię czcionkę z pliku XIB
Jordan Montel
Czyste, uruchom ponownie i bez efektu. Projekt> cel wdrożenia systemu iOS 7.0, podstawowy zestaw SDK 7.0 w miejscu docelowym z tymi samymi ustawieniami.
Błażej
2

Oto szybkie rozwiązanie podklasy, którego często używam w przypadku tego problemu.

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
        }
    }
}
WaltersGE1
źródło
2

Ten problem powrócił w Xcode 8. Oto jak go naprawiłem:

Zmieniono rozszerzenie na:

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

i zaznaczono opcję Wybieralne w programie Interface Builder.

Posiadanie tego „wybieralnego” parametru nie jest zbyt eleganckie, ale wystarczy.

Alessandro Ranaldi
źródło
1

W iOS 8.3 obejście ustawienia „selectable” na YES przed setText i NO po, nie rozwiązało tego problemu.

Zauważyłem, że muszę ustawić opcję „do wyboru” na TAK w scenorysie, zanim to zadziała.

Peter Johnson
źródło
Uratowałeś mi dzień, myślę, że to tylko kolejny śmieszny błąd w CocoaTouch
Chris
1

To zadziałało dla mnie:

let font = textView.font
textView.attributedText = attributedString
textView.font  = font
David Green
źródło
0

Dla mnie z przypisanym tekstem wystarczyło ustawić czcionkę w słowniku atrybutów, zamiast ustawiać ją we własnym polu.

Krzykacz
źródło
0

Mam ten problem. Szybkie i przyjazne rozwiązanie odpowiedzi @Ken Steele. Rozszerzam UITextView i dodaję właściwość obliczoną.

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

mam nadzieję, że to pomoże.

LastMove
źródło
0

Minęły już 3 lata, a błąd nadal istnieje w najnowszej stabilnej wersji Xcode (7.3). Najwyraźniej Apple nie naprawi tego w najbliższym czasie, pozostawiając programistom dwie opcje: pozostawienie wyboru włączonego i ustawienie UserInteractionEnabled na false lub swizzling Method.

Jeśli masz przycisk na swoim textView, pierwszy nie wystarczy.

Szybkie rozwiązanie wymagające zmiany kodu:

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

Cel 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
Mark Bourke
źródło
0

Korzystając z obejścia omówionego w tym problemie, to rozszerzenie UITextView udostępnia setTextInCurrentStyle()funkcję. Oparty na rozwiązaniu Alessandro Ranaldiego, ale nie wymaga przekazywania bieżącej wartości isSelectable do funkcji.

extension UITextView{
    func setTextInCurrentStyle(_ newText: String) {
        let selectablePreviously = self.isSelectable
        isSelectable = true
        text = newText
        isSelectable = selectablePreviously
    }
}
Duncan Babbage
źródło