ПоявлениеWhenContainedIn в Swift

Я пытаюсь преобразовать свое приложение в язык Swift.

У меня есть эта строка кода:

[[UIBarButtonItem appearanceWhenContainedIn:[UINavigationBar class], nil]
                     setTitleTextAttributes:textDictionary
                                   forState:UIControlStateNormal];

Как преобразовать его в Swift?

В Apple docs такого метода нет.

Ответ 1

Обновление для iOS 9:

Если вы настроите iOS 9+ (начиная с Xcode 7 b1), в протоколе UIAppearance есть новый метод, который не использует varargs:

static func appearanceWhenContainedInInstancesOfClasses(containerTypes: [AnyObject.Type]) -> Self

Что можно использовать так:

UITextField.appearanceWhenContainedInInstancesOfClasses([MyViewController.self]).keyboardAppearance = .Light

Если вам все еще нужно поддерживать iOS 8 или ранее, используйте следующий оригинальный ответ на этот вопрос.

Для iOS 8 и 7:

Эти методы недоступны для Swift, поскольку методы varargs Obj-C несовместимы с Swift (см. http://www.openradar.me/17302764).

Я написал невариантное обходное решение, которое работает в Swift (я повторил тот же метод для UIBarItem, который не сходит с UIView):

// UIAppearance+Swift.h
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface UIView (UIViewAppearance_Swift)
// appearanceWhenContainedIn: is not available in Swift. This fixes that.
+ (instancetype)my_appearanceWhenContainedIn:(Class<UIAppearanceContainer>)containerClass;
@end
NS_ASSUME_NONNULL_END

-

// UIAppearance+Swift.m
#import "UIAppearance+Swift.h"
@implementation UIView (UIViewAppearance_Swift)
+ (instancetype)my_appearanceWhenContainedIn:(Class<UIAppearanceContainer>)containerClass {
    return [self appearanceWhenContainedIn:containerClass, nil];
}
@end

Просто не забудьте #import "UIAppearance+Swift.h" в заголовке моста.

Затем для вызова из Swift (например):

# Swift 2.x:
UITextField.my_appearanceWhenContainedIn(MyViewController.self).keyboardAppearance = .Light

# Swift 3.x:
UITextField.my_appearanceWhenContained(in: MyViewController.self).keyboardAppearance = .light

Ответ 2

ios 10 swift 3

UIBarButtonItem.appearance(whenContainedInInstancesOf: [UISearchBar.self]).title = "Kapat"

Ответ 3

Для iOS 8 и 7:

Я использую категорию на основе ответа Alex, чтобы указать несколько контейнеров. Это временное решение, пока Apple официально не поддерживает appearanceWhenContainedIn в Swift.

UIAppearance + Swift.h

@interface UIView (UIAppearance_Swift)
/// @param containers An array of Class<UIAppearanceContainer>
+ (instancetype)appearanceWhenContainedWithin: (NSArray *)containers;
@end

UIAppearance + Swift.m

@implementation UIView (UIAppearance_Swift)

+ (instancetype)appearanceWhenContainedWithin: (NSArray *)containers
{
    NSUInteger count = containers.count;
    NSAssert(count <= 10, @"The count of containers greater than 10 is not supported.");

    return [self appearanceWhenContainedIn:
            count > 0 ? containers[0] : nil,
            count > 1 ? containers[1] : nil,
            count > 2 ? containers[2] : nil,
            count > 3 ? containers[3] : nil,
            count > 4 ? containers[4] : nil,
            count > 5 ? containers[5] : nil,
            count > 6 ? containers[6] : nil,
            count > 7 ? containers[7] : nil,
            count > 8 ? containers[8] : nil,
            count > 9 ? containers[9] : nil,
            nil];
}
@end

Затем добавьте #import "UIAppearance+Swift.h" в заголовок моста.

Использовать из Swift:

TextField.appearanceWhenContainedWithin([MyViewController.self, TableViewController.self]).keyboardAppearance = .Light

Хорошо, если бы я мог найти способ, используя CVarArgType, но я не нашел чистого решения.

Ответ 4

Здесь менее уродливое, но все же уродливое, обходное решение, вдохновленное @tdun.

  • Создайте класс, чтобы сохранить внешний вид Objective-C. Для целей этого примера позвоните ему AppearanceBridger.
  • Добавьте этот класс в свой заголовок. Если у вас нет заголовка моста, создать один.
  • Создайте метод класса в AppearanceBridger с именем +(void)setAppearance и поместите код внешнего вида Objective-C в этот метод. Например:


+ (void)setAppearance {
    [[UIView appearanceWhenContainedIn:[UITableViewHeaderFooterView class], nil] setBackgroundColor:[UIColor whiteColor]];
}
  1. В вашем коде Swift, где вы задаете внешний вид, вызовите AppearanceBridger.setAppearance(), и вы должны быть добрым!

Надеюсь, это хорошо работает для людей, которые это видят.

Ответ 5

Вот уродливое решение обходного пути, которое я использовал....

Просто создайте Objective-C Cocoa Touch Class (UIViewController), названный так, как вы хотите.

Я назвал мой WorkaroundViewController...

Теперь в (WorkaroundViewController.m):

-(id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil

Запустите код внешнего вида Objective-C для .appearanceWhenContainedIn() (здесь мой пример):

[[UITextField appearanceWhenContainedIn:[UISearchBar class], nil] setDefaultTextAttributes:@{NSFontAttributeName: [UIFont fontWithName:@"Avenir-Light" size:16.0f]}];

Затем создайте заголовок моста для вашего проекта Swift и затем инициализируйте ваш ViewController Objective-C в вашем Swift-коде, как это (опять же, просто мой пример):

var work : WorkaroundViewController = WorkaroundViewController()

Тогда все готово! Дайте мне знать, если это сработает для вас... Как я уже сказал, это уродливо, но работает!

Ответ 6

Это может быть расширено для любого класса, который соответствует протоколу UIAppearance, а не только UIViews. Итак, вот более общая версия:

UIAppearance + Swift.h

#import <UIKit/UIKit.h>

@interface NSObject (UIAppearance_Swift)

+ (instancetype)appearanceWhenContainedWithin:(Class<UIAppearanceContainer>)containerClass;

@end

UIAppearance + Swift.m

#import "UIAppearance+Swift.h"

@implementation NSObject (UIAppearance_Swift)

+ (instancetype)appearanceWhenContainedWithin:(Class<UIAppearanceContainer>)containerClass {
    if ([self conformsToProtocol:@protocol(UIAppearance)]) {
        return [(id<UIAppearance>)self appearanceWhenContainedIn:containerClass, nil];
    }
    return nil;
}

@end

Ответ 7

Я создал репо для вас, ребята, которые хотят использовать CocoaPods:

  • Добавьте это в свой Podfile:

    pod 'UIViewAppearanceSwift'
    
  • Импортируйте в свой класс:

    import UIViewAppearanceSwift
    
    func layout() {
        UINavigationBar.appearanceWhenContainedWithin(MFMailComposeViewController.self).barStyle = .Black
        UIBarButtonItem.appearanceWhenContainedWithin(UISearchBar.self).setTitleTextAttributes([NSFontAttributeName: UIFont.systemFontOfSize(15)], forState: UIControlState.Normal)
    }
    
  • Ссылка: https://github.com/levantAJ/UIViewAppearanceSwift

Ответ 8

Кажется, Swift (по крайней мере, с Beta5) не может поддерживать его по неизвестным мне причинам. Возможно, требуемая языковая функция все еще продолжается, поскольку я могу только предположить, что они оставили ее вне интерфейса по уважительной причине. Как вы сказали, согласно документам, он все еще доступен в ObjC. Действительно неутешительно.

Ответ 9

Вы можете использовать это:

UIBarButtonItem.appearance().setTitleTextAttributes(textDictionary, forState: UIControlState.Normal)

Изменить: внешний видWhenContainedIn был удален в Swift. Этот ответ состоял в том, что Beta 5 изменила внешний вид текста всех кнопок на панели.

Ответ 10

Вы должны просто перевести синтаксис Objective-C в синтаксис Swift.

В быстрой версии методы должны быть объявлены следующим образом:

func appearanceWhenContainedIn(containerClass : <UIAppearanceContainer>)
func setTitleTextAttributes(_ attributes: NSDictionary!, forState state: UIControlState)

Итак, вы можете попробовать следующее:

UIBarButtonItem.appearanceWhenContainedIn(UINavigationBar).setTitleTextAttributes(textDictionary, forState: UIControlStateNormal)

Мне все же нужно выяснить, является ли это чистым способом вызова метода класса в Swift.

Надеюсь, что это поможет,