Я не хочу использовать подпредставление, если я могу избежать этого. Я хочу UIButton
с фоновым изображением, текстом и изображением в нем. Прямо сейчас, когда я это делаю, изображение находится на левой стороне текста. Фоновое изображение, текст и изображение имеют разные состояния подсветки.
Как поместить изображение в правую часть текста в UIButton?
Ответ 1
Несмотря на то, что некоторые из предложенных ответов очень креативны и чрезвычайно умны, самое простое решение заключается в следующем:
button.semanticContentAttribute = UIApplication.shared
.userInterfaceLayoutDirection == .rightToLeft ? .forceLeftToRight : .forceRightToLeft
Так просто. В качестве бонуса, изображение будет слева на правой стороне слева.
РЕДАКТИРОВАТЬ: как вопрос был задан несколько раз, это iOS 9 +.
Ответ 2
Самое простое решение:
iOS 10 и выше, Swift:
button.transform = CGAffineTransform(scaleX: -1.0, y: 1.0)
button.titleLabel?.transform = CGAffineTransform(scaleX: -1.0, y: 1.0)
button.imageView?.transform = CGAffineTransform(scaleX: -1.0, y: 1.0)
До iOS 10, Swift/Obj-C:
button.transform = CGAffineTransformMakeScale(-1.0, 1.0);
button.titleLabel.transform = CGAffineTransformMakeScale(-1.0, 1.0);
button.imageView.transform = CGAffineTransformMakeScale(-1.0, 1.0);
Ответ 3
ОБНОВЛЕНО ДЛЯ XCODE 9 (через Интерфейсный Разработчик)
Есть более простой способ от Interface Builder. Выберите UIButton и выберите эту опцию в View Utilities:
Это! Красиво и просто!
ДОПОЛНИТЕЛЬНО - 2-й шаг:
Если вы хотите настроить расстояние между изображением и заголовком, вы можете изменить здесь вставку изображения:
Надеюсь, это поможет!
Ответ 4
Подклассификация UIButton совершенно не нужна. Вместо этого вы можете просто установить высокое значение левой вставки для вставки изображения и небольшую правую вставку для названия. Что-то вроде этого:
button.imageEdgeInsets = UIEdgeInsetsMake(0., button.frame.size.width - (image.size.width + 15.), 0., 0.);
button.titleEdgeInsets = UIEdgeInsetsMake(0., 0., 0., image.size.width);
Ответ 5
Я даю Inspire48 кредит для этого. Основываясь на его предположении и рассматривая этот другой вопрос, я придумал это. Подкласс UIButton и переопределить эти методы.
@implementation UIButtonSubclass
- (CGRect)imageRectForContentRect:(CGRect)contentRect
{
CGRect frame = [super imageRectForContentRect:contentRect];
frame.origin.x = CGRectGetMaxX(contentRect) - CGRectGetWidth(frame) - self.imageEdgeInsets.right + self.imageEdgeInsets.left;
return frame;
}
- (CGRect)titleRectForContentRect:(CGRect)contentRect
{
CGRect frame = [super titleRectForContentRect:contentRect];
frame.origin.x = CGRectGetMinX(frame) - CGRectGetWidth([self imageRectForContentRect:contentRect]);
return frame;
}
@end
Ответ 6
Просто обновите вставки, когда заголовок будет изменен. Вы должны компенсировать вставку с равной и противоположной вставкой с другой стороны.
[thebutton setTitle:title forState:UIControlStateNormal];
thebutton.titleEdgeInsets = UIEdgeInsetsMake(0, -thebutton.imageView.frame.size.width, 0, thebutton.imageView.frame.size.width);
thebutton.imageEdgeInsets = UIEdgeInsetsMake(0, thebutton.titleLabel.frame.size.width, 0, -thebutton.titleLabel.frame.size.width);
Ответ 7
Все эти ответы, начиная с января 2016 года, не нужны. В Interface Builder установите View Semantic в значение Force Right-to-Left
, или если вы предпочитаете программный путь, semanticContentAttribute = .forceRightToLeft
Это приведет к появлению изображения справа от вашего текста.
Ответ 8
В построителе интерфейсов вы можете настроить опции Edge Insets для UIButton, отдельно каждую из трех частей: содержимое, изображение, название
Xcode 8:
Ответ 9
Обновление: Swift 3
class ButtonIconRight: UIButton {
override func imageRect(forContentRect contentRect:CGRect) -> CGRect {
var imageFrame = super.imageRect(forContentRect: contentRect)
imageFrame.origin.x = super.titleRect(forContentRect: contentRect).maxX - imageFrame.width
return imageFrame
}
override func titleRect(forContentRect contentRect:CGRect) -> CGRect {
var titleFrame = super.titleRect(forContentRect: contentRect)
if (self.currentImage != nil) {
titleFrame.origin.x = super.imageRect(forContentRect: contentRect).minX
}
return titleFrame
}
}
Оригинальный ответ для Swift 2:
Решение, которое обрабатывает все горизонтальные выравнивания, с примером реализации Swift. Просто переведите на Objective-C при необходимости.
class ButtonIconRight: UIButton {
override func imageRectForContentRect(contentRect:CGRect) -> CGRect {
var imageFrame = super.imageRectForContentRect(contentRect)
imageFrame.origin.x = CGRectGetMaxX(super.titleRectForContentRect(contentRect)) - CGRectGetWidth(imageFrame)
return imageFrame
}
override func titleRectForContentRect(contentRect:CGRect) -> CGRect {
var titleFrame = super.titleRectForContentRect(contentRect)
if (self.currentImage != nil) {
titleFrame.origin.x = CGRectGetMinX(super.imageRectForContentRect(contentRect))
}
return titleFrame
}
}
Также стоит отметить, что он отлично обрабатывает вставки изображений и заголовков.
Вдохновленный от ответа на jasongregori;)
Ответ 10
Вот решение для UIButton
с выровненным по центру контентом.
Этот код выравнивает изображение и позволяет использовать imageEdgeInsets
и titleEdgeInsets
для драгоценного позиционирования.
Подкласс UIButton
с вашим специальным классом и добавьте:
- (CGRect)imageRectForContentRect:(CGRect)contentRect {
CGRect frame = [super imageRectForContentRect:contentRect];
CGFloat imageWidth = frame.size.width;
CGRect titleRect = CGRectZero;
titleRect.size = [[self titleForState:self.state] sizeWithAttributes:@{NSFontAttributeName: self.titleLabel.font}];
titleRect.origin.x = (self.frame.size.width - (titleRect.size.width + imageWidth)) / 2.0 + self.titleEdgeInsets.left - self.titleEdgeInsets.right;
frame.origin.x = titleRect.origin.x + titleRect.size.width - self.imageEdgeInsets.right + self.imageEdgeInsets.left;
return frame;
}
- (CGRect)titleRectForContentRect:(CGRect)contentRect {
CGFloat imageWidth = [self imageForState:self.state].size.width;
CGRect frame = [super titleRectForContentRect:contentRect];
frame.origin.x = (self.frame.size.width - (frame.size.width + imageWidth)) / 2.0 + self.titleEdgeInsets.left - self.titleEdgeInsets.right;
return frame;
}
Ответ 11
Если это нужно сделать в UIBarButtonItem, следует использовать дополнительную упаковку в представлении Это будет работать
let view = UIView()
let button = UIButton()
button.setTitle("Skip", for: .normal)
button.setImage(#imageLiteral(resourceName:"forward_button"), for: .normal)
button.semanticContentAttribute = .forceRightToLeft
button.sizeToFit()
view.addSubview(button)
view.frame = button.bounds
navigationItem.rightBarButtonItem = UIBarButtonItem(customView: view)
Это не сработает
let button = UIButton()
button.setTitle("Skip", for: .normal)
button.setImage(#imageLiteral(resourceName:"forward_button"), for: .normal)
button.semanticContentAttribute = .forceRightToLeft
button.sizeToFit()
navigationItem.rightBarButtonItem = UIBarButtonItem(customView: button)
Ответ 12
Поскольку решение для преобразования не работает в iOS 11, я решил написать новый подход.
Регулировка кнопок semanticContentAttribute
дает нам изображение справа вправо без необходимости ретрансляции, если текст изменяется. Из-за этого это идеальное решение. Однако мне все еще нужна поддержка RTL. Тот факт, что приложение не может изменить направление компоновки в одном сеансе, легко решает эту проблему.
С учетом сказанного, это довольно просто.
extension UIButton {
func alignImageRight() {
if UIApplication.shared.userInterfaceLayoutDirection == .leftToRight {
semanticContentAttribute = .forceRightToLeft
}
else {
semanticContentAttribute = .forceLeftToRight
}
}
}
Ответ 13
Основываясь на элегантном решении Piotr Tomasik: если вы хотите иметь немного интервала между ярлыком кнопки и изображением, а затем включите это в свои кросс-вставки следующим образом (копируя мой код здесь, отлично работает для меня):
CGFloat spacing = 3;
CGFloat insetAmount = 0.5 * spacing;
// First set overall size of the button:
button.contentEdgeInsets = UIEdgeInsetsMake(0, insetAmount, 0, insetAmount);
[button sizeToFit];
// Then adjust title and image insets so image is flipped to the right and there is spacing between title and image:
button.titleEdgeInsets = UIEdgeInsetsMake(0, -button.imageView.frame.size.width - insetAmount, 0, button.imageView.frame.size.width + insetAmount);
button.imageEdgeInsets = UIEdgeInsetsMake(0, button.titleLabel.frame.size.width + insetAmount, 0, -button.titleLabel.frame.size.width - insetAmount);
Спасибо Piotr за ваше решение!
Эрик
Ответ 14
Свифт -Extend UiButton и поместите эти строки
if let imageWidth = self.imageView?.frame.width {
self.titleEdgeInsets = UIEdgeInsetsMake(0, -imageWidth, 0, imageWidth);
}
if let titleWidth = self.titleLabel?.frame.width {
let spacing = titleWidth + 20
self.imageEdgeInsets = UIEdgeInsetsMake(0, spacing, 0, -spacing);
}
Ответ 15
Взял @Piotr ответ и превратил его в расширение Swift. Обязательно установите изображение и заголовок, прежде чем вызывать это, чтобы кнопка правильно отображалась.
extension UIButton {
/// Makes the ``imageView`` appear just to the right of the ``titleLabel``.
func alignImageRight() {
if let titleLabel = self.titleLabel, imageView = self.imageView {
// Force the label and image to resize.
titleLabel.sizeToFit()
imageView.sizeToFit()
imageView.contentMode = .ScaleAspectFit
// Set the insets so that the title appears to the left and the image appears to the right.
// Make the image appear slightly off the top/bottom edges of the button.
self.titleEdgeInsets = UIEdgeInsets(top: 0, left: -1 * imageView.frame.size.width,
bottom: 0, right: imageView.frame.size.width)
self.imageEdgeInsets = UIEdgeInsets(top: 4, left: titleLabel.frame.size.width,
bottom: 4, right: -1 * titleLabel.frame.size.width)
}
}
}
Ответ 16
Быстрый вариант, который делает то, что вы хотите, не играя с любыми вставками:
class RightImageButton: UIButton {
override func layoutSubviews() {
super.layoutSubviews()
if let textSize = titleLabel?.intrinsicContentSize(),
imageSize = imageView?.intrinsicContentSize() {
let wholeWidth = textSize.width + K.textImageGap + imageSize.width
titleLabel?.frame = CGRect(
x: round(bounds.width/2 - wholeWidth/2),
y: 0,
width: ceil(textSize.width),
height: bounds.height)
imageView?.frame = CGRect(
x: round(bounds.width/2 + wholeWidth/2 - imageSize.width),
y: RoundRetina(bounds.height/2 - imageSize.height/2),
width: imageSize.width,
height: imageSize.height)
}
}
struct K {
static let textImageGap: CGFloat = 5
}
}
Ответ 17
Подкласс и перенаправление макетов. Предполагается, что ваш лучший путь.
Ссылка на: iPhone UIButton - позиция изображения
Ответ 18
Решения, упомянутые здесь, перестали работать, как только я включил Автоматический макет. Я должен был придумать свой собственный:
Подкласс UIButton и переопределить метод layoutSubviews
:
//
// MIThemeButtonImageAtRight.m
// Created by Lukasz Margielewski on 7/9/13.
//
#import "MIThemeButtonImageAtRight.h"
static CGRect CGRectByApplyingUIEdgeInsets(CGRect frame, UIEdgeInsets insets);
@implementation MIThemeButtonImageAtRight
- (void)layoutSubviews
{
[super layoutSubviews];
CGRect contentFrame = CGRectByApplyingUIEdgeInsets(self.bounds, self.contentEdgeInsets);
CGRect frameIcon = self.imageView.frame;
CGRect frameText = self.titleLabel.frame;
frameText.origin.x = CGRectGetMinX(contentFrame) + self.titleEdgeInsets.left;
frameIcon.origin.x = CGRectGetMaxX(contentFrame) - CGRectGetWidth(frameIcon);
self.imageView.frame = frameIcon;
self.titleLabel.frame = frameText;
}
@end
static CGRect CGRectByApplyingUIEdgeInsets(CGRect frame, UIEdgeInsets insets){
CGRect f = frame;
f.origin.x += insets.left;
f.size.width -= (insets.left + insets.right);
f.origin.y += (insets.top);
f.size.height -= (insets.top + insets.bottom);
return f;
}
Результат:
Ответ 19
Путь расширения
Используя расширение, чтобы установить изображение на правой стороне с пользовательским смещением
extension UIButton {
func addRightImage(image: UIImage, offset: CGFloat) {
self.setImage(image, for: .normal)
self.imageView?.translatesAutoresizingMaskIntoConstraints = false
self.imageView?.centerYAnchor.constraint(equalTo: self.centerYAnchor, constant: 0.0).isActive = true
self.imageView?.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -offset).isActive = true
}
}
Ответ 20
Swift 3:
open override func imageRect(forContentRect contentRect: CGRect) -> CGRect {
var frame = super.imageRect(forContentRect: contentRect)
let imageWidth = frame.size.width
var titleRect = CGRect.zero
titleRect.size = self.title(for: self.state)!.size(attributes: [NSFontAttributeName: self.titleLabel!.font])
titleRect.origin.x = (self.frame.size.width - (titleRect.size.width + imageWidth)) / 2.0 + self.titleEdgeInsets.left - self.titleEdgeInsets.right;
frame.origin.x = titleRect.origin.x + titleRect.size.width - self.imageEdgeInsets.right + self.imageEdgeInsets.left;
return frame
}
open override func titleRect(forContentRect contentRect: CGRect) -> CGRect {
var frame = super.titleRect(forContentRect: contentRect)
if let imageWidth = self.image(for: self.state)?.size.width {
frame.origin.x = (self.frame.size.width - (frame.size.width + imageWidth)) / 2.0 + self.titleEdgeInsets.left - self.titleEdgeInsets.right;
}
return frame
}
Ответ 21
swift 3.0 Миграция решение, данное jasongregori
class ButtonIconRight: UIButton {
override func imageRect(forContentRect contentRect: CGRect) -> CGRect {
var imageFrame = super.imageRect(forContentRect: contentRect)
imageFrame.origin.x = super.titleRect(forContentRect: contentRect).maxX - imageFrame.width
return imageFrame
}
override func titleRect(forContentRect contentRect: CGRect) -> CGRect {
var titleFrame = super.titleRect(forContentRect: contentRect)
if (self.currentImage != nil) {
titleFrame.origin.x = super.imageRect(forContentRect: contentRect).minX
}
return titleFrame
}
Ответ 22
Как насчет ограничений? В отличие от semanticContentAttribute, они не меняют семантики. Что-то вроде этого возможно:
button.rightAnchorconstraint(equalTo: button.rightAnchor).isActive = true
или Objective-C:
[button.imageView.rightAnchor constraintEqualToAnchor:button.rightAnchor].isActive = YES;
Предостережения: Untested, iOS 9 +
Ответ 23
Попробовав несколько решений по всему интернету, я не достиг точного требования. Так что я закончил писать собственный код утилиты. Публикация, чтобы помочь кому-то в будущем. Проверено на Swift 4.2
// This function should be called in/after viewDidAppear to let view render
func addArrowImageToButton(button: UIButton, arrowImage:UIImage = #imageLiteral(resourceName: "my_image_name") ) {
let btnSize:CGFloat = 32
let imageView = UIImageView(image: arrowImage)
let btnFrame = button.frame
imageView.frame = CGRect(x: btnFrame.width-btnSize-8, y: btnFrame.height/2 - btnSize/2, width: btnSize, height: btnSize)
button.addSubview(imageView)
//Imageview on Top of View
button.bringSubviewToFront(imageView)
}
Ответ 24
Благодаря Виталию Гоженко
Я просто хочу добавить, что вы можете добавить IB_DESIGNABLE перед вашей кнопкой @interface и установить свой класс кнопок в storyborad. Затем вы можете смотреть его макет в режиме реального времени без запуска приложения только на стадии построения интерфейса.
Ответ 25
Чтобы выровнять изображение по правому краю в UIButton, попробуйте код ниже
btn.contentHorizontalAlignment = .right
Ответ 26
Правильный ответ в Swift
import UIKit
extension UIButton {
func imageRectForContentRect(contentRect:CGRect) -> CGRect {
var frame = self.imageRectForContentRect(contentRect)
frame.origin.x = CGRectGetMaxX(contentRect) - CGRectGetWidth(frame) - self.imageEdgeInsets.right + self.imageEdgeInsets.left
return frame
}
func titleRectForContentRect(contentRect:CGRect) -> CGRect {
var frame = self.titleRectForContentRect(contentRect)
frame.origin.x = CGRectGetMaxX(contentRect) - CGRectGetWidth(self.imageRectForContentRect(contentRect))
return frame
}
}