iOS: Metin uzunluğuna göre UIButton yeniden boyutlandırma


134

Arayüz oluşturucuda, Command+ tuşunu basılı tutarak =bir düğme metnine sığacak şekilde yeniden boyutlandırılır. Düğmenin görünüme eklenmeden önce bunun programlı olarak yapılıp yapılmayacağını merak ediyordum.

UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button.titleLabel setFont:[UIFont fontWithName:@"Arial-BoldMT" size:12]];
[button addTarget:self action:@selector(buttonTapped:) forControlEvents:UIControlEventTouchUpInside];
// I need to know the width needed to accomodate NSStringVariable
[button setTitle:NSStringVariable forState:UIControlStateNormal]; 
// So that I can set the width property of the button before addSubview
[button setFrame:CGRectMake(10, 0, width, fixedHeight)];
[subNavigation addSubview:button];

1
Bu çok eski soru için not: günümüzde (2017), kısıtlamayı "büyük veya eşit" olarak ayarlayın ve her şeyi yapar. (
Tad'ın

@Fattie AutoLayout ile uyumluluk için " büyük veya eşit " bir kısıtlama yeterli değildir . Günümüzde (2017+), düğmeyi ya uygun şekilde yeniden boyutlandırılan bir şeyin içine sarmalı (Bartłomiej Semańczyk cevabı) ya da stackoverflow.com/a/50575588/1033581
Cœur

hi @ Cœur - otomatik yerleşim için birçok incelik vardır. Biraz farklı bir durum düşünüyor olabilirsiniz? Ancak, neyse ki, tamamen yanılıyorsunuz - sadece deneyin !! Bir görünüm denetleyicisine bir UIButton koyun. yatay ve dikey merkezi açıkça ayarlayın. Ve sonra> = 100 genişlik kısıtlaması ekleyin. en son iOS'ta mükemmel çalışır.
Fattie

1
(Burada otomatik googling googling yeni herkes için ........... sadece TBC hiçbir şey eklemek zorunda değilsiniz ve UIButton (ayrıca UILabel, vb) metin değişiklikleri ile otomatik olarak genişliği yeniden boyutlandırılır. H / V konumunu doğru şekilde sınırlayın.)
Fattie

@Şişe gösterisi . Özellikle, çalışma zamanında, şöyle davranır: github.com/Coeur/autolayoutButton/blob/master/buttonSelfSizing/…
Cœur

Yanıtlar:


1

Xcode 4.5 ve sonraki sürümlerde, bu artık ' Otomatik düzen / Kısıtlamalar ' kullanılarak yapılabilir.

Başlıca avantajları:

  1. Çerçeveleri programlı olarak ayarlamanız gerekmez!
  2. Doğru yapılırsa, yön değişiklikleri için kareleri sıfırlama konusunda endişelenmenize gerek yoktur.
  3. Ayrıca, cihaz değişikliklerinin sizi rahatsız etmesi gerekmez (okuma, farklı ekran boyutları için ayrı ayrı kodlamaya gerek yoktur).

Birkaç dezavantajı:

  1. Geriye dönük uyumlu değil - yalnızca iOS 6 ve üstü için çalışır.
  2. Aşina olmanız gerekiyor (ancak daha sonra zaman kazanacaksınız).

En havalı şey şu gibi bir niyet beyan etmeye odaklanmaktır:

  • Bu iki düğmenin aynı genişlikte olmasını istiyorum; veya
  • Bu görüşün dikey olarak ortalanması ve denetimin kenarından en fazla 10 punto kadar uzatılması gerekir; ya da,
  • Bu düğmenin / etiketin görüntülediği etikete göre yeniden boyutlandırılmasını istiyorum!

İşte otomatik düzen ile tanışmak için basit bir öğretici.

Daha fazla ayrıntı için .

İlk başta biraz zaman alır, ama kesinlikle çabaya değecek gibi görünüyor.


3
Bu cevabı neredeyse özledim - gerçekten çok daha fazla oy gerekiyor. Bu çözümle, yazı tipi yüz adlarını ve boyutlarını veya yalnızca iOS 7 çağrılarını gömmekten kaçınabilirsiniz. UIButton'umun uzatılmasını istediğim tarafın kısıtlamasını ayarladım ve hepsi bu.
Carl

Neredeyse mükemmel bir çözüm, titleEdgeInsets kullanıyorsanız maalesef işe yaramaz: /
Zoltán

130
Bu kötü bir cevaptır - bu durumda sorucunun problemini çözmek için AutoLayout'un bu durumda nasıl uygulanabileceğinden ziyade AutoLayout'un avantajlarını detaylandırır.
mattsven

4
Bunun programlı olarak yapmanın mümkün olup olmadığını merak ediyordum cevabı söylüyor ...
Juan Boero

@JuanPabloBoeroAlvarez Otomatik Düzen kısıtlamaları, Arayüz Oluşturucu'da ve / veya programlı olarak belirtilebilir.
Slipp D.Thompson

130

UIKit'te, belirli bir fontta işlendiğinde alacağı boyutta belirli bir NSString nesnesinden almak için NSString sınıfına eklemeler vardır.

Dokümanlar buradaydı . Şimdi burada Kullanımdan Kaldırıldı altında.

Kısacası, giderseniz:

CGSize stringsize = [myString sizeWithFont:[UIFont systemFontOfSize:14]]; 
//or whatever font you're using
[button setFrame:CGRectMake(10,0,stringsize.width, stringsize.height)];

... düğmenin çerçevesini oluşturduğunuz dizenin yüksekliğine ve genişliğine ayarlayacaksınız.

Muhtemelen bu CGSize etrafında bir tampon alanı denemek isteyeceksiniz, ancak doğru yerden başlayacaksınız.


4
Görünüşe göre iOS varsayılan dolgusu 12 piksel, 8 piksel.
Ben Lachman

19
sizeWithFont, iOS 7.0'da kullanımdan kaldırıldı. SizeWithAttributes kullanın: bunun yerine
carmen_munich

6
Artık çerçevelerle oynamayı değil, YALNIZCA kısıtlamalarla oynamanızı şiddetle tavsiye ediyorum.
Gil Sand

@GilSand Bunun için arayüz oluşturucu kullanmanın bir yolu var mı?
huggie

Evet, bir google araması size birçok yararlı sonuç vermelidir
Gil Sand

101

Bunu kodda yapmanın yolu:

[button sizeToFit];

Alt sınıflama yapıyorsanız ve fazladan kurallar eklemek istiyorsanız geçersiz kılabilirsiniz:

- (CGSize)sizeThatFits:(CGSize)size;

5
sizeToFit, UIButton veya UILabel gibi standart kontrollerde mükemmel çalışır. Özel bir UIView üzerinde yapıyorsanız, uygulamanız gerekir -(CGSize)sizeThatFits:(CGSize)size.
Cameron Lowell Palmer

4
Yalnızca metni ayarladıktan sonra koyarsanız çalışır, aksi takdirde ne kadar büyük olması gerektiği hakkında yeterli bilgi yoktur: [button setTitle:@"Your text here" forState:UIControlStateNormal]; [button sizeToFit]; Ayrıca metni daha sonra güncellerseniz, tekrar aramayı unutmayın.
Juan Boero

Metni yalnızca bu şekilde ayarladığınızdan emin olun: [myButton setTitle: @ "başlığım" forState: UIControlStateNormal]; Benim için bu ifadeyi tekrarlayana kadar işe yaramadı.
Darius Miliauskas

7
sizeToFit()başlık kenarı iç metinlerine uymaz.
kelin

32

Düğmeniz Interface Builder ile yapılmışsa ve koddaki başlığı değiştiriyorsanız, bunu yapabilirsiniz:

[self.button setTitle:@"Button Title" forState:UIControlStateNormal];
[self.button sizeToFit];

1
Düğmeniz kodla yapılmış olsa bile bunu yapabilirsiniz.
Markus

22

Swift:

Buradaki önemli şey, ne zaman arayacağınızdır, .sizeToFit()metni görüntülenecek şekilde ayarladıktan sonra gereken boyutu okuyacaktır, daha sonra metni güncellerseniz tekrar arayın.

var button = UIButton()
button.setTitle("Length of this text determines size", forState: UIControlState.Normal)
button.sizeToFit()
self.view.addSubview(button)

18

Bunu otomatik düzenleme kullanarak gerçekleştirmek için değişken genişlik kısıtlaması ayarlamayı deneyin:

Genişlik Kısıtlaması

Ayrıca ayarlamanız Content Hugging Priorityve Content Compression Resistance Priorityihtiyacınız olan sonuçları elde etmeniz de gerekebilir.


UILabel tamamen otomatik olarak boyutlandırılır :

Bu UILabel basitçe ekranda ortalanacak şekilde ayarlanmıştır (yalnızca iki kısıtlama, yatay / dikey):

Genişlikleri tamamen otomatik olarak değiştirir:

Herhangi bir genişlik veya yükseklik ayarlamanıza gerek yoktur - tamamen otomatiktir.

resim açıklamasını buraya girin

resim açıklamasını buraya girin

Küçük sarı karelerin basit bir şekilde takıldığına dikkat edin (sıfırın "aralığı"). UILabel yeniden boyutlandıkça otomatik olarak hareket ederler.

"> =" Kısıtı eklemek, UILabel için minimum genişliği ayarlar:

resim açıklamasını buraya girin


16

Metni düğmenin aksine yeniden boyutlandırmak istiyorsanız, şunu kullanabilirsiniz ...

button.titleLabel.adjustsFontSizeToFitWidth = YES;
button.titleLabel.minimumScaleFactor = .5;
// The .5 value means that I will let it go down to half the original font size 
// before the texts gets truncated

// note, if using anything pre ios6, you would use I think
button.titleLabel.minimumFontSize = 8;

3
* ayarlarFontSizeToFitWidth
Daniel Bang

8

sizeToFit düzgün çalışmıyor. yerine:

myButton.size = myButton.sizeThatFits(CGSize.zero)

ayrıca contentInsetdüğmeye ekleyebilirsiniz :

myButton.contentEdgeInsets = UIEdgeInsetsMake(8, 8, 4, 8)


SizeToFit: // ile ilgili Apple dokümanlarından sizeThatFits: geçerli görünüm sınırları ve sınırların boyutunu değiştirir. Bu yüzden düzgün çalışır, daha sonra metni ayarlamanız gerekir.
Markus

5

basitçe:

  1. UIViewGörüntülemek için otomatik düzen ile sarıcı olarak oluşturun .
  2. Sargının UILabeliçine koy . Etiketinizi ambalajın kenarlarına yapıştıracak kısıtlamalar ekleyin.
  3. Paketleyicinizin UIButtoniçine koyun , daha sonra yaptığınız kısıtlamaları basitçe ekleyin UILabel.
  4. Metinle birlikte otomatik boyutlu düğmenizin keyfini çıkarın.

1
Bu erişilebilirlikle iyi oynuyor mu?
2018

4

Hızlı 4.2

Şükürler olsun, bu çözüldü. Düğmeye bir metin ayarladıktan sonra, bir UIView'dan doğal boyut olan intrinsicContentSize'ı alabilirsiniz (resmi belge burada ). UIButton için aşağıdaki gibi kullanabilirsiniz.

button.intrinsicContentSize.width

Bilginiz için, düzgün görünmesi için genişliği ayarladım.

button.frame = CGRect(fx: xOffset, y: 0.0, width: button.intrinsicContentSize.width + 18, height: 40)

Simülatör

İntrinsicContentSize ile UIButtonları

Kaynak: https://riptutorial.com/ios/example/16418/get-uibutton-s-size-strictly-based-on-its-text-and-font


1
Biraz daha bağlam verebilir misiniz? Kod satırınız sorudaki kodla nasıl ilişkilidir? Önerdiğiniz kodun ne yaptığını da özetleyebilir misiniz? Bağlantıyı yalnızca açıklama olarak sunmak bu site için doğru biçim değildir ( nedenlerle meta.stackexchange.com/a/8259/266197 adresine bakın ), ancak bazı açıklamalar ve bağlamlar eklerseniz cevabınız daha değerli hale gelir!
NOhs

3

Çözülmeyen bu yazı ile ilgili bazı ek gereksinimlerim var sizeToFit. Metinden bağımsız olarak düğmeyi orijinal konumunda tutmam gerekiyordu. Düğmenin asla orijinal boyutundan daha büyük olmasını da istemiyorum.

Bu nedenle, düğmeyi maksimum boyutuna göre düzenler, bu boyutu Denetleyiciye kaydeder ve metin değiştiğinde düğmeyi boyutlandırmak için aşağıdaki yöntemi kullanırım:

+ (void) sizeButtonToText:(UIButton *)button availableSize:(CGSize)availableSize padding:(UIEdgeInsets)padding {    

     CGRect boundsForText = button.frame;

    // Measures string
    CGSize stringSize = [button.titleLabel.text sizeWithFont:button.titleLabel.font];
    stringSize.width = MIN(stringSize.width + padding.left + padding.right, availableSize.width);

    // Center's location of button
    boundsForText.origin.x += (boundsForText.size.width - stringSize.width) / 2;
    boundsForText.size.width = stringSize.width;
    [button setFrame:boundsForText];
 }

1

Metin için yükseklik otomatik olarak boyutlandırılan bu düğme sınıfı (Xamarin için ancak başka bir dil için yeniden yazılabilir)

[Register(nameof(ResizableButton))]
public class ResizableButton : UIButton
{
    NSLayoutConstraint _heightConstraint;
    public bool NeedsUpdateHeightConstraint { get; private set; } = true;

    public ResizableButton(){}

    public ResizableButton(UIButtonType type) : base(type){}

    public ResizableButton(NSCoder coder) : base(coder){}

    public ResizableButton(CGRect frame) : base(frame){}

    protected ResizableButton(NSObjectFlag t) : base(t){}

    protected internal ResizableButton(IntPtr handle) : base(handle){}

    public override void LayoutSubviews()
    {
        base.LayoutSubviews();
        UpdateHeightConstraint();
        InvalidateIntrinsicContentSize();
    }

    public override void SetTitle(string title, UIControlState forState)
    {
        NeedsUpdateHeightConstraint = true;
        base.SetTitle(title, forState);
    }

    private void UpdateHeightConstraint()
    {
        if (!NeedsUpdateHeightConstraint)
            return;
        NeedsUpdateHeightConstraint = false;
        var labelSize = TitleLabel.SizeThatFits(new CGSize(Frame.Width - TitleEdgeInsets.Left - TitleEdgeInsets.Right, float.MaxValue));

        var rect = new CGRect(Frame.X, Frame.Y, Frame.Width, labelSize.Height + TitleEdgeInsets.Top + TitleEdgeInsets.Bottom);

        if (_heightConstraint != null)
            RemoveConstraint(_heightConstraint);

        _heightConstraint = NSLayoutConstraint.Create(this, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1, rect.Height);
        AddConstraint(_heightConstraint);
    }

     public override CGSize IntrinsicContentSize
     {
         get
         {
             var labelSize = TitleLabel.SizeThatFits(new CGSize(Frame.Width - TitleEdgeInsets.Left - TitleEdgeInsets.Right, float.MaxValue));
             return new CGSize(Frame.Width, labelSize.Height + TitleEdgeInsets.Top + TitleEdgeInsets.Bottom);
         }
     }
}

1

Nedense func sizeToFit()benim için çalışmıyor. Benim kurulumum içinde bir düğme kullanıyorumUITableViewCell kullanıyorum ve otomatik düzen kullanıyorum.

Benim için işe yarayan:

  1. genişlik sınırını getir
  2. intrinsicContentSizegenişliği almak çünkü bu belgeye göre otomatik düzen farkında değildir intrinsicContentSize. Genişlik kısıtlaması ayarlama intrinsicContentSizegenişliği

resim açıklamasını buraya girin

İşte iki başlık: Debug View Hierachry resim açıklamasını buraya girin

resim açıklamasını buraya girin


0

Dürüst olmak gerekirse, film şeridinde metni yerleştirmek için düğmeleri yeniden boyutlandırmak istediğinizi söylemek için basit bir onay kutusunun bulunmaması gerçekten utanç verici. Pekala, her neyse.

İşte storyboard kullanan en basit çözüm.

  1. UIView yerleştirin ve bunun için kısıtlamalar koyun. Misal: resim açıklamasını buraya girin
  2. UILabel'i UIView içine yerleştirin. UIView kenarlarına iliştirmek için kısıtlamalar ayarlayın.

  3. UIButton'unuzu UIView içine yerleştirin. UIView'in kenarlarına takmak için aynı kısıtlamaları ayarlayın.

  4. UILabel'in satır sayısı için 0 ayarlayın. resim açıklamasını buraya girin

  5. Çıkışları ayarlayın.

    @IBOutlet var button: UIButton!
    @IBOutlet var textOnTheButton: UILabel!
  1. Uzun, uzun, uzun bir başlık al.

    let someTitle = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
  1. ViewDidLoad üzerinde başlığı UILabel ve UIButton için ayarlayın.

    override func viewDidLoad() {
        super.viewDidLoad()
        textOnTheButton.text = someTitle
        button.setTitle(someTitle, for: .normal)
        button.titleLabel?.numberOfLines = 0
    }
  1. Düğmenin yeniden boyutlandırıldığından ve basılabildiğinden emin olmak için çalıştırın.

resim açıklamasını buraya girin

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.