Je dois augmenter la largeur d'un champ de texte en fonction de son contenu. Lorsque l'utilisateur saisit du texte, la taille du champ de texte doit augmenter automatiquement. J'ai un bouton proche (X) à côté de ce champ de texte.
J'ai contraint le champ de texte et le bouton de sorte que le champ de texte soit centré sur l'écran et que le bouton lui soit adjacent. (Le champ de texte doit être modifiable, le bouton doit être cliquable)
La taille du champ de texte est la suivante:
Lorsque je saisis du texte, la taille devrait automatiquement augmenter:
Comment puis-je atteindre cet objectif?
Je résous mon problème: utilisez ceci pour que textfield ne sort pas de l'écran.
func getWidth(text: String) -> CGFloat
{
let txtField = UITextField(frame: .zero)
txtField.text = text
txtField.sizeToFit()
return txtField.frame.size.width
}
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool
{
let width = getWidth(textField.text!)
if UIScreen.mainScreen().bounds.width - 55 > width
{
txtWidthOfName.constant = 0.0
if width > txtWidthOfName.constant
{
txtWidthOfName.constant = width
}
self.view.layoutIfNeeded()
}
return true
}
Version Objective C
-(CGFloat)getWidth:(NSString *)text{
UITextField * textField = [[UITextField alloc]initWithFrame:CGRectZero];
textField.text = text;
[textField sizeToFit];
return textField.frame.size.width;
}
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
if (self.textFieldName.isEditing == YES) {
CGFloat width = [self getWidth:textField.text];
if ([UIScreen mainScreen].bounds.size.width - 60 > width) {
self.txtWidthOfName.constant = 0.0;
if (width > self.txtWidthOfName.constant) {
self.txtWidthOfName.constant = width;
}
[self.view layoutIfNeeded];
}
}
return YES;
}
Vous pouvez y parvenir en surchargeant la classe UITextField
et en renvoyant une valeur personnalisée dans intrinsicContentSize
. Vous devez également vous abonner à un événement de changement de texte et invalider la taille du contenu intrinsèque lorsque le changement de texte est animé.
Voici un exemple dans Swift 3
class Test: UITextField {
override init(frame: CGRect) {
super.init(frame: frame)
setupTextChangeNotification()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupTextChangeNotification()
}
func setupTextChangeNotification() {
NotificationCenter.default.addObserver(
forName: Notification.Name.UITextFieldTextDidChange,
object: self,
queue: nil) { (notification) in
UIView.animate(withDuration: 0.05, animations: {
self.invalidateIntrinsicContentSize()
})
}
}
deinit {
NotificationCenter.default.removeObserver(self)
}
override var intrinsicContentSize: CGSize {
if isEditing {
if let text = text,
!text.isEmpty {
// Convert to NSString to use size(attributes:)
let string = text as NSString
// Calculate size for current text
var size = string.size(attributes: typingAttributes)
// Add margin to calculated size
size.width += 10
return size
} else {
// You can return some custom size in case of empty string
return super.intrinsicContentSize
}
} else {
return super.intrinsicContentSize
}
}
}
Une solution de contournement effrontée pour obtenir la largeur d’une chaîne particulière serait:
func getWidth(text: String) -> CGFloat {
let txtField = UITextField(frame: .zero)
txtField.text = text
txtField.sizeToFit()
return txtField.frame.size.width
}
Et pour avoir la largeur,
let width = getWidth(text: "Hello world")
txtField.frame.size.width = width
self.view.layoutIfNeeded() // if you use Auto layout
Si vous avez une contrainte liée à la largeur de txtField, alors faites
yourTxtFieldWidthConstraint.constant = width
self.view.layoutIfNeeded() // if you use Auto layout
Edit Nous créons un UITextField avec un cadre de pratiquement tous les zéros. Lorsque vous appelez sizeToFit (), il définit le cadre de UITextField de manière à afficher tout son contenu sans littéralement plus d'espace. Nous voulions seulement sa largeur, j'ai donc renvoyé la largeur du nouveau UITextField. ARC se chargera de le supprimer de la mémoire pour nous.
Mettre à jour
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if textField.text != nil {
let text = textField.text! as NSString
let finalString = text.replacingCharacters(in: range, with: string)
textField.frame.size.width = getWidth(text: finalString)
}
return true
}
Les réponses nécessitent toutes un tas de code, mais vous pouvez tout faire constructeur d’interface; pas de code nécessaire.
Il suffit d’incorporer le textField dans un UIStackView et de contraindre le stackView à être inférieur ou égal à son superview moins une constante (si vous voulez, vous pouvez également lui donner une largeur minimale). StackView veillera à ce que textField conserve toujours sa taille intrinsèque, ou la largeur maximale de stackView (quelle que soit sa taille), de sorte que la taille change automatiquement pour s'adapter au contenu.
Je pense que c'est une meilleure solution que d'avoir une contrainte de largeur que vous devez modifier:
Redimensionne un UITextField lors de la frappe (en utilisant Autolayout)
- (IBAction) textFieldDidChange: (UITextField*) textField
{
[UIView animateWithDuration:0.1 animations:^{
[textField invalidateIntrinsicContentSize];
}];
}
Vous pouvez omettre l'animation si vous le souhaitez.
EDIT: voici un exemple de projet: https://github.com/TomSwift/growingTextField
Implémentez la méthode suivante de UITextFieldDelegate
. Utilisez l'approche fournie par Matt pour obtenir la largeur requise de textField. Dans la disposition automatique, assurez-vous que les contraintes de centre et de largeur sont définies pour textfield. Créez IBOutlet pour votre contrainte de largeur dans un fichier de code. Assurez-vous également que vous définissez la propriété delegate de votre textField.
@IBOutlet weak var widthConstraint: NSLayoutConstraint!
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let width = getWidth(text : textField.text)
if width > widthConstraint.constant {
widthConstraint.constant = width
}
self.layoutIfNeeded()
return true
}
Cela semble tellement frustrant qu’il n’existe aucun moyen direct, comme il existe un "réducteur automatique" ou une "taille de police minimale" pour UILabel
dans IB lui-même ... ". Le réglage de la taille dans IB pour un champ de texte n’est pas bon non plus.
Pourquoi Apple nous oblige-t-il à écrire tout ce code standard, alors qu'un champ de texte nécessite autant que possible la fusion automatique, sinon plus, que le UILabel!