Comment styliser UITextview pour aimer le champ de texte Rounded Rect?

170

J'utilise une vue de texte comme compositeur de commentaires.

Dans l'inspecteur de propriétés, je ne trouve rien de tel qu'une propriété de style de bordure pour pouvoir utiliser un rect arrondi, quelque chose comme UITextField.

Alors, la question est: comment puis-je coiffer un UITextViewcomme un UITextFieldavec un rect arrondi?

harshalb
la source
1
Ne pourriez-vous pas utiliser UITextFieldet éteindre simplement userInteractionEnabled?
jowie

Réponses:

285

Il n'y a pas de style implicite à choisir, cela implique d'écrire un peu de code en utilisant le QuartzCoreframework:

//first, you
#import <QuartzCore/QuartzCore.h>

//.....

//Here I add a UITextView in code, it will work if it's added in IB too
UITextView *textView = [[UITextView alloc] initWithFrame:CGRectMake(50, 220, 200, 100)];

//To make the border look very close to a UITextField
[textView.layer setBorderColor:[[[UIColor grayColor] colorWithAlphaComponent:0.5] CGColor]];
[textView.layer setBorderWidth:2.0];

//The rounded corner part, where you specify your view's corner radius:
textView.layer.cornerRadius = 5;
textView.clipsToBounds = YES;

Cela ne fonctionne que sur OS 3.0 et supérieur, mais je suppose que maintenant c'est la plate-forme de facto de toute façon.

luvieere
la source
47
J'ai trouvé que l'ajout du haut suivant le code ci-dessus rend la bordure très proche d'un UITextField. [textView.layer setBorderColor: [[[UIColor grayColor] colorWithAlphaComponent: 0,5] CGColor]]; [textView.layer setBorderWidth: 2.0];
Rob
12
Assurez-vous d'avoir: #import <QuartzCore / QuartzCore.h>. J'ai eu des problèmes car je n'ai pas importé QuartzCore
austen
1
Pour les n00bs comme moi, digne de mention: mettez ce code dans viewDidLoad PAS dans initWithNibName :-)
Brian Colavito
1
Vous pouvez simplement utiliser a UITextFieldavec la borderStylepropriété définie sur UITextBorderStyleRoundedRect- voir mon message ci-dessous.
jowie
5
iOS 7 - borderWidth de 1.0 et alpha de .2 fonctionne avec le style par défaut.
Kalel Wade
77

ce code a bien fonctionné pour moi:

    [yourTextView.layer setBackgroundColor: [[UIColor whiteColor] CGColor]];
    [yourTextView.layer setBorderColor: [[UIColor grayColor] CGColor]];
    [yourTextView.layer setBorderWidth: 1.0];
    [yourTextView.layer setCornerRadius:8.0f];
    [yourTextView.layer setMasksToBounds:YES];
hanumanDev
la source
4
Je dirais que 5px est plus proche des champs de texte, mais la couleur grise de cette réponse est meilleure que la réponse sélectionnée.
Peter DeWeese
2
Bien sûr, vous devez ajouter QuartzCore Framework pour cette réponse et l'importer par #import <QuartzCore / QuartzCore.h>
lukaswelte
36

Version Swift 3

Après avoir configuré la vue de texte dans le générateur d'interface.

@IBOutlet weak var textView: UITextView!

override func viewDidLoad() {
    super.viewDidLoad()
    textView.layer.cornerRadius = 5     
    textView.layer.borderColor = UIColor.gray.withAlphaComponent(0.5).cgColor
    textView.layer.borderWidth = 0.5  
    textView.clipsToBounds = true
}

Version Swift 2.2

@IBOutlet weak var textView: UITextView!

override func viewDidLoad() {
    super.viewDidLoad()
    textView.layer.cornerRadius = 5     
    textView.layer.borderColor = UIColor.grayColor().colorWithAlphaComponent(0.5).CGColor
    textView.layer.borderWidth = 0.5  
    textView.clipsToBounds = true
}
Sean McClory
la source
1
Le problème est que ce n'est pas exactement gris. La couleur du cadre de UITextField est un peu différente.
Makalele
1
Faire .borderWidth = 0.7 le rend plus proche du style actuel que je vois sur iOS 11.
Chris Amelinckx
28

Edit: vous devez importer

#import <QuartzCore/QuartzCore.h>

pour utiliser le rayon de coin.

Essayez ceci, cela fonctionnera à coup sûr

UITextView* txtView = [[UITextView alloc] initWithFrame:CGRectMake(50, 50, 300, 100)];
txtView.layer.cornerRadius = 5.0;
txtView.clipsToBounds = YES;

Comme Rob l'a compris, si vous voulez que la couleur de la bordure soit similaire, UITextFieldvous devez changer la largeur de la bordure en 2.0 et la couleur en gris en ajoutant la ligne suivante

[textView.layer setBorderColor:[[[UIColor grayColor] colorWithAlphaComponent:0.5] CGColor]]; 
[textView.layer setBorderWidth:2.0];
Suresh Varma
la source
2
Je me demandais pourquoi cela ne fonctionnait pas. Merci pour le tuyau sur QuartzCore.
Echilon
23

Je voulais la vraie affaire, alors j'ajoute UIImageViewcomme sous-vue du UITextView. Cela correspond à la bordure native sur a UITextField, y compris le dégradé de haut en bas:

textView.backgroundColor = [UIColor clearColor];
UIImageView *borderView = [[UIImageView alloc] initWithFrame: CGRectMake(0, 0, textView.frame.size.width, textView.frame.size.height)];
borderView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
UIImage *textFieldImage = [[UIImage imageNamed:@"TextField.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(15, 8, 15, 8)];
borderView.image = textFieldImage;
[textField addSubview: borderView];
[textField sendSubviewToBack: borderView];

Voici les images que j'utilise:

entrez la description de l'image ici entrez la description de l'image ici

Ben Packard
la source
2
Je pense que vous devez également dire à textView d'avoir UITextBorderStyle None si vous ne l'avez pas déjà défini dans XCode
superlogical
1
J'ai re-téléchargé les images png
Ben Packard
5
Pas bon, l'arrière-plan se déplace lorsque vous faites défiler UITextView. Je suppose que je vais devoir tout placer dans un UIView parent.
Oliver Pearmain
1
Excellent. Ça a l'air génial: D
Sune Trudslev
12

Une solution consiste à ajouter un UITextField sous UITextView , à rendre l' UITextViewarrière - plan transparent et à désactiver toute interaction utilisateur sur le UITextField. Ensuite, dans le code, changez le UITextFieldcadre avec quelque chose comme ça

self.textField.frame = CGRectInset(self.textView.frame, 0, -2);

Vous aurez exactement le même aspect qu'un champ de texte.

Et comme suggéré par Jon , vous devriez mettre ce morceau de code à l'intérieur [UIViewController viewDidLayoutSubviews]sur iOS 5.0+.

Phil
la source
1
C'était si simple et ça ressemble exactement à ce que je voulais. Je viens de faire correspondre le cadre du UITextField au UITextView: CGRect frame = self.myTextView.frame; frame.size.height + = 2; self.myTextField.frame = cadre;
Buyin Brian
1
Belle réponse. Propre et simple. Mettez du code dans viewDidLayoutSubviews:(iOS 5.0+).
Jon
1
Bien, c'était la solution avec laquelle je suis allé à la fin. Notez que cela n'a pas fonctionné jusqu'à ce que j'utilise le commentaire de Jon re: viewDidLayoutSubviews:
daver
1
C'était le plus rapide et le meilleur.
Weston
5

Pour le meilleur effet, vous devez utiliser une image d'arrière-plan personnalisée (extensible). C'est aussi ainsi que la UITextFieldbordure arrondie du 's est dessinée.

KennyTM
la source
4

Une façon que j'ai trouvée pour le faire sans programmation est de rendre le fond du champ de texte transparent, puis de placer un bouton Round Rect derrière. Assurez-vous de modifier les paramètres du bouton pour le désactiver et décochez la Disable adjusts imagecase.

Andrew_L
la source
4

Vous voudrez peut-être consulter ma bibliothèque appelée DCKit .

Vous pourrez créer une vue de texte dans un coin arrondi (ainsi qu'un champ de texte / bouton / simple UIView) à partir de Interface Builderdirectement:

DCKit: UITextView bordé

Il possède également de nombreuses autres fonctionnalités utiles, telles que des champs de texte avec validation, des contrôles avec des bordures, des bordures en pointillés, des vues de cercle et de cheveux, etc.

Andrey Gordeev
la source
4

Je sais qu'il y a déjà beaucoup de réponses à celle-ci, mais je n'ai vraiment trouvé aucune d'elles suffisante (du moins dans Swift). Je voulais une solution qui fournisse la même bordure exacte qu'un UITextField (pas une approximation qui ressemble en quelque sorte à ce qu'elle ressemble maintenant, mais une qui lui ressemble exactement et qui lui ressemblera toujours). J'avais besoin d'utiliser un UITextField pour sauvegarder l'UITextView pour l'arrière-plan, mais je ne voulais pas avoir à le créer séparément à chaque fois.

La solution ci-dessous est un UITextView qui fournit son propre UITextField pour la bordure. Ceci est une version réduite de ma solution complète (qui ajoute la prise en charge des "espaces réservés" à UITextView de la même manière) et a été publiée ici: https://stackoverflow.com/a/36561236/1227119

// This class implements a UITextView that has a UITextField behind it, where the 
// UITextField provides the border.
//
class TextView : UITextView, UITextViewDelegate
{
    var textField = TextField();

    required init?(coder: NSCoder)
    {
        fatalError("This class doesn't support NSCoding.")
    }

    override init(frame: CGRect, textContainer: NSTextContainer?)
    {
        super.init(frame: frame, textContainer: textContainer);

        self.delegate = self;

        // Create a background TextField with clear (invisible) text and disabled
        self.textField.borderStyle = UITextBorderStyle.RoundedRect;
        self.textField.textColor = UIColor.clearColor();
        self.textField.userInteractionEnabled = false;

        self.addSubview(textField);
        self.sendSubviewToBack(textField);
    }

    convenience init()
    {
        self.init(frame: CGRectZero, textContainer: nil)
    }

    override func layoutSubviews()
    {
        super.layoutSubviews()
        // Do not scroll the background textView
        self.textField.frame = CGRectMake(0, self.contentOffset.y, self.frame.width, self.frame.height);
    }

    // UITextViewDelegate - Note: If you replace delegate, your delegate must call this
    func scrollViewDidScroll(scrollView: UIScrollView)
    {
        // Do not scroll the background textView
        self.textField.frame = CGRectMake(0, self.contentOffset.y, self.frame.width, self.frame.height);
    }        
}
BobDickinson
la source
3

Une façon que j'ai trouvée pour le faire sans programmation est de rendre le fond du champ de texte transparent, puis de placer un bouton Round Rect derrière. Assurez-vous de modifier les paramètres du bouton pour le désactiver et décochez la case Désactiver ajuste l'image.

J'ai essayé le code Quartzcore et j'ai trouvé qu'il causait un décalage sur mon ancien 3G (que j'utilise pour les tests). Ce n'est pas un gros problème, mais si vous voulez être aussi inclusif que possible pour différents ios et matériels, je recommande la réponse d'Andrew_L ci-dessus - ou créez vos propres images et postulez en conséquence.

Pomme Jooce
la source
3

Il existe une superbe image d'arrière-plan identique à celle UITextViewutilisée pour envoyer des messages texte dans l'application Messages de l'iPhone. Vous aurez besoin d'Adobe Illustrator pour l'obtenir et le modifier. éléments vectoriels iphone ui

ma11hew28
la source
3
#import <QuartzCore/QuartzCore.h>
- (void)viewDidLoad{
  UITextView *textView = [[UITextView alloc] initWithFrame:CGRectMake(50, 220, 200, 100)];
  textView.layer.cornerRadius = 5;
  textView.clipsToBounds = YES;
  [textView.layer setBackgroundColor: [[UIColor whiteColor] CGColor]];
  [textView.layer setBorderColor: [[UIColor grayColor] CGColor]];
  [textView.layer setBorderWidth: 1.0];
  [textView.layer setCornerRadius:8.0f];
  [textView.layer setMasksToBounds:YES];
  [self.view addSubView:textview];
}
Sonu
la source
2

Vous pouvez créer un champ de texte qui n'accepte aucun événement au-dessus d'une vue de texte comme ceci:

CGRect frameRect = descriptionTextField.frame;
frameRect.size.height = 50;
descriptionTextField.frame = frameRect;
descriptionTextView.frame = frameRect;
descriptionTextField.backgroundColor = [UIColor clearColor];
descriptionTextField.enabled = NO;
descriptionTextView.layer.cornerRadius = 5;
descriptionTextView.clipsToBounds = YES;
Nate
la source
Ou créez simplement un champ de texte dans le générateur d'interface. Ensuite, définissez la hauteur dans le code (puisque le constructeur d'interface ne vous le permettra pas). CGRect frameRect = self.textField.frame; frameRect.size.height = 50; self.textField.frame = frameRect;
audub
2

Si vous souhaitez conserver le code de votre contrôleur propre, vous pouvez sous-classe UITextView comme ci-dessous et modifier le nom de la classe dans Interface Builder.

RoundTextView.h

#import <UIKit/UIKit.h>
@interface RoundTextView : UITextView
@end

RoundTextView.m

#import "RoundTextView.h"
#import <QuartzCore/QuartzCore.h>
@implementation RoundTextView
-(id) initWithCoder:(NSCoder *)aDecoder {
    if (self = [super initWithCoder:aDecoder]) {
        [self.layer setBorderColor:[[[UIColor grayColor] colorWithAlphaComponent:0.333] CGColor]];
        [self.layer setBorderWidth:1.0];
        self.layer.cornerRadius = 5;
        self.clipsToBounds = YES;
    }
    return self;
}
@end
Satoshi Nakajima
la source
1

Voici ma solution:

- (void)viewDidLoad {
    [super viewDidLoad];


    self.textView.text = self.messagePlaceholderText;
    self.textView.layer.backgroundColor = [[UIColor whiteColor] CGColor];
    self.textView.layer.borderColor = [[[UIColor grayColor] colorWithAlphaComponent:0.3] CGColor];
    self.textView.layer.borderWidth = 0.5;
    self.textView.layer.cornerRadius = 5.5f;
    self.textView.layer.masksToBounds = YES;
    self.textView.textColor = [[UIColor grayColor] colorWithAlphaComponent:0.4];
}

- (void)textViewDidBeginEditing:(UITextView *)textView {
    if (textView == self.tvMessage) {
        // Delete placeholder text
        if ([self.textView.text isEqualToString:self.messagePlaceholderText]) {
            self.textView.text = @"";
            self.textView.textColor = [UIColor blackColor];
        }
    }
}

- (void)textViewDidEndEditing:(UITextView *)textView {
    if (textView == self.tvMessage) {
        // Write placeholder text
        if (self.textView.text.length == 0) {
            self.textView.text = self.messagePlaceholderText;
            self.textView.textColor = [[UIColor grayColor] colorWithAlphaComponent:0.4];
        }
    }
}
Manuel Schmitzberger
la source
0

Je ne pense pas que ce soit possible. mais vous pouvez faire UITableView(groupé) avec 1 section et 1 cellule vide et l'utiliser comme conteneur pour votre UITextView.

Morion
la source
0

C'est une vieille question, et j'ai également été recherché pour cette réponse aux questions. La réponse de luvieeres est correcte à 100% et plus tard, Rob a ajouté du code. C'est excellent, mais j'ai trouvé un tiers dans une autre réponse aux questions qui me semble très utile. Je n'étais pas seulement cherché aspect similaire de UITextFieldplus UITextView, je cherchais aussi multiligne. ChatInputSample satisfait les deux. C'est pourquoi je pense que ce tiers pourrait être utile aux autres. Merci également à Timur, il a mentionné cette source ouverte ici .

sumon
la source
0

Dans iOS7, ce qui suit correspond parfaitement à la frontière UITextField (du moins à mes yeux):

textField.layer.borderColor = [[[UIColor grayColor] colorWithAlphaComponent:0.5] CGColor];
textField.layer.borderWidth = 0.5;
textField.layer.cornerRadius = 5;
textField.clipsToBounds = YES;

Il n'est pas nécessaire d'importer quoi que ce soit de spécial.

Merci à @uvieere et @hanumanDev dont les réponses me mènent presque là :)

Adrian Toman
la source
-1

Que diriez-vous simplement:

UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(20, 20, 280, 32)];
textField.borderStyle = UITextBorderStyleRoundedRect;
[self addSubview:textField];
jowie
la source
La question concerne la visualisation de texte.
Azik Abdullah
Désolé - déclenchez une réponse de pile heureuse. Ce serait intéressant de savoir pourquoi ils ne pouvaient pas seulement utiliser un UITextFieldavec userInteractionEnabledjeu pour NO.
jowie
Textfield ne prend pas en charge plusieurs lignes
Azik Abdullah
compris. Merci d'avoir clarifié
jowie