Создание подкласса UIButton и создание его для IBDesignable

У меня есть приложение, в котором используются настраиваемые кнопки, кнопки должны иметь просто фоновое изображение. Вместо добавления фонового изображения ко всем кнопкам я бы предпочел подкласс UIButton. Было бы здорово, если бы настраиваемая кнопка также правильно отображалась в Интерфейсном Разработчике. Это моя попытка:

import UIKit

@IBDesignable
class STACPatientButton: UIButton {

    override init(frame: CGRect) {
        NSLog("initWithFrame");
        super.init(frame: frame)
        _setup()
    }

    required init(coder: NSCoder) {
        NSLog("initWithCoder");
        super.init(coder: coder)
        _setup()
    }

    override func prepareForInterfaceBuilder() {
        _setup()
    }

    private func _setup() {
        if let image = UIImage(named:"patientButton.png") {
            let insets = UIEdgeInsetsMake(8.0, 8.0, 8.0, 8.0)
            let strechableImage = image.resizableImageWithCapInsets(insets)
            self.setBackgroundImage(strechableImage, forState: UIControlState.Normal)
            self.contentEdgeInsets = UIEdgeInsetsMake(16.0, 16.0, 16.0, 16.0)
            self.sizeToFit()
        }
    }

}

Где это PatientButton.png

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

Две проблемы:

  1. кнопка не отображается должным образом в Интерфейсном Разработчике. Он просто отображается как системная кнопка
  2. заголовок не отображается, если я не изменю размер кнопки в Интерфейсном Разработчике, чтобы оставить место для изображения; т.е. свойство contentEdgeInsets и sizeToFit, похоже, не имеют никакого эффекта

Думаю, это довольно простой вопрос, но я не могу его решить. Какой-нибудь совет?

ИЗМЕНИТЬ 1 согласно обсуждению с Мэттом ниже:

Я пытаюсь выделить место вокруг названия кнопки. Это было мое понимание contentEdgeInsets, но похоже, что я ошибаюсь. Без contentEdgeInsets это отрисовка кнопки

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

что выглядит ужасно. Я хочу программно получить что-то вроде этого, без необходимости изменять размер кнопки в IB

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


person Wolfy    schedule 28.06.2015    source источник


Ответы (1)


Вы неправильно поняли, что делает contentEdgeInsets. Для вставки вашего фонового изображения вам необходимо реализовать этот метод:

override func backgroundRectForBounds(bounds: CGRect) -> CGRect {
    return bounds.rectByInsetting(dx: 16, dy: 16)
}

Для IBDesignable то, что вы делаете, структурно правильно; если вы удалите свой _setup() код и замените его на

self.backgroundColor = UIColor.redColor()

кнопка действительно будет красной в IB. Так что, возможно, IB просто не «делает» фоновые изображения, установленные в коде, и так далее.

person matt    schedule 28.06.2015
comment
Я попытался добавить простую функцию intrinsicContentSize, возвращающую постоянный размер; функция вызывается, но размер кнопки не изменяется. Вместо этого я попробую sizeToFit. - person Wolfy; 29.06.2015
comment
Что ж, в IB его размер не изменится. Я предлагал, что с этим делать, когда приложение запускается ... - person matt; 29.06.2015
comment
Ну, наверное, потому, что вы не используете автоматический макет. Внедрение intrinsicContentSize, безусловно, работает для меня. - person matt; 29.06.2015
comment
Я использую автоматический макет, по крайней мере, мне так кажется. Можете ли вы опубликовать свой полный код? - person Wolfy; 29.06.2015
comment
Реализация sizeToFit тоже не работает. Похоже, что размер кнопки фиксирован на то, что установлено в IB. Должно быть, я упустил что-то действительно глупое. - person Wolfy; 29.06.2015
comment
У меня есть еще один вопрос - вы не ожидаете, что contentEdgeInsets повлияет на изображение background, не так ли? Потому что это не так; он влияет только на заголовок и внутреннее изображение. - person matt; 29.06.2015
comment
Думаю, я не знаю, чего вы пытаетесь достичь. Не могли бы вы нарисовать картину того, как вы пытаетесь заставить эту кнопку выглядеть? Я удалил часть своего ответа о краевых вставках, так как не знаю, актуально ли это вообще. - person matt; 29.06.2015
comment
О да! Я ожидал, что contentEdgeInsets повлияет на фоновое изображение. Думаю, поэтому intrinsicContentSize тоже не делает того, чего я ожидаю. Кстати, переопределение sizeToFit работает, но мне нужно отключить автоматическую компоновку. - person Wolfy; 29.06.2015
comment
Хорошо, но intrinsicContentSize тоже работает, если кнопка находится в автоматическом режиме. Вы можете вернуть постоянный размер, или вы можете вызвать super и оттуда отрегулировать. Вот как бы я это сделал. - person matt; 29.06.2015
comment
Очевидно, что для вставки фонового изображения вам потребуется реализовать backgroundRectForBounds. Я добавлю это к своему ответу. - person matt; 29.06.2015
comment
Большое спасибо за Вашу помощь. По-прежнему похоже, что я не ясно передаю, чего хочу достичь. Я отредактировал исходный пост, добавив больше деталей. Надеюсь, что это проясняет. - person Wolfy; 29.06.2015
comment
Хорошо, похоже, что backgroundRectForBounds с отрицательными вставками делает свое дело! Еще раз спасибо! - person Wolfy; 29.06.2015