Как загрузить изображение в prepareForInterfaceBuilder с помощью IBDesignable UIImageView
Я хотел бы загрузить образец изображения в дизайн IB UIImageView
, чтобы отображаться в Интерфейсном Разработчике при редактировании интерфейса. Следующий код не работает, так как заполнитель представления в IB остается пустым (область просмотра содержит только текст UIImageView):
@IBDesignable
class TestImageView : UIImageView
{
override func prepareForInterfaceBuilder() {
//let bundle = NSBundle.mainBundle()
let bundle = NSBundle(forClass: nil)
let imagePath = bundle.pathForResource("Test", ofType: "jpg")
self.image = UIImage(contentsOfFile: imagePath)
}
}
Обратите внимание, что:
- в IB правильный класс Custom для представления корректен (TestImageView)
- Test.jpg присутствует в проекте (если я вручную установить свойство изображения
UIImageView
в IB изображение появляется). - Я попробовал два разных способа получения пакета в коде
Это было проверено с Xcode 6 beta 3.
Обновление: в обоих случаях путь к пакету, который я получаю, "/Applications/Temporary/Xcode6-Beta3.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/Library/Xcode/Overlays"
, На этом пути изображение явно не присутствует.
7 ответов
В Swift 4.1 код @kasplat изменился на:
// DYNAMIC BUNDLE DEFINITION FOR DESIGNABLE CLASS
let designTimeBundle = Bundle(for: type(of: self))
// OR ALTERNATIVELY BY PROVDING THE CONCRETE NAME OF YOUR DESIGNABLE VIEW CLASS
let designTimeBundle = Bundle(for: YourDesignableView.self)
// AND THEN SUCCESSFULLY YOU CAN LOAD THE RESSOURCE
let image = UIImage(named: "Logo", in: designTimeBundle, compatibleWith: nil)
Попробуйте получить связку класса следующим образом:
let bundle = NSBundle(forClass: self.dynamicType)
или указав имя класса, как это
let bundle = NSBundle(forClass: TestImageView.self)
Предполагая, что ваше изображение находится в комплекте, например, Images.xcassets, вы можете загрузить его, используя:
self.image = UIImage("Test", inBundle: bundle, compatibleWithTraitCollection: self.traitCollection)
Не забудьте проверить, является ли ваше изображение нулевым, прежде чем пытаться его использовать. Я не смог получить путь к изображению, используя bundle.pathForResource для правильной работы с обычными изображениями. Также, похоже, нет вызова UIImage, в котором вы указываете только имя и пакет, поэтому вы должны использовать коллекцию признаков.
Этот вопрос связан с:
xcode 6 IB_DESIGNABLE - не загружать ресурсы из пакета в Интерфейсном Разработчике
Ответ от Apple...
Инжиниринг установил, что эта проблема ведет себя как задумано, основываясь на следующем:
Мы не можем сделать это проще, чем указать комплект. Вы могли бы сказать: "О, давайте пошлём -[NSBundle mainBundle]", но многие сайты вызовов, которые ссылаются на пакет, не проходят через него (или проходят через CF API). Кто-то может сказать тогда: "Хорошо, ну, как насчет того, чтобы мы хотя бы пошутили -[UIImage imageNamed:]". Проблема здесь в том, что нет единой замены для основного комплекта. У вас может быть одновременно загружено несколько пакетов живого просмотра (фреймворки или приложения), поэтому мы не можем просто выбрать один из них как основной.
Разработчики должны знать о пакетах и о том, как получить изображения из пакета. Разработчики должны использовать UIImage(с именем:inBundle:compatibilityWithTraitCollection:) для всех поисков изображений.
Давай заглянем в быстрый ответ 3
let bundle = Bundle(for: self.classForCoder)
... UIImage(named: "AnImageInYourAssetsFolderPerhaps", in: bundle, compatibleWith: self.traitCollection)!
Для Swift 4 (и 3) используйте это:
let image = UIImage(named: "foo", in: Bundle(for: type(of: self)), compatibleWith: traitCollection)
Этот подход получает расслоение универсально
Мне удалось решить проблему с получением пути проекта Interface Builder из текущего NSProcessInfo
объект. Затем вы можете выбрать правильный путь из IB_PROJECT_SOURCE_DIRECTORIES
ключ.
override func prepareForInterfaceBuilder() {
let processInfo = NSProcessInfo.processInfo()
let environment = processInfo.environment
let projectSourceDirectories : AnyObject = environment["IB_PROJECT_SOURCE_DIRECTORIES"]!
let directories = projectSourceDirectories.componentsSeparatedByString(":")
if directories.count != 0 {
let firstPath = directories[0] as String
let imagePath = firstPath.stringByAppendingPathComponent("PrepareForIBTest/Test.jpg")
let image = UIImage(contentsOfFile: imagePath)
self.image = image
}
}
Этот метод описан в сеансе WWDC 2014 411 "Что нового в Интерфейсном Разработчике " в соответствии с предложением bjhomer в этом сообщении на форумах разработчиков Apple.
Более того, я должен сказать, что он должен был перейти на UIView
подкласс, потому что кажется, что появление UIImageView
не меняется в живом представлении.
Это загрузит ваш IB_Designable, или, если у вас его нет - изображение по умолчанию.
- (void)prepareForInterfaceBuilder
{
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
imagePic = imagePic ? [imagePic imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] : [UIImage imageNamed:@"goodIcon" inBundle:bundle compatibleWithTraitCollection:self.traitCollection];
}
Для Swift 2 и Xcode 7 интерфейс был изменен. Следует использовать
let bundle = NSBundle(forClass: self.dynamicType)
let image = UIImage(named: "imageName", inBundle: bundle, compatibleWithTraitCollection: self.traitCollection)
let imageView = UIImageView(image: image)
Я использую его в своем проекте, он отлично работает как для IB, так и для устройства.