Yazarken bir UITextField yeniden boyutlandırma (Autolayout kullanarak)

iki Uıtextfields (sınırsız) olan bir Uıtableviewcell var. Aşağıdaki kısıtlamalar yatay düzeni ayarlamak için kullanılır.

@"|-10-[leftTextField(>=80)]-(>=10)-[rightTextField(>=40)]-10-|"

hiçbir şey fantezi ve beklendiği gibi çalışır.

enter image description here

gördüğünüz gibi üst textField doğru boyutu vardır. Alt textField boş bir metin ile başladı ve boş metin nedeniyle 80 puan geniş. Metni düzenleme metnine yazdığımda, metin sola kaydırır, genişliğini değiştirmez.

bunu sevmiyorum, metin alanının genişliği, kullanıcı o metin alanına girerken ayarlanmalıdır.

bence kutunun dışında çalışması gerekir. UIControlEventEditingChanged olayı için IBAction uygulayarak, yazmanın aslında Uıtextfield'ın intrinsicContentSize değerini değiştirdiğini doğrulayabilirim.

ama iyi, genişlik, textField artık ilk yanıtlayıcı olana kadar değişmez. İmleci başka bir metin alanına koyarsam, düzenlenmiş metin alanının genişliği ayarlanır. İstediğim şey için biraz geç oldu.

bu satırları yorumladı herhangi bir başarı olmadan denedim:

- (IBAction)textFieldDidChange:(UITextField *)textField {
    [UIView animateWithDuration:0.1 animations:^{
//        [self.contentView removeConstraints:horizontalConstraints];
//        [self.contentView addConstraints:horizontalConstraints];
//        [self.contentView layoutIfNeeded];

//        [self.contentView setNeedsLayout];

//        [self.contentView setNeedsUpdateConstraints];
    }];
    NSLog(@"%@", NSStringFromCGSize(textField.intrinsicContentSize));
}

ne kaçırdığımı bilen var mı? Bu işi yapmak için ne deneyebilirim?

53
tarihinde sordu Matthias Bauch 2013-08-14 19:59:27
kaynak

9 ответов

bu benim için işe yarıyor:

- (IBAction) textFieldDidChange: (UITextField*) textField
{
    [UIView animateWithDuration:0.1 animations:^{
        [textField invalidateIntrinsicContentSize];
    }];
}

ilginç olan şey, belgelerinden metni göz önüne alındığında, kutunun dışında çalışması gerektiği gibi görünüyor:

buna ek olarak, bir görünümün bir özelliği değişirse ve bu değişiklik etkilenirse iç içerik boyutu, görünüm çağırmalıdır ınvalidateıntrinsiccontentsize böylece düzen sistemi fark eder değişim ve yeniden düzen olabilir. Uygulamada görünüm sınıfınız, eğer herhangi bir özellik değeri hangi üzerine emin olmalısınız içsel boyut değişiklikleri bağlıdır, çağırmak ınvalidateıntrinsiccontentsize. örneğin, bir metin alanı çağırır ınvalidateıntrinsiccontentsize dize değeri değişirse.

en iyi tahminim, textfield'ın yalnızca ınvalidateıntrinsiccontentsize düzenleme bittikten sonra, sırasında değil çağırmasıdır.

Düzenle: bir grup "bu benim için çalışmıyor". Buradaki karışıklığın belki de textFieldDidChange: işleyicisine bağlı tetikleyici olay olduğunu düşünüyorum. Olay UİControlEventEditingChanged olması gerekir. IB kullanıyorsanız, doğru olayı ele aldığınızı iki kez kontrol edin.

UITextField de boyut olarak kısıtlanamaz. Kısıtlamalarla konuma kilitleyebilirsiniz, ancak herhangi bir genişlik kısıtlaması veya sol+sağ konumlandırma kısıtlamaları kümesi iç içerik boyutuna yeniden boyutlandırılmasını önleyin.

53
cevap TomSwift 2017-04-21 21:29:40
kaynak

neden UITextField ilk yanıtlayıcı statüsünden istifa ettiğinde intrinsicContentSize sadece intrinsicContentSize güncellemelerini bilmiyorum. Bu hem iOS 7 hem de iOS 8 için olur.

geçici bir çözüm olarak intrinsicContentSize geçersiz kılar ve typingAttributes kullanarak boyutunu belirler . Bu leftView ve rightView de

hesapları
// This method is target-action for UIControlEventEditingChanged
func textFieldEditingChanged(textField: UITextField) {
  textField.invalidateIntrinsicContentSize()
}


override var intrinsicContentSize: CGSize {
    if isEditing {
      let string = (text ?? "") as NSString
      let size = string.size(attributes: typingAttributes)
      return CGSize(width: size.width + (rightView?.bounds.size.width ?? 0) + (leftView?.bounds.size.width ?? 0) + 2,
                    height: size.height)
    }

    return super.intrinsicContentSize
  }

burada, bt'yi

17
cevap onmyway133 2017-01-27 11:21:03
kaynak

İşte Swift'deki cevap. Bonus olarak, bir yer tutucu varsa bu snippet metin alanını daraltmaz.

// UITextField subclass

override func awakeFromNib() {
    super.awakeFromNib()
    self.addTarget(self, action: #selector(textFieldTextDidChange), forControlEvents: .EditingChanged)
}

func textFieldTextDidChange(textField: UITextField) {
    textField.invalidateIntrinsicContentSize()
}

override func intrinsicContentSize() -> CGSize {
    if self.editing {
        let textSize: CGSize = NSString(string: ((text ?? "" == "") ? self.placeholder : self.text) ?? "").sizeWithAttributes(self.typingAttributes)
        return CGSize(width: textSize.width + (self.leftView?.bounds.size.width ?? 0) + (self.rightView?.bounds.size.width ?? 0) + 2, height: textSize.height)
    } else {
        return super.intrinsicContentSize()
    }
}
4
cevap WaltersGE1 2016-07-22 22:16:33
kaynak

bir UITextView ile benzer bir gereksinime sahiptim (dinamik olarak yüksekliğini ve diğer bazı şeyleri arttırmak zorunda kaldım).

yaptığım şey buna benzer bir şeydi:

self.contentView superview textField

- (IBAction)textFieldDidChange:(UITextField *)textField {
    //You can also use "textField.superview" instead of "self.contentView"
    [self.contentView setNeedsUpdateConstraints];

    //Since you wish to animate that expansion right away...
    [UIView animateWithDuration:0.1 animations:^{
        [self.contentView updateConstraintsIfNeeded];
    }];
    NSLog(@"%@", NSStringFromCGSize(textField.intrinsicContentSize));
}

ayrıca, sahip olduğum gereksinimleri göz önünde bulundurarak, UITextView 'in superview yönteminin updateConstraints yöntemini geçersiz kılmak zorunda kaldım .

Should you bu çözümü tercih etmeyi seçin (belki daha ince ayarlanmış bir yaklaşım için), şunları yapabilirsiniz:

- (void)updateConstraints {
    [super updateConstraints];

    //Firstly, remove the width constraint from the textField.
    [self.myTextField removeConstraint:self.textFieldWidthConstraint];
    self.textFieldWidthConstraint = nil;

    CGSize contentSize = self.myTextField.intrinsicContentSize;
    self.textFieldWidthConstraint = [NSLayoutConstraint constraintWithItem:self.myTextField attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:contentSize.width];

    [self.myTextField addConstraint:self.textFieldWidthConstraint];
}

belirtildiği gibi, geçersiz kılma seçeneği benim tarafımdan kullanıldı, çünkü daha ince ayarlanmış bir yaklaşım gerektirdim.

Ayrıca, her zaman olduğu gibi, karşılaşabileceğiniz herhangi bir kenar vakasını (boyutlandırma değerleri açısından) kontrol ettiğinizden emin olmanız gerekir.

Umarım bu yardımcı olur!

şerefe!

1
cevap codeBearer 2013-08-16 23:17:10
kaynak

first things first : Swift 4'te uıtextfield'ın intrinsicContentSize, bir yöntem değil, hesaplanan bir değişkendir.

aşağıda özel bir kullanım kılıfı ile Swift4 çözümüdür. Sağ piksel textfield yeniden boyutlandırmak ve belirli bir piksel sınırına kadar sola uzatabilirsiniz. Textfield CurrencyTextField sınıfı '151930920 UITextField devralır atanır . CurrencyTextField daha sonra genişletilir nesnenin intrinsicContentSize döndürülmesi için özel davranış sağlamak için hesaplanan bir değişken. .

CurrencyTextField örneğinin " düzenleme değişti " olayı repositionAndResize IBAction yöntemi ana Uıviewcontroller sınıfında eşlenir. Bu yöntem yalnızca geçerli iç içerik boyutunu geçersiz CurrencyTextField örneği. Currencytextfield'ın çağrılması ınvalidateıntrinsiccontentsize yöntemi (devralınan form UITextField ) nesnenin iç içerik boyutu almak için bir girişim tetikler.

özel mantık Currencytextfield's ıntrinsiccontentsize getter yöntemi dönüştürmek zorunda Currenttextfield's text özelliği NSString boyutunu belirlemek için, olarak döndürür ıntrinsiccontentsize eğer X koordinatı CurrencyTextField öngörülen piksel sınırından daha büyüktür.

class CurrencyTextField:UITextField {

}

extension CurrencyTextField {


     override open var intrinsicContentSize: CGSize {

        if isEditing {
            let string = (text ?? "") as NSString
            let stringSize:CGSize = string.size(withAttributes: 
             [NSAttributedStringKey.font: UIFont.systemFont(ofSize: 
             19.0)])
             if self.frame.minX > 71.0 {
                return stringSize
             }
       }

       return super.intrinsicContentSize
    }


}

class TestController: UIViewController {

    @IBAction func repositionAndResize(_ sender: CurrencyTextField) {
        sender.invalidateIntrinsicContentSize()
    }


    override func viewDidLoad() {
        super.viewDidLoad()

    }

}
1
cevap sigmonky 2018-03-21 17:54:08
kaynak

bunun için başka bir çözüm, metin alanına önde gelen/sondaki kısıtlamaları ayarlamak ve bunları açmak/kapatmak için isActive kullanmaktır.

düzenleme başladığında, metin ortalanırsa, efekt aynı olacaktır (metin yazarken otomatik olarak yeniden boyutlandırma gibi görünüyor). Düzenleme durduğunda, çerçeveyi metnin etrafına saracak olan kısıtlamaları kapatın.

0
cevap bauerMusic 2016-10-19 11:07:52
kaynak

benim için de textfield (UİControlEventEditingChanged)

bir hedef ekledim
- (void)textFieldChanged:(UITextField *)textField {
    [textField sizeToFit];
}

bir arka plan renginiz varsa, o zaman sadece temsilci yönteminde güncelleyin:

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {

    textField.backgroundColor = [UIColor grayColor];
    return YES;
}
0
cevap robegamesios 2016-11-16 12:58:31
kaynak

sorunu çözmek için viewDidLoad bu kodu ekleyebilirsiniz.

if ([self respondsToSelector:@selector(setEdgesForExtendedLayout:)])
{
    self.edgesForExtendedLayout = UIRectEdgeNone;
}
0
cevap Eric Lee 2017-03-07 12:33:53
kaynak

diye bir sebepten dolayı invalidateIntrinsicContentSize benim için de işe yaramadı, ancak marjlar ve düzenleme kontrolleri nedeniyle diğer çözümlerle ilgili sorunlarla karşılaştım.

bu çözüm her zaman gerekli değildir; invalidateIntrinsicContentSize çalışıyorsa, yapılması gereken tek şey, diğer cevaplarda olduğu gibi metin değiştirildiğinde buna bir çağrı eklemektir. Bu işe yaramazsa, işte bir çözüm ( dan uyarlanmış), aynı zamanda bir Temizle kontrol:

class AutoResizingUITextField: UITextField {
    var lastTextBeforeEditing: String?

    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: OperationQueue.main) { (notification) in                   
                self.invalidateIntrinsicContentSize()
        }
        NotificationCenter.default.addObserver(
            forName: Notification.Name.UITextFieldTextDidBeginEditing,
            object: self,
            queue: OperationQueue.main) { (notification) in
                self.lastTextBeforeEditing = self.text
        }
    }                

    override var intrinsicContentSize: CGSize {
        var size = super.intrinsicContentSize

        if isEditing, let text = text, let lastTextBeforeEditing = lastTextBeforeEditing {
            let string = text as NSString
            let stringSize = string.size(attributes: typingAttributes)
            let origSize = (lastTextBeforeEditing as NSString).size(attributes: typingAttributes)
            size.width = size.width + (stringSize.width - origSize.width)
        }

        return size
    }

    deinit {
        NotificationCenter.default.removeObserver(self)
    }
}

invalidateIntrinsicContentSize kendi başına çalışıyorsa, bu değişikliği iki kez sayarak ilk önce kontrol edilmesi gerekir.

0
cevap Learn OpenGL ES 2017-05-23 15:09:56
kaynak