aspectWhenContainedIn in Swift


125

Sto cercando di convertire la mia app nella lingua Swift.

Ho questa riga di codice:

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

Come convertirlo in Swift?

Nei documenti di Apple , non esiste tale metodo.


1
@LukeTheObscure controlla la mia risposta qui sotto ... brutta, ma funziona.
LCD

Risposte:


230

Aggiornamento per iOS 9:

Se scegli come target iOS 9+ (a partire da Xcode 7 b1), nel UIAppearanceprotocollo è presente un nuovo metodo che non utilizza varargs:

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

Quale può essere usato così:

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

Se hai ancora bisogno di supportare iOS 8 o precedenti, usa la seguente risposta originale a questa domanda.

Per iOS 8 e 7:

Questi metodi non sono disponibili per Swift perché i metodi varargs di Obj-C non sono compatibili con Swift (vedere http://www.openradar.me/17302764 ).

Ho scritto una soluzione alternativa non variadica che funziona in Swift (ho ripetuto lo stesso metodo per UIBarItem, da cui non discende 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

Assicurati di #import "UIAppearance+Swift.h"averlo nell'intestazione del ponte.

Quindi, per chiamare da Swift (ad esempio):

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

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

15
UIBarButtonItem non è un UIView e deve essere esteso separatamente
Sergey Skoblikov

7
Nota che almeno in iOS8, UIAppearance + Swift.h dovrebbe importare UIKit / UIKit.h
Chase,

UIBarButtonItem può essere supportato anche se si crea semplicemente un altro metodo destinato a UIBarButtonItem anziché UIView. @interface UIBarButtonItem (UIViewAppearance_Swift)
Michael Peterson

1
@rptwsthi: ho aggiunto un esempio per Swift 3, è leggermente diverso
Alex Pretzlav

1
La versione iOS 9 per Swift 3.2 è UIBarButtonItem.appearance (whenContainedInInstancesOf: [UISearchBar.self]). Title = "Done"
Eli Burke,

31

ios 10 swift 3

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

1
Non so perché questo è un downvote poiché è il modo di farlo in iOS10 swift 3 ... Grazie
Vassily,

14

Per iOS 8 e 7:

Uso una categoria basata sulla risposta di Alex per specificare più contenitori. Questa è una soluzione alternativa fino a quando Apple non supporta ufficialmente appearanceWhenContainedInSwift.

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

Quindi aggiungi #import "UIAppearance+Swift.h"all'intestazione del ponte.

Per utilizzare da Swift :

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

È stato bello se avessi trovato un modo usando CVarArgType , ma non ho trovato una soluzione pulita.


Bella soluzione alternativa alla rottura di Varargs! È davvero un peccato che non ci sia una soluzione generale diversa da (ora) utilizzando il metodo solo iOS 9 di Apple.
Alex Pretzlav,

12

Ecco una soluzione meno brutta, ma ancora brutta, ispirata a @tdun.

  1. Crea una classe per contenere il tuo aspetto Objective-C. Ai fini di questo esempio, chiamiamolo AppearanceBridger.
  2. Aggiungi questa classe all'intestazione del ponte. Se non hai un'intestazione a ponte, creane uno .
  3. Creare un metodo di classe in AppearanceBridgernamed +(void)setAppearancee inserire il codice identificativo Objective-C in questo metodo. Per esempio:


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

  1. Nel tuo codice Swift in cui hai impostato l'aspetto, chiama AppearanceBridger.setAppearance()e dovresti essere a posto!

Spero che questo funzioni bene per le persone che lo vedono.


4

Ecco una brutta soluzione alternativa che ho usato ....

Crea una classe di cacao touch Objective-C (UIViewController), chiamata come preferisci.

Ho chiamato il mio WorkaroundViewController...

Ora tra ( WorkaroundViewController.m):

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

Esegui il codice identificativo Objective-C per .appearanceWhenContainedIn()(ecco il mio esempio):

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

Quindi crea un'intestazione ponte per il tuo progetto Swift e quindi inizializza il tuo ViewController Objective-C nel tuo codice Swift, in questo modo (di nuovo, solo il mio esempio):

var work : WorkaroundViewController = WorkaroundViewController()

Allora hai finito! Fammi sapere se funziona per te ... Come ho detto, è brutto, ma funziona!


È una soluzione tmp, penso che dovremmo trovare o aspettare un modo migliore :)
AlexZd

@AlexZd, assolutamente, spero che lo includano rapidamente ... Ma per ora, se ne hai bisogno, eccoti!
LCD

4

Questo può essere esteso a qualsiasi classe conforme al protocollo UIAppearance, non solo a UIVview. Quindi, ecco una versione più generica:

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

3

Ho creato un repository per voi ragazzi che volete usare CocoaPods:

  1. Aggiungi questo nel tuo Podfile:

    pod 'UIViewAppearanceSwift'
  2. Importa nella tua classe:

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


1

Swift 4: iOS 9+

UIProgressView.appearance(whenContainedInInstancesOf: [LNPopupBar.self]).tintColor = .red

0

Sembra che Swift (almeno dalla Beta5) non sia in grado di supportarlo per motivi a me sconosciuti. Forse la funzionalità linguistica richiesta è ancora in corso, poiché posso solo supporre che l'hanno lasciata fuori dall'interfaccia per una buona ragione. Come hai detto, secondo i documenti è ancora disponibile in ObjC. Davvero deludente.


Questo ha funzionato per me in Beta 5 usando il metodo @spinillos.
Jason Crump,

Giusto, ma appearanceWhenContainedIn:è ancora fuori dal tavolo.
hlfcoding del

-3

Puoi usare questo:

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

Modifica: aspectWhenContainedIn è stato rimosso in Swift. Questa risposta era per la Beta 5 per cambiare l'aspetto del testo di tutti i pulsanti della barra.


1
Inoltre, non è necessario utilizzarlo UIControlState.Normal, puoi semplicemente usare .NormalSwift che conosce il tipo per inferenza.
Ben Lachman,

12
questo cambierà aspetto per tutti gli UIBarButtonItems, non per uno specifico
Kostiantyn Koval,

@KonstantinKoval Esattamente - questo è lo scopo dei proxy di aspetto. È possibile modellare l'intera applicazione senza la necessità di contenere chiamate di codice / metodo di boilerplate in ogni controller di visualizzazione.
Craig Otis,

3
Questo in realtà non risponde alla domanda, in Swift appearanceWhenContainedInè stato rimosso.
Tim Windsor Brown

-7

Dovresti essere in grado di tradurre semplicemente la Objective-Csintassi in Swiftsintassi.

In breve i metodi dovrebbero essere dichiarati in questo modo:

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

Quindi puoi provare questo:

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

Devo ancora capire se questo è il modo pulito di chiamare un metodo di classe Swift.

Spero che questo ti aiuti,


1
Non esiste questo metodo aspettoWhenContainedIn in rapido non è compilabile. Errore: "UIBarButtonItem.Type" non ha un membro chiamato "
aspectWhenContainedIn

Ciao @AlexZd, il tuo commento si basa sull'attuale XCode 6 Beta ma se guardi la UIAppearancedocumentazione del protocollo (a cui è UIBarButtonItemconforme), esiste il metodo `aspectWhenContainedIn (_ :) (non è ancora implementato in Swift): developer.apple .com / library / pre-release / ios / documentazione / UIKit / ...
Zedenem

@Zedenem Lo so, è davvero stupido e non vuoi crederci - ma questo metodo non può essere chiamato letteralmente da Swift, controlla la documentazione: developer.apple.com/library/ios/documentation/UIKit/Reference/… - il metodo è nascosto da Swift
powerj1984,

Ciao @ powerj1984, non è che non voglio crederti. Speravo solo al momento in cui ho scritto la mia risposta che questo era dovuto solo allo stato beta di Swift. Il fatto che il metodo non sia stato deprecato ma sia semplicemente nascosto da Swift è davvero strano e non avere alcuna spiegazione da parte di Apple lo rende ancora peggio ... Ma hai ragione, anche se non capisco perché, la mia risposta è sbagliato. Forse c'è una caratteristica in Swift a cui non sto pensando che ci permetterebbe di fare proprio questo ...
Zedenem,

Haha, scusa, intendo davvero che non voglio credermi. È una cosa così sciocca per Apple rovinare. È strano come diamine!
powerj1984,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.