Как загрузить изображение в prepareForInterfaceBuilder с IBDesignable UIImageView
Я хотел бы загрузить образ образца в IB UIImageView
, который будет отображаться в Interface Builder при редактировании интерфейса. Следующий код не работает, поскольку замещающий объект в 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 Class для представления корректен (TestImageView)
- Test.jpg присутствует в проекте (если я вручную установил свойство изображения
UIImageView
в IB, изображение появится).
- Я попробовал два разных метода получения пакета в коде
Это было протестировано с помощью Xcode 6 beta 3.
Обновить: в обоих случаях путь пучка, который я получаю, равен "/Applications/Temporary/Xcode6-Beta3.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/Library/Xcode/Overlays"
. На этом пути изображение, очевидно, отсутствует.
Ответы
Ответ 1
Обновлено для Swift 4.2
Когда вы создаете экземпляр UIImage (с UIImage (с именем: "SomeName"), приложение будет искать ресурс в вашем основном комплекте, который обычно работает нормально. Но когда вы находитесь во время разработки, InterfaceBuilder содержит код проектируемых представлений ( для компиляции при проектировании) в отдельной связке.
Итак, решение таково: определите ваш пакет динамически, поэтому ваши файлы могут быть найдены во время разработки, компиляции и выполнения:
// DYNAMIC BUNDLE DEFINITION FOR DESIGNABLE CLASS
let dynamicBundle = Bundle(for: type(of: self))
// OR ALTERNATIVELY BY PROVDING THE CONCRETE NAME OF YOUR DESIGNABLE VIEW CLASS
let dynamicBundle = Bundle(for: YourDesignableView.self)
// AND THEN SUCCESSFULLY YOU CAN LOAD THE RESSOURCE
let image = UIImage(named: "Logo", in: dynamicBundle, compatibleWith: nil)
Ответ 2
Попробуйте получить пакет класса следующим образом:
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...
Engineering определила, что эта проблема ведет себя как предполагаемая на следующем:
Мы не можем сделать это проще, чем указывать пакет. Вы может сказать: "О, пусть swizzle - [NSBundle mainBundle]", но много сайты звонков, которые ссылаются на пакет, не проходят там (или идут через CF API). Тогда можно сказать "хорошо, ну тогда как насчет наименее swizzle - [UIImage imageNamed:]". Проблема здесь в том, что там не является единственной заменой основного пучка. У вас может быть несколько в реальном времени (или фреймворки или приложения) загружаются сразу, поэтому мы не может просто выбрать один из них в качестве основного пучка.
Разработчики должны знать о связках и как получать изображения с расслоение. Разработчики должны использовать UIImage (имя: inBundle: compatibleWithTraitCollection:) для всех поисков изображений.
Ответ 3
Позволяет выбрать быстрый ответ
let bundle = Bundle(for: self.classForCoder)
... UIImage(named: "AnImageInYourAssetsFolderPerhaps", in: bundle, compatibleWith: self.traitCollection)!
Ответ 4
Мне удалось исправить проблему с получением пути проекта 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 в этом
Ответ 5
Для Swift 4 (и 3) используйте это:
let image = UIImage(named: "foo", in: Bundle(for: type(of: self)), compatibleWith: traitCollection)
Этот подход получает универсальный пакет
Ответ 6
Для 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, так и для устройства.
Ответ 7
Это загрузит ваш IB_Designable, или если у вас его нет - изображение по умолчанию.
- (void)prepareForInterfaceBuilder
{
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
imagePic = imagePic ? [imagePic imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] : [UIImage imageNamed:@"goodIcon" inBundle:bundle compatibleWithTraitCollection:self.traitCollection];
}