Autolayout - Wewnętrzny rozmiar UIButton nie zawiera wstawek tytułu

Jeśli mam UIButton ustawiony za pomocą autolayout, jego rozmiar ładnie dopasowuje się do jego zawartości.

Jeśli ustawię obraz jako button.image, rozmiar instrinsic ponownie wydaje się to tłumaczyć.

Jeśli jednak poprawię titleEdgeInsets przycisku, układ nie uwzględnia tego i zamiast tego obcina tytuł przycisku.

Jak mogę upewnić się, że wewnętrzna szerokość przycisku odpowiada wstawce?

Tutaj wpisz opis obrazka

Edit:

Używam "po": {]}

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

Celem jest dodanie pewnej separacji między obrazem a tekstem.

Author: Astoria, 2013-07-23

11 answers

Można rozwiązać ten problem bez konieczności nadpisywania metod lub ustawiania ograniczeń szerokości. Możesz to zrobić w interfejsie Builder w następujący sposób.

  • Wewnętrzna szerokość przycisku pochodzi od szerokości tytułu plus szerokości ikony oraz lewej i prawej zawartości wstawek krawędzi.

  • Jeśli przycisk ma zarówno obraz, jak i tekst, są one wyśrodkowane jako grupa, bez odstępów między nimi.

  • Jeśli dodasz lewą wstawkę zawartości, będzie ona obliczana względnie do tekstu, a nie do ikony tekst+.

  • Jeśli ustawisz ujemną lewą wstawkę obrazu, obraz zostanie wyciągnięty w lewo, ale nie ma to wpływu na ogólną szerokość przycisku.

  • Jeśli zostanie ustawiona ujemna lewa wstawka obrazu, rzeczywisty układ będzie używał połowy tej wartości. Aby uzyskać wstawkę -20 punktów w lewo, musisz użyć wartości wstawki -40 punktów w Builderze interfejsu.

Więc podajesz wystarczająco duży lewy wkład zawartości, aby utworzyć miejsce dla obu żądanych lewych wkładek i wewnętrzne wypełnienie między ikoną a tekstem, a następnie przesuń ikonę w lewo, podwajając żądaną ilość wypełnienia między ikoną a tekstem. Rezultatem jest przycisk z równymi wstawkami zawartości po lewej i prawej stronie oraz para tekstu i ikon, które są wyśrodkowane jako grupa, z określoną ilością wypełnień między nimi.

Niektóre przykładowe wartości:

// 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)
 126
Author: jaredsinclair,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-13 20:32:03

Możesz to uruchomić w Kreatorze interfejsów (bez pisania kodu), używając kombinacji negatywnego i pozytywnego tytułu oraz wstawek treści.

Tutaj wpisz opis obrazka

Aktualizacja: Xcode 7 ma błąd, w którym nie można wprowadzić wartości ujemnych w polu Wstaw Right, ale można użyć kontrolki krokowej obok, aby zmniejszyć wartość. (Thanks Stuart)

Spowoduje to dodanie 8PT odstępu między obrazkiem a tytułem i zwiększy wewnętrzną szerokość przycisku o taką samą kwotę. Tak:

Tutaj wpisz opis obrazka

 164
Author: n.Drake,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-22 10:01:51

Dlaczego nie przesłaniać metody intrinsicContentSize w UIView? Na przykład:

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

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

To powinno powiedzieć systemowi autolayout, że powinien zwiększyć rozmiar przycisku, aby umożliwić wstawianie i pokazać pełny tekst. Nie mam własnego komputera, więc tego nie testowałem.

 90
Author: Maarten,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-22 12:57:11

Nie sprecyzowałeś, jak ustawiasz wstawki, więc zgaduję, że używasz titleEdgeInsets, ponieważ widzę ten sam efekt, który otrzymujesz. Jeśli używam contentEdgeInsets zamiast tego działa poprawnie.

- (IBAction)ChangeTitle:(UIButton *)sender {
    self.button.contentEdgeInsets = UIEdgeInsetsMake(0,20,0,20);
    [self.button setTitle:@"Long Long Title" forState:UIControlStateNormal];
}
 82
Author: rdelmar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-23 03:06:26

Ten wątek jest trochę stary, ale sam na to wpadłem i byłem w stanie rozwiązać go za pomocą negatywnego wstawki. Na przykład, zastąp żądane wartości wypełnienia tutaj:

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

W połączeniu z odpowiednimi ograniczeniami autolayout, kończysz z przyciskiem automatycznej zmiany rozmiaru, który zawiera obraz i tekst! Zobacz poniżej z desiredLeftPadding ustawionym na 10.

Przycisk z obrazkiem i krótkim tekstem

Przycisk z obrazkiem i długim tekstem

Widać, że rzeczywisty ramka przycisku nie obejmuje etykiety (ponieważ etykieta jest przesunięta o 10 punktów w prawo, poza granice), ale osiągnęliśmy 10 punktów wypełnienia między tekstem a obrazem.

 18
Author: Brian Gerstle,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-18 02:50:58

I dla Swift pracował to:

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)
    }
}

Love U Swift

 14
Author: pegpeg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-29 02:18:21

Wszystko powyżej nie działało dla iOS 9+, to co zrobiłem to:

  • Dodaj ograniczenie szerokości (dla minimalnej szerokości, gdy przycisk nie ma żadnego tekstu. Przycisk będzie automatycznie skalowany, jeśli zostanie podany tekst)
  • Ustaw relację na większą lub równą

Tutaj wpisz opis obrazka

Teraz, aby dodać obramowanie wokół przycisku, użyj metody:

button.contentEdgeInsets = UIEdgeInsetsMake(0,20,0,20);
 7
Author: Oritm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-07 12:43:30

Dla Swift 3 na podstawie pegpeg ' s odpowiedź:

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)

    }

}
 6
Author: TheoK,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-10 13:24:06

Opcja jest również dostępna w interface builder. Zobacz też Ustawiłem lewo i prawo na 3. Działa jak urok.

Interface builder zrzut ekranu

 3
Author: zeiteisen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-03 14:26:02

Chciałem dodać odstęp 5pt pomiędzy ikoną UIButton a etykietą. Tak to osiągnąłem:

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

Sposób, w jaki contentEdgeInsets, titleEdgeInsets i imageEdgeInsets odnoszą się do siebie, wymaga trochę dawania i brania od każdego wstawki. Więc jeśli dodasz jakieś wstawki do tytułu po lewej stronie, musisz dodać wstawkę negatywną po prawej stronie i zapewnić trochę więcej miejsca (poprzez wstawkę pozytywną) NA treści po prawej stronie.

Poprzez dodanie odpowiedniego wstawki treści, aby dopasować przesunięcie tytułu Wstaw mój tekst nie wychodzi poza granice przycisku.

 2
Author: orj,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-19 07:36:46

Rozwiązaniem, którego używam, jest dodanie ograniczenia szerokości na przycisku. Następnie gdzieś w inicjalizacji, po ustawieniu tekstu, zaktualizuj ograniczenie szerokości w następujący sposób:

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

Gdzie 8 jest tym, czym jest twoja wstawka.

 1
Author: Bob Spryn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-29 06:00:23