Le style UITextView est réinitialisé après la définition de la propriété text

145

J'ai UITextView *_masterTextet après l'appel setText, la police de propriété de la méthode est en cours de réinitialisation. Cela se produit après avoir changé le sdk 7. _masterText est IBOutletglobal et les propriétés sont définies dans le storyboard. C'est seulement moi ou c'est un bogue général du SDK?

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

@implementation myViewController

-(void)viewWillAppear:(BOOL)animated
{
    [_masterText setText:@"New text"];
}
Błażej
la source

Réponses:

450

Assis avec ça pendant des heures, j'ai trouvé le bogue. Si la propriété "Selectable" = NO, elle réinitialisera la police et la couleur de la police lorsque setText est utilisé.

Alors activez Selectable et le bogue est parti.

Bosse Nilsson
la source
15
Cela m'arrive également dans Xcode 5. Ma solution de contournement consiste à définir temporairement selectable = YES avant d'appeler setText:
Rollin_s
8
Wow, quel bug ridicule. Merci pour la perspicacité!
Micah
3
Merci beaucoup !
Magurizio
6
6.4 a toujours ce problème
RndmTsk
4
Cela semble être résolu dans iOS 10, si vous ciblez toujours iOS 9 ou une version inférieure, vous devrez faire la solution de contournement.
user1184205
11

J'ai rencontré le même problème (sur Xcode 6.1) et bien que la réponse de John Cogan ait fonctionné pour moi, j'ai trouvé que l'extension de la classe UITextView avec une catégorie était une meilleure solution pour mon projet particulier.

interface

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

la mise en oeuvre

@implementation UITextView (XcodeSetTextFormattingBugWorkaround)
- (void)setSafeText:(NSString *)textValue
{
    BOOL selectable = [self isSelectable];
    [self setSelectable:YES];
    [self setText:textValue];
    [self setSelectable:selectable];
}
@end
Ken Steele
la source
1
Et en swift:extension UITextView { func setSafeText(text: String){ let originalSelectable = selectable selectable = true self.text = text selectable = originalSelectable } }
petit
8

Si vous voulez que votre vue de texte soit en "lecture seule", vous pouvez cocher Modifiable et sélectionnable et décocher Interaction utilisateur activée, avec cela, UITextView se comportait comme je le voulais

entrez la description de l'image ici

entrez la description de l'image ici

Chuy47
la source
3
Cela semble à première vue être une solution viable, mais ce n'est finalement pas une bonne option pour un UITextView. Normalement, vous choisissez un UITextView car vous avez besoin d'une zone de texte défilante. la désactivation de l'interaction utilisateur désactive également la vue déroulante. Pour moi, le choix d'utiliser un UITextView était parce que j'avais une zone qui devait contenir plus de texte que ce qui pouvait en tenir dans cette zone, et être capable de faire défiler.
jhelzer
6

Si ce problème moi-même et la réponse ci-dessus ont aidé, j'ai ajouté un wrapper à mon code ViewController comme suit et il suffit de passer l'instance et le texte uiview à modifier et la fonction wrapper active la valeur sélectionnable, modifie le texte, puis la désactive à nouveau. Utile lorsque vous avez besoin que uitextview soit désactivé à tout moment par défaut.

/*
    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
la source
1
Il serait peut-être préférable de sous-classer UITextView et de remplacer setText et d'utiliser votre sous-classe dans l'application
powerj1984
2

ÉDITER :

La définition de la police pour UITextView dans iOS 7 fonctionne pour moi si vous définissez d'abord le texte, puis la police:

@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

}

Sur un fichier XIB, si vous ajoutez du texte dans votre UITextView et changez la police ou la couleur, cela fonctionnera.

Jordan Montel
la source
hmm .. J'utilise la propriété mais pas de changement.
Błażej
oublié [super viewWillAppear: animé];
Jordan Montel
J'ai oublié, mais cela n'a pas affecté :(
Błażej
nettoyez et redémarrez votre XCode car il fonctionne très bien pour moi sans la ligne "_myTextView.font ..." même si je change la police du fichier XIB
Jordan Montel
Propre, redémarrer et sans effet. Projet> Cible de déploiement iOS 7.0, SDK de base 7.0 dans la cible les mêmes paramètres.
Błażej
2

Voici une solution rapide de sous-classe que j'utilise souvent pour ce problème.

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
la source
2

Ce problème a refait surface dans Xcode 8. Voici comment je l'ai résolu:

L'extension a été remplacée par:

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

et coché l'option sélectionnable dans le générateur d'interface.

Ce n'est pas très élégant d'avoir ce paramètre «sélectionnable», mais ça fera l'affaire.

Alessandro Ranaldi
la source
1

Dans iOS 8.3, la solution de contournement consistant à définir «sélectionnable» sur OUI avant le setText, et NON après, ne l'a pas résolu pour moi.

J'ai trouvé que je devais également définir «sélectionnable» sur OUI dans le storyboard avant que cela ne fonctionne.

Peter Johnson
la source
Vous avez sauvé ma journée, je crois que ce n'est qu'un autre bogue ridicule dans CocoaTouch
Chris
1

Cela a fonctionné pour moi:

let font = textView.font
textView.attributedText = attributedString
textView.font  = font
David Green
la source
0

Pour moi avec du texte attribué, j'avais juste besoin de définir la police dans le dictionnaire d'attributs plutôt que de la définir dans son propre champ.

grande gueule
la source
0

J'ai ce problème à. Une solution rapide de la réponse de @Ken Steele. J'étends UITextView et j'ajoute une propriété calculée.

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

J'espère que ça aide.

LastMove
la source
0

Cela fait 3 ans et le bogue existe toujours dans la dernière version stable de Xcode (7.3). Il est clair qu'Apple ne le corrigera pas de sitôt, laissant aux développeurs deux options: laisser le sélectionnable activé et définir UserInteractionEnabled sur false ou Method swizzling.

Si vous avez un bouton sur votre textView, le premier ne suffira pas.

Solution sans changement de code dans Swift:

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

Objectif 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
la source
0

À l'aide de la solution de contournement décrite dans ce problème, cette extension d'UITextView fournit une setTextInCurrentStyle()fonction. Basé sur la solution d'Alessandro Ranaldi mais ne nécessite pas que la valeur isSelectable actuelle soit transmise à la fonction.

extension UITextView{
    func setTextInCurrentStyle(_ newText: String) {
        let selectablePreviously = self.isSelectable
        isSelectable = true
        text = newText
        isSelectable = selectablePreviously
    }
}
Duncan Babbage
la source