появаWhenContainIn в Swift


125

Я намагаюся перетворити додаток на мову Swift.

У мене є такий рядок коду:

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

Як перетворити його на Swift?

В документах Apple такого методу немає.


1
@LukeTheObscure перевірити мою відповідь нижче ... некрасиво, але працює.
tcd

Відповіді:


230

Оновлення для 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

15
UIBarButtonItem - це не UIView і його потрібно розширити окремо
Сергій Скобліков

7
Зауважте, що принаймні в iOS8 UIAppearance + Swift.h повинен імпортувати UIKit / UIKit.h
Chase

UIBarButtonItem можна підтримати також, якщо ви просто зробите інший метод, орієнтований на UIBarButtonItem замість UIView. @interface UIBarButtonItem (UIViewAppearance_Swift)
Майкл Петерсон

1
@rptwsthi: Я додав приклад для Swift 3, він зовсім трохи інший
Алекс Прецлав

1
Версія iOS 9 для Swift 3.2 - це UIBarButtonItem.appearance (whenContainInInsancesOf: [UISearchBar.self]). Title = "Готово"
Елі Берк

31

ios 10 swift 3

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

1
Не знаю , чому це так downvote це працює так , як це зробити в iOS10 стрімкими 3 ... Спасибі
Василь

14

Для iOS 8 і 7:

Я використовую категорію на основі відповіді Алекса, щоб вказати кілька контейнерів. Це рішення, поки Apple офіційно не підтримає appearanceWhenContainedInSwift.

Поява UIA + Swift.h

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

Поява UIA + 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 , але я не знайшов чистого рішення.


Приємного вирішення розбитості варагів! Це дуже погано, що немає іншого рішення, окрім (зараз), методу Apple, лише для iOS 9.
Олексій Прецлав

12

Ось менш потворний, але все ж потворний спосіб вирішення натхнення @tdun.

  1. Створіть клас, щоб утримувати зовнішній вигляд Objective-C. Для цілей цього прикладу назвемо це AppearanceBridger.
  2. Додайте цей клас до мостового заголовка. Якщо у вас немає мостового заголовка, створіть його .
  3. Створіть метод класу в AppearanceBridgerімені +(void)setAppearanceта введіть у цей метод код зовнішності Objective-C. Наприклад:


+ (void)setAppearance {
    [[UIView appearanceWhenContainedIn:[UITableViewHeaderFooterView class], nil] setBackgroundColor:[UIColor whiteColor]];
}

  1. У вашому коді Swift, де ви встановлюєте зовнішній вигляд, дзвоніть, AppearanceBridger.setAppearance()і вам слід погодитися!

Сподіваюся, це добре працює для людей, які бачать це.


4

Ось некрасиве рішення рішення, яке я використав….

Просто зробіть сенсорний клас какао-об'єктива Objective-C (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, а потім ініціалізуйте ваш Objective-C ViewController у своєму Swift-коді, як це (знову ж, лише мій приклад):

var work : WorkaroundViewController = WorkaroundViewController()

Тоді ви закінчили! Дайте мені знати, чи працює це для вас ... Як я вже сказав, це некрасиво, але працює!


Це рішення tmp, я думаю, що ми повинні знайти або почекати на якийсь кращий шлях :)
AlexZd

@AlexZd, абсолютно, я сподіваюся, що вони включать це швидко ... Але поки, якщо вам це потрібно, ви їдете!
tcd

4

Це може бути розширено до будь-якого класу, який відповідає протоколу UIAppearance - не лише UIView. Отже, ось більш універсальна версія:

Поява UIA + Swift.h

#import <UIKit/UIKit.h>

@interface NSObject (UIAppearance_Swift)

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

@end

Поява UIA + 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

3

Я створив репо для вас, хлопці, які хочете використовувати CocoaPods:

  1. Додайте це до свого Podfile:

    pod 'UIViewAppearanceSwift'
  2. Імпорт у ваш клас:

    import UIViewAppearanceSwift
    
    func layout() {
        UINavigationBar.appearanceWhenContainedWithin(MFMailComposeViewController.self).barStyle = .Black
        UIBarButtonItem.appearanceWhenContainedWithin(UISearchBar.self).setTitleTextAttributes([NSFontAttributeName: UIFont.systemFontOfSize(15)], forState: UIControlState.Normal)
    }
  3. Довідка: https://github.com/levantAJ/UIViewAppearanceSwift



0

Здається, Свіфт (принаймні, як у Beta5) не в змозі підтримати це з незрозумілих мені причин. Можливо, потрібна мовна функція все ще працює, тому що я можу лише припустити, що вони її залишили поза інтерфейсом з поважної причини. Як ви вже говорили, згідно з документами він все ще доступний в ObjC. Дійсно розчаровує.


Це працювало для мене в бета-версії 5, використовуючи метод @spinillos.
Джейсон Крамп

Правильно, але appearanceWhenContainedIn:все ще поза столом.
hlfcoding

-3

Ви можете скористатися цим:

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

Редагувати: виглядWhenContainIn видалено в Swift. Ця відповідь стала для Beta 5, щоб змінити вигляд тексту всіх кнопок рядка.


1
Крім того, не потрібно використовувати, UIControlState.Normalви можете просто використовувати .NormalSwift знає тип за висновком.
Бен Лачман

12
це змінить зовнішній вигляд для всіх UIBarButtonItems, а не конкретний
Костянтин Коваль

@KonstantinKoval Саме так - це мета появи проксі. Ви можете стилізувати всю програму без необхідності містити виклики коду / методу котла у кожному контролері перегляду.
Крейг Отіс

3
Це фактично не відповідає на питання, у Swift appearanceWhenContainedInбуло видалено.
Тім Віндзор Браун

-7

Ви повинні мати можливість просто перевести Objective-Cсинтаксис у Swiftсинтаксис.

Швидко методи слід оголосити так:

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

Тож ви можете спробувати це:

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

Я все ще повинен з'ясувати, чи це чистий спосіб викликати метод класу, Swiftхоча.

Сподіваюся, це допомагає,


1
Немає цього методу появиWhenContainIn, швидко він не компілюється. Помилка: "UIBarButtonItem.Type" не має учасника з ім'ям "
lookWhenContainIn

Привіт @AlexZd, ваш коментар базується на фактичній бета-версії XCode 6, але якщо ви подивитеся на UIAppearanceдокументацію протоколу (якій UIBarButtonItemвідповідає), існує метод `izgledWhenContainIn (_ :) (він просто ще не реалізований у Swift): developer.apple .com / бібліотека / передвипуск / ios / документація / UIKit /…
Zedenem

@ Zedenem Я знаю, це дуже глупо, і ви не хочете нам повірити - але цей метод буквально не можна викликати від Swift, перегляньте документацію: developer.apple.com/library/ios/documentation/UIKit/Reference/… - метод приховано від Swift
powerj1984

Привіт @ powerj1984, це не те, що я не хочу тобі вірити. Я тільки сподівався, коли я написав свою відповідь, що це саме завдяки бета-статусу Свіфта. Те, що метод не був застарілим, а просто прихований від Свіфта, насправді дивно, а відсутність пояснень від Apple робить це навіть найгірше ... Але ти маєш рацію, навіть якщо я не розумію чому, моя відповідь неправильно. Можливо, є якась особливість у Свіфта, я не замислююся над тим, що дозволило б нам робити саме це ...
Zedenem

Ха-ха, вибачте - я справді маю на увазі, що я не хочу мені вірити. Це якраз така дурна річ, що Apple закрутиться. Це дивно, як чорт!
powerj1984
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.