Otomatik yerleşim - UIButton'un gerçek boyutu başlık eklerini içermez


196

Otomatik yerleşim kullanarak düzenlenmiş bir UIButtonum varsa, boyutu içeriğine uyacak şekilde güzelce ayarlanır.

Bir görüntüyü olarak ayarlarsam button.image, içsel boyut yine bunu hesaba katar.

Ancak, titleEdgeInsetsdüğmenin ayarını yaparsam , düzen bunu hesaba katmaz ve bunun yerine düğme başlığını keser.

Düğmenin iç genişliğinin iç metinleri hesaba katmasını nasıl sağlayabilirim?

resim açıklamasını buraya girin

Düzenle:

Aşağıdakileri kullanıyorum:

[self.backButton setTitleEdgeInsets:UIEdgeInsetsMake(0, 5, 0, 0)];

Amaç, görüntü ile metin arasına bir miktar ayrım eklemektir.


3
Bunu bir radar olarak dosyaladın mı? Kesinlikle UIButton'un içsel boyut hesaplamalarında bir hata gibi görünüyor.
Ryan Poolos

1
Bir radar yayınlamaya hazırdım, ama bu aslında beklenen bir davranış gibi görünüyor. Bu, UIButton'un * EdgeInsets özelliklerinde belgelenmiştir : "Belirttiğiniz iç metinler, bu dikdörtgen düğmenin metnine sığacak şekilde boyutlandırıldıktan sonra başlık dikdörtgenine uygulanır. Bu nedenle, pozitif iç metin değerleri başlık metnini kırpabilir. [...] düğmesi intrinsicContentSize ve sizeThatFits öğelerini belirlemek için bu özelliği kullanmaz: "
Guillaume Algis

7
Bunun belirtilen davranış olmasına rağmen, bu iddia ediyorum @GuillaumeAlgis değil bir autolayout kullanırken gerçekleşmesini beklediğiniz hiç. Bir hata dosyaladım ve başkalarını da bir dosya açmaya teşvik ediyorum.
memmons

Buradaki radar hatasına bağlanabilirseniz, üzerine tıklayabilir ve üzerine +1 koyabilir miyiz?
gprasant

1
dan titleEdgeInsetbelgeler: The insets you specify are applied to the title rectangle after that rectangle has been sized to fit the button’s text. Thus, positive inset values may actually clip the title text. Yani girinti ekleyerek kesin klibi metin için düğmeye zorluyor
Marco PAPPALARDO

Yanıtlar:


192

Bunu herhangi bir yöntemi geçersiz kılmak veya rastgele bir genişlik kısıtlaması ayarlamak zorunda kalmadan çözebilirsiniz. Hepsini Interface Builder'da aşağıdaki gibi yapabilirsiniz.

  • İçsel düğme genişliği başlık genişliği artı simge genişliği artı sol ve sağ içerik kenarı iç metinlerinden türetilir .

  • Bir düğmenin hem resmi hem de metni varsa, aralarında dolgu olmadan bir grup olarak ortalanırlar.

  • Sol içerik iç metin eklerseniz, metin + simgesine değil metne göre hesaplanır.

  • Negatif bir sol görüntü eki ayarlarsanız, görüntü sola çekilir ancak toplam düğme genişliği etkilenmez.

  • Negatif bir sol görüntü eki ayarlarsanız, gerçek düzen bu değerin yarısını kullanır. Bu nedenle, -20 punto sol iç metin elde etmek için, Arayüz Oluşturucu'da -40 nokta sol iç metin değeri kullanmanız gerekir.

Böylece, hem istenen sol iç metin hem de simgenin ile metin arasında istediğiniz doldurma miktarını iki katına bıraktığı simgesine simgesi ve metin arasındaki iç dolgusu ve ardından kayması. Sonuç, eşit sol ve sağ içerik girişlerine sahip bir düğme ve grup olarak ortalanmış, aralarında belirli miktarda dolgu bulunan bir metin ve simge çiftidir.

Bazı örnek değerler:

// Produces a button with the layout:
// |-20-icon-10-text-20-|
// AutoLayout intrinsic width works as you'd desire.
button.contentEdgeInsets = UIEdgeInsetsMake(10, 30, 10, 20)
button.imageEdgeInsets = UIEdgeInsetsMake(0, -20, 0, 0)

neden gerçek düzen negatif sol iç metin değerinin yarısını kullanıyor ?? Aynı sorunla karşılaştım!
Tony Lin

1
Bir çözüm olması harika, ama umarım bu garip davranışı haklı çıkarmak için kullanılmaz UIButton.
funct7

205

Negatif ve pozitif Başlık ve İçerik Ekleri birleşimini kullanarak Arayüz Oluşturucu'da (herhangi bir kod yazmadan) çalışmasını sağlayabilirsiniz.

resim açıklamasını buraya girin

Güncelleme : Xcode 7, RightAnkastre alanına negatif değerler giremeyeceğiniz bir hataya sahip , ancak değeri azaltmak için yanındaki step kontrolünü kullanabilirsiniz. (Teşekkürler Stuart)

Bunu yapmak, görüntü ve başlık arasında 8pt boşluk ekleyecek ve düğmenin iç genişliğini aynı miktarda artıracaktır. Bunun gibi:

resim açıklamasını buraya girin


2
Otomatik yerleşimin düğme genişliğini artırmasına izin vermek için contentEdgeInsets (buggy olmayan) kullanıyor. Etiketi sağdaki boş yere taşıyın. Başlık kenarı iç metin hatasını düzeltmenin akıllı yolu.
ugur

7
Bu hile artık çalışmıyor. Arayüz oluşturucu artık Rightalanda negatif değerleri kabul etmiyor .
Joris Mans

7
@JorisMans Sen olamaz yazın negatif değerler, ancak zorunlu negatif değer ... go rakama istifa metin alanının sağ step denetimini kullanarak benim için çalıştı!
Stuart

3
Bu ilk cevap olmalı, neden burada? Bunu bulmadan önce diğer 5'i de denedim ...
Lord Zsolt

2
Metni UIButton'da ortalamak için 16 içerik girme
hakkını sağladım

96

Neden intrinsicContentSizeUIView'daki yöntemi geçersiz kılmıyorsunuz? Örneğin:

- (CGSize) intrinsicContentSize
{
    CGSize s = [super intrinsicContentSize];

    return CGSizeMake(s.width + self.titleEdgeInsets.left + self.titleEdgeInsets.right,
                      s.height + self.titleEdgeInsets.top + self.titleEdgeInsets.bottom);
}

Bu, otomatik yerleştirme sistemine, eklere izin vermek ve tam metni göstermek için düğmenin boyutunu artırması gerektiğini söylemelidir. Kendi bilgisayarımda değilim, bu yüzden bunu test etmedim.


1
Düğmeler bildiğim kadar geçersiz kılınmamalıdır. Sorun, her düğme türünün farklı bir alt sınıf tarafından uygulanmasıdır.
Sulthan

2
intrinsicContentSizeUIView üzerinde bir yöntemdir, UIButton değil, bu yüzden herhangi bir UIButton yönteminde karışıklık olmazsınız. Apple bunun bir sorun olduğunu düşünmüyor: "Bu yöntemin geçersiz kılınması, özel bir görünümün içeriğine dayanarak hangi boyutta olmasını istediğini düzen sistemine iletmesine izin verir." Ve OP farklı düğmeler hakkında hiçbir şey söylemedi, sadece bir tane.
Maarten

1
Bu kesinlikle işe yarıyor ve gittiğim çözüm. intrinsicContentSizeUIView üzerinde bir yöntemdir ve UIButton, UIView'in bir alt sınıfıdır, bu yüzden elbette bu yöntemi geçersiz kılabilirsiniz; Apple'ın belgelerinde hiçbir şey yapmamanız gerektiğini söylemiyor. Maarten'ın geçersiz kılınmış yöntemini kullanarak bir UIButton alt sınıfı yapın ve Interface Builder'daki UIButton'unuzu YourUIButtonSubclass türünde olacak şekilde değiştirin ve mükemmel şekilde çalışacaktır.
n8tr

37
Bana intrinsicContentSizeUIButton başlığında eklemek gibi görünüyorEdgeInsets , ben Apple ile bir hata dosya olacak.
progrmr

6
Kabul ediyorum ve aynısı imageEdgeInsets için.
Ricardo Sanchez-Saez

87

Ekleri nasıl ayarladığınızı belirtmediniz, bu yüzden elde ettiğiniz etkiyi gördüğüm için titleEdgeInsets kullandığınızı tahmin ediyorum. Bunun yerine contentEdgeInsets kullanırsam düzgün çalışır.

- (IBAction)ChangeTitle:(UIButton *)sender {
    self.button.contentEdgeInsets = UIEdgeInsetsMake(0,20,0,20);
    [self.button setTitle:@"Long Long Title" forState:UIControlStateNormal];
}

Gerçekten titleEdgeInsets kullanıyorum. Başlığı resimden değil, düğmenin kenarından değil. Belki de içinde biraz dolgu bulunan bir resim kullanmalıyım? Gerçi deli gibi görünüyor.
Ben Packard

Bu, otomatik düzenleme ile birlikte mükemmel çalışır, teşekkür ederim!
Cal S

3
Bu daha iyi bir çözümdür, çünkü intrinsicContentSize'a dokunmadan tam olarak istediğinizi yapar.
RyJ

28
Bu, bir görüntü kullanırken ve görüntü ile başlık arasındaki iç metni ayarlamanız gerektiğinde soruyu yanıtlamaz!
Brody Robertson

24

Ve Swift için bunu çalıştı:

extension UIButton {
    override open var intrinsicContentSize: CGSize {
        let intrinsicContentSize = super.intrinsicContentSize

        let adjustedWidth = intrinsicContentSize.width + titleEdgeInsets.left + titleEdgeInsets.right
        let adjustedHeight = intrinsicContentSize.height + titleEdgeInsets.top + titleEdgeInsets.bottom

        return CGSize(width: adjustedWidth, height: adjustedHeight)
    }
}

Aşk U Swift


1
Gerekmese de, bu durumda alt sınıfta bulunmak daha iyidir, çünkü Apple dokümanları, içsel boyutun hesaplamasına titleEdgeInsets içermediğini açıkça belirtmektedir ve bu nedenle bir uzantı kullanarak sadece Apple'ın beklentilerini değil, okuyan diğer tüm geliştiricileri ihlal ediyorsunuz dokümanlar.
Sirenler

18

Bu iplik biraz eski, ama ben sadece kendim bu koştu ve negatif bir iç metin kullanarak çözmeyi başardı. Örneğin, istediğiniz dolgu değerlerini buraya yazın:

UIButton* myButton = [[UIButton alloc] init];
// setup some autolayout constraints here
myButton.titleEdgeInsets = UIEdgeInsetsMake(-desiredBottomPadding,
                                            -desiredRightPadding,
                                            -desiredTopPadding,
                                            -desiredLeftPadding);

Doğru otomatik düzenleme kısıtlamaları ile birlikte, bir resim ve metin içeren otomatik yeniden boyutlandırma düğmesi ile sonuçlanırsınız! Aşağıda desiredLeftPadding10 olarak ayarlanmış olarak görülüyor .

Görüntü ve kısa metin düğmesi

Görüntü ve uzun metin düğmesi

Düğmenin gerçek çerçevesinin etiketi içermediğini görebilirsiniz (etiket 10 sınır sağa, sınırların dışına kaydırıldığından), ancak metin ve resim arasında 10 nokta dolgusu elde ettik.


1
Alt sınıf gerektirmediği için kullandığım çözüm bu. Düğmenizin arka planı varsa işe yaramaz, ancak bu genellikle iOS 7 ile ilgili bir sorun değildir
José Manuel Sánchez

Düğmenin içerik dengesini de ayarladıysanız (pozitif değer> = başlık eki) bu bir arka plan resmiyle çalışır.
Ben Flynn

9

For Swift 3 dayanan pegpeg 'ın cevabı:

extension UIButton {

    override open var intrinsicContentSize: CGSize {

        let intrinsicContentSize = super.intrinsicContentSize

        let adjustedWidth = intrinsicContentSize.width + titleEdgeInsets.left + titleEdgeInsets.right
        let adjustedHeight = intrinsicContentSize.height + titleEdgeInsets.top + titleEdgeInsets.bottom

        return CGSize(width: adjustedWidth, height: adjustedHeight)

    }

}

Merhaba. interfacebuilder özel uzatma düğmesini kullanmak istiyorum. plz yardım
kemdo

6

Yukarıdakilerin hepsi iOS 9+ için çalışmadı, yaptığım şey:

  • Bir genişlik kısıtlaması ekleyin (düğmenin metni yoksa minimum genişlik için. Metin sağlanırsa düğme otomatik olarak ölçeklenir)
  • ilişkiyi Büyük veya Eşit olarak ayarlama

resim açıklamasını buraya girin

Şimdi düğmenin etrafına bir kenarlık eklemek için sadece yöntemi kullanın:

button.contentEdgeInsets = UIEdgeInsetsMake(0,20,0,20);

Neden olmasın? İçeriği otomatik olarak ölçeklendirir, yalnızca minimum genişlik ayarlamanız gerekir (görüntülenecek metinden daha küçük olabilir)
Oritm

Çünkü minimum genişliği tanımlarsınız. Otomatik düzenleme fikri, açık (minimum) genişlik ayarlamadan yapılmasıdır.
Joris Mans

Genişliği ile ilgili değil, isterseniz genişliği 1 olarak ayarlayabilirsiniz, ancak otomatik yerleşim genişliğin eşit veya daha fazla olabileceğini bilmelidir . Cevabımı güncelledim
Oritm

Genişlik sınırlamasına hiç ihtiyacınız yoktur, contentEdgeInset anahtardır, otomatik düzen daha sonra içsel içerik boyutu için bunu kullanır.
Chris Conover

5

UIButton simgesi ile etiket arasına 5pt boşluk eklemek istedim. Bunu nasıl başardım:

UIButton *infoButton = [UIButton buttonWithType:UIButtonTypeCustom];
// more button config etc
infoButton.contentEdgeInsets = UIEdgeInsetsMake(0, 0, 0, 5);
infoButton.titleEdgeInsets = UIEdgeInsetsMake(0, 5, 0, -5);

ContentEdgeInsets, titleEdgeInsets ve imageEdgeInsets'in birbiriyle ilişkili şekli, her bir girişten biraz vermek ve almak gerektirir. Bu nedenle, başlığın soluna bazı ekler eklerseniz, sağa negatif iç metin eklemeniz ve sağdaki içeriğe biraz daha fazla alan (pozitif bir ek yoluyla) sağlamanız gerekir.

Başlık iç metinlerinin kaymasıyla eşleşecek doğru bir içerik iç metin ekleyerek metnim düğmenin sınırları dışına çıkmıyor.


3

Bu seçenek arayüz oluşturucuda da mevcuttur. Ek'e bakınız. Sol ve sağ 3 olarak ayarladım. Bir cazibe gibi çalışır.

Interface builder ekran görüntüsü


1
Evet, bu cevabın açıkladığı gibi, çalışmasının nedeni Edge: Title veya Edge: Image yerine Edge: Content ayarını yapmanızdır .
smileyborg

1

Kullandığım çözüm, düğmeye bir genişlik kısıtlaması eklemektir. Ardından, başlangıçta bir yerde, metniniz ayarlandıktan sonra genişlik sınırlamasını şu şekilde güncelleyin:

self.buttonWidthConstraint.constant = self.shareButton.intrinsicContentSize.width + 8;

Nerede olursa olsun 8 nerede.


ButtonWidthConstraint nedir?
Alexey Golikov


1
Bu harika bir çözüm değildir, çünkü düğmenin gerçek içerik boyutu değişirse, düğmeyi manuel olarak güncellemeniz gerekir. constant kısıtlamanın değerini yeni değere ... ve düğmenin gerçek içerik boyutunun ne zaman değiştiğini bilmek gerekir düğmeyi alt sınıflamadan.
smileyborg

Ayup. Artık bu yöntemi kullanmıyorum. Aşağı oylamaya layıktı ama ¯_ (ツ) _ / ¯
Bob Spryn

setNeedsUpdateConstraintsDüğme başlığı veya resmi güncellendikten sonra "manuel" olarak arama yapılabilir. Daha sonra oradan sabitini geçersiz kılabilir updateConstraintsve yeniden hesaplayabilirsiniz buttonWidthConstraint. Bu mutlaka en iyi yaklaşım değildir, ancak benim için yeterince iyi çalışır. YMMV;)
Olivier

1

sizeToFit () öğesinin çağrılması, contentEdgeInset öğesinin etkinleştirilmesini sağlar

extension UIButton {

   open override func draw(_ rect: CGRect) { 
       self.contentEdgeInsets = UIEdgeInsets(top: 10, left: 40, bottom: 10, right: 40)
       self.sizeToFit()
   }
}

Soru hakkındatitleEdgeInsets
androidguy
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.