iPhone UIButton - положення зображення


116

У мене є UIButtonтекст "Дослідіть додаток" і UIImage(>) Interface BuilderВін виглядає так:

[ (>) Explore the app ]

Але мені потрібно розмістити це UIImageПІСЛЯ тексту:

[ Explore the app (>) ]

Як я можу рухатись UIImageправоруч?


Ви також можете використовувати Interface Builder. Перевірте моя відповідь тут: stackoverflow.com/questions/2765024 / ...
n8tr

1
Просто використовуйте цей підклас з кількома рядками коду: github.com/k06a/RTLButton
k06a

Відповіді:


161

Моє рішення цього питання досить просте

[button sizeToFit];
button.titleEdgeInsets = UIEdgeInsetsMake(0, -button.imageView.frame.size.width, 0, button.imageView.frame.size.width);
button.imageEdgeInsets = UIEdgeInsetsMake(0, button.titleLabel.frame.size.width, 0, -button.titleLabel.frame.size.width);

4
Це чудово працює! Важко зрозуміти концепцію крайової вставки. Будь-яка ідея, чому нам потрібно встановити як лівий, так і правий край вставки? Теоретично, якщо я переміщу заголовок вліво і зображення вправо, цього було б достатньо. Чому мені потрібно встановити і лівий, і правий?
PokerIncome.com

3
НАЙКРАЩЕ РІШЕННЯ Я
ЗНАЙДУ

2
Ця відповідь прекрасно працює. Прийнята відповідь правильна і вказує на правильні документи API, але це рішення копіювання та вставки, щоб зробити те, про що вимагав ОП.
mclaughlinj

Стає трохи складніше, коли ви починаєте змінювати текст кнопки. Підкласне рішення працювало для мене краще в цьому випадку.
Бред Госс

Дякую, що показали мені, що потрібно застосовувати однакові ширини до лівої та правої сторони, я не знаю на 100%, як це працює (бо іноді це впливатиме на розмір, а також на походження), але мені вдалося вирішити подібні проблеми використовуючи цей метод.
Тобі

128

На iOS 9 і далі здається, що простий спосіб досягти цього - змусити семантичну думку.

введіть тут опис зображення

Або програмно, використовуючи:

button.semanticContentAttribute = .ForceRightToLeft

4
Наскільки мені сподобалась ваша відповідь (+1), я ненавиджу сказати, що це може бути не "правильний" спосіб зробити це, але це один із найпростіших.
farzadshbfn

@farzadshbfn ви праві. Я змінив це слово на «просте», здається більш послідовним.
Альвіві

@farzadshbfn Чому це не був би "правильний" спосіб зробити?
Самман Бікрам Тапа

3
@SammanBikramThapa IMHO правильним способом було б підкласифікувати UIButton та переосмислити layoutSubviews та повагу semanticContentAttributeдо нашої логіки компонування, замість зміни semanticContentAttributeсебе. (зміна семантичного підходу, не буде добре працювати з інтернаціоналізацією)
farzadshbfn

@farzadshbfn абсолютно прав. Незважаючи на те, що ця відповідь набирає більшість балів, вона невірна - це може порушити UX для правого лівого інтерфейсу.
Павло Якименко

86

Встановіть imageEdgeInsetта titleEdgeInsetпереміщуйте компоненти навколо зображення. Ви також можете створити кнопку, використовуючи графіку, що має повний розмір, і використовувати її як фонове зображення для кнопки (потім використовуйте titleEdgeInsetsдля переміщення заголовка навколо).


8
Набагато менше коду просто встановити вставки, ніж реалізувати підклас. У цьому вся суть вставки. Маніпулювання кадрами для поданих подань (які ви ще не створили) більше схоже на злом.
Кім Андре Сенд

6
@kimsnarf, справді? Це набагато менше роботи (і менше злому), щоб підправити вставки, коли ви зробите незначну зміну розміру зображення або довжини заголовка?
Кірк Волл

54

Відповідь Реймонда У найкраще тут. Підклас UIButton з користувацьким layoutSubviews. Це надзвичайно просто, ось реалізація layoutSubviews, яка працювала для мене:

- (void)layoutSubviews
{
    // Allow default layout, then adjust image and label positions
    [super layoutSubviews];

    UIImageView *imageView = [self imageView];
    UILabel *label = [self titleLabel];

    CGRect imageFrame = imageView.frame;
    CGRect labelFrame = label.frame;

    labelFrame.origin.x = imageFrame.origin.x;
    imageFrame.origin.x = labelFrame.origin.x + CGRectGetWidth(labelFrame);

    imageView.frame = imageFrame;
    label.frame = labelFrame;
}

2
Цей спосіб краще в тому випадку, якщо вам потрібно керувати багатьма кнопками, але мені потрібно змінити лише одну кнопку :)
Павло Якименко

2
Якщо зображення кнопки є нульовим, результати мітки неправильно розміщені, ймовірно, тому, що UIImageView не вставляється (випробувано на iOS6.0). Вам слід розглянути можливість редагування кадрів, лише якщо imageView.image не дорівнює нулю.
Скакко

2
Я запропонував би наступне вдосконалення цієї відповіді, щоб обидва погляди залишалися в центрі: 'CGFloat cumulativeWidth = CGRectGetWidth (imageFrame) + CGRectGetWidth (labelFrame) + 10; CGFloat tooWidth = CGRectGetWidth (self.bounds) - накопичувальна ширина; labelFrame.origin.x = overWidth / 2; imageFrame.origin.x = CGRectGetMaxX (labelFrame) + 10; '
i-konov

Це перерва на iOS 7 для мене. Будь-хто інший? Чудово працює на iOS 8.
rounak

1
Не підтримуйте iOS7 взагалі, і ваша проблема піде нанівець. Не варто підкріплювати це все одно.
Гіль Сенд

30

А як щодо підкласифікації UIButtonта переосмислення layoutSubviews?

Потім обробляйте місця self.imageView&self.titleLabel


4
Це набагато простіше, ніж усі інші поради (на зразок тієї, що описана вище) про спробу правильно розмістити все, використовуючи ручні налаштовані вставки.
Стівен Крамер

13

Ще один простий спосіб (тобто НЕ iOS 9) - це підклас UIButton для зміни цих двох методів

override func titleRectForContentRect(contentRect: CGRect) -> CGRect {
    var rect = super.titleRectForContentRect(contentRect)
    rect.origin.x = 0
    return rect
}

override func imageRectForContentRect(contentRect: CGRect) -> CGRect {
    var rect = super.imageRectForContentRect(contentRect)
    rect.origin.x = CGRectGetMaxX(contentRect) - CGRectGetWidth(rect)
    return rect
}

contentEdgeInsets вже враховується за допомогою супер.


Дякую! Мені це подобається набагато більше, ніж відповіді, які підклас та переосмислення макетаSubviews () :)
Джо Суснік

1
На мій скромний погляд, найкращий спосіб зробити це :)
DrPatience

9

Примушувати кнопку "справа наліво" для кнопки - це не варіант, якщо ваш додаток підтримує і "зліва направо", і "справа наліво".

Для мене працювало рішення - підклас, який можна додати до кнопки на дошці розкадрувань і добре працює з обмеженнями (перевірено в iOS 11):

class ButtonWithImageAtEnd: UIButton {

    override func layoutSubviews() {
        super.layoutSubviews()

        if let imageView = imageView, let titleLabel = titleLabel {
            let padding: CGFloat = 15
            imageEdgeInsets = UIEdgeInsets(top: 5, left: titleLabel.frame.size.width+padding, bottom: 5, right: -titleLabel.frame.size.width-padding)
            titleEdgeInsets = UIEdgeInsets(top: 0, left: -imageView.frame.width, bottom: 0, right: imageView.frame.width)
        }

    }

}

Де 'padding' буде пробілом між заголовком та зображенням.


Звичайно .forceRightToLeft, це варіант! Просто використовуйте протилежне значення ( .forceLeftToRight), якщо UIApplication.shared.userInterfaceLayoutDirection == .rightToLeft.
manmal

5

У Свіфті:

override func layoutSubviews(){
    super.layoutSubviews()

    let inset: CGFloat = 5

    if var imageFrame = self.imageView?.frame,
       var labelFrame = self.titleLabel?.frame {

       let cumulativeWidth = imageFrame.width + labelFrame.width + inset
       let excessiveWidth = self.bounds.width - cumulativeWidth
       labelFrame.origin.x = excessiveWidth / 2
       imageFrame.origin.x = labelFrame.origin.x + labelFrame.width + inset

       self.imageView?.frame = imageFrame
       self.titleLabel?.frame = labelFrame  
    }
}

4

Створення відповіді від @split ...

Відповідь є фантастичною, але вона ігнорує той факт, що кнопка може мати власні вставки зображення та заголовки краю, які були встановлені заздалегідь (наприклад, у розкадровці).

Наприклад, ви, можливо, захочете, щоб зображення містило трохи накладки зверху і внизу контейнера, але все ж перемістіть зображення в правій частині кнопки.

Я розширив концепцію цим методом:

- (void) moveImageToRightSide {
    [self sizeToFit];

    CGFloat titleWidth = self.titleLabel.frame.size.width;
    CGFloat imageWidth = self.imageView.frame.size.width;
    CGFloat gapWidth = self.frame.size.width - titleWidth - imageWidth;
    self.titleEdgeInsets = UIEdgeInsetsMake(self.titleEdgeInsets.top,
                                            -imageWidth + self.titleEdgeInsets.left,
                                            self.titleEdgeInsets.bottom,
                                            imageWidth - self.titleEdgeInsets.right);

    self.imageEdgeInsets = UIEdgeInsetsMake(self.imageEdgeInsets.top,
                                            titleWidth + self.imageEdgeInsets.left + gapWidth,
                                            self.imageEdgeInsets.bottom,
                                            -titleWidth + self.imageEdgeInsets.right - gapWidth);
}

2
// Get the size of the text and image
CGSize buttonLabelSize = [[self.button titleForState:UIControlStateNormal] sizeWithFont:self.button.titleLabel.font];
CGSize buttonImageSize = [[self.button imageForState:UIControlStateNormal] size];

// You can do this line in the xib too:
self.button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentRight;

// Adjust Edge Insets according to the above measurement. The +2 adds a little space 
self.button.imageEdgeInsets = UIEdgeInsetsMake(0, 0, 0, -(buttonLabelSize.width+2));
self.button.titleEdgeInsets = UIEdgeInsetsMake(0, 0, 0, buttonImageSize.width+2);

При цьому створюється кнопка вирівнювання праворуч, наприклад:

[           button label (>)]

Кнопка не регулює її ширину відповідно до контексту, тому пробіл з’явиться зліва від мітки. Ви можете вирішити це шляхом обчислення ширини рамки кнопки від кнопкиLabelSize.width та buttonImageSize.width.



0

Це рішення працює на iOS 7 і вище

Просто підклас UIButton

@interface UIButton (Image)

- (void)swapTextWithImage;

@end

@implementation UIButton (Image)

- (void)swapTextWithImage {
   const CGFloat kDefaultPadding = 6.0f;
   CGSize buttonSize = [self.titleLabel.text sizeWithAttributes:@{
                                                               NSFontAttributeName:self.titleLabel.font
                                                               }];

   self.titleEdgeInsets = UIEdgeInsetsMake(0, -self.imageView.frame.size.width, 0, self.imageView.frame.size.width);
   self.imageEdgeInsets = UIEdgeInsetsMake(0, buttonSize.width + kDefaultPadding, 0, -buttonSize.width); 
}

@end

Використання (десь у вашому класі):

[self.myButton setTitle:@"Any text" forState:UIControlStateNormal];
[self.myButton swapTextWithImage];

0

Спираючись на попередні відповіді. Якщо ви хочете мати поле між значком та заголовком кнопки, код має трохи змінитись, щоб запобігти плаванню мітки та піктограми над межами кнопок власного розміру.

let margin = CGFloat(4.0)
button.titleEdgeInsets = UIEdgeInsetsMake(0, -button.imageView.frame.size.width, 0, button.imageView.frame.size.width);
button.imageEdgeInsets = UIEdgeInsetsMake(0, button.titleLabel.frame.size.width, 0, -button.titleLabel.frame.size.width)
button.contentEdgeInsets = UIEdgeInsetsMake(0, margin, 0, margin)

Останній рядок коду важливий для власне обчислення розміру вмісту для автоматичного компонування.


0

Ось мій власний спосіб зробити це (приблизно через 10 років)

  1. Підклас від UIButton (кнопка, як ми живемо в епоху Свіфта)
  2. Поставте зображення та мітку у подання стека.
class CustomButton: Button {

    var didLayout: Bool = false // The code must be called only once

    override func layoutSubviews() {
        super.layoutSubviews()
        if !didLayout, let imageView = imageView, let titleLabel = titleLabel {
            didLayout = true
            let stack = UIStackView(arrangedSubviews: [titleLabel, imageView])
            addSubview(stack)
            stack.edgesToSuperview() // I use TinyConstraints library. You could handle the constraints directly
            stack.axis = .horizontal
        }
    }
}

0

Рішення для однієї лінії в Swift:

// iOS 9 and Onwards
button.semanticContentAttribute = .forceRightToLeft

Це не добре, оскільки це порушить макет для всіх користувачів RTL. Вам потрібно буде змусити їх зліва направо. Ви краще спробуйте інше рішення звідси.
Павло Якименко
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.