apariciónCuandoContainedIn en Swift


125

Estoy tratando de convertir mi aplicación al lenguaje Swift.

Tengo esta línea de código:

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

¿Cómo convertirlo a Swift?

En los documentos de Apple , no existe tal método.


1
@LukeTheObscure mira mi respuesta a continuación ... feo, pero funciona.
tcd

Respuestas:


230

Actualización para iOS 9:

Si está apuntando a iOS 9+ (a partir de Xcode 7 b1), hay un nuevo método en el UIAppearanceprotocolo que no usa varargs:

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

Que se puede usar así:

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

Si aún necesita admitir iOS 8 o anterior, use la siguiente respuesta original a esta pregunta.

Para iOS 8 y 7:

Estos métodos no están disponibles para Swift porque los métodos de varargs Obj-C no son compatibles con Swift (consulte http://www.openradar.me/17302764 ).

Escribí una solución no variada que funciona en Swift (repetí el mismo método para UIBarItem, que no desciende 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

Solo asegúrese de hacerlo #import "UIAppearance+Swift.h"en su encabezado de puente.

Luego, para llamar desde Swift (por ejemplo):

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

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

15
UIBarButtonItem no es una UIView y debe ampliarse por separado
Sergey Skoblikov

77
Tenga en cuenta que al menos en iOS8, UIAppearance + Swift.h debería importar UIKit / UIKit.h
Chase

UIBarButtonItem también se puede admitir si solo realiza otro método dirigido a UIBarButtonItem en lugar de UIView. @interface UIBarButtonItem (UIViewAppearance_Swift)
Michael Peterson

1
@rptwsthi: agregué un ejemplo para Swift 3, es muy ligeramente diferente
Alex Pretzlav, el

1
La versión de iOS 9 para Swift 3.2 es UIBarButtonItem.appearance (whenContainedInInstancesOf: [UISearchBar.self]). Title = "Done"
Eli Burke

31

ios 10 swift 3

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

1
No sé por qué esto es un voto negativo, ya que es la forma de hacerlo en iOS10 swift 3 ... Gracias
Vassily

14

Para iOS 8 y 7:

Utilizo una categoría basada en la respuesta de Alex para especificar varios contenedores. Esta es una solución alternativa hasta que Apple sea oficialmente compatible appearanceWhenContainedIncon 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

Luego agregue #import "UIAppearance+Swift.h"a su encabezado de puente.

Para usar desde Swift :

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

Fue bueno poder encontrar una forma de usar CVarArgType , pero no encontré una solución limpia.


¡Buena solución a la fragilidad de los varargs! Es realmente una lástima que no haya otra solución general que no sea (ahora) usar el método solo para iOS 9 de Apple.
Alex Pretzlav

12

Aquí hay una solución menos fea, pero aún fea, inspirada en @tdun.

  1. Crea una clase para mantener tu apariencia de Objective-C. Para los propósitos de este ejemplo, llamémoslo AppearanceBridger.
  2. Agregue esta clase a su encabezado de puente. Si no tiene un encabezado de puente, cree uno .
  3. Cree un método de clase en AppearanceBridgernamed +(void)setAppearancey coloque el código de apariencia Objective-C en este método. Por ejemplo:


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

  1. En su código Swift donde establece la apariencia, llame AppearanceBridger.setAppearance()y ¡debería estar listo!

Espero que esto funcione bien para las personas que lo ven.


4

Aquí hay una solución fea que usé ...

Simplemente haga una clase Objective-C Cocoa Touch Class (UIViewController), llamada lo que quiera.

Yo llamé el mío WorkaroundViewController...

Ahora en ( WorkaroundViewController.m):

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

Ejecute el código de apariencia de Objective-C para .appearanceWhenContainedIn()(aquí está mi ejemplo):

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

Luego cree un encabezado de puente para su proyecto Swift y luego inicialice su Objective-C ViewController en su código Swift, así (de nuevo, solo mi ejemplo):

var work : WorkaroundViewController = WorkaroundViewController()

Entonces has terminado! Avísame si te funciona ... Como dije, es feo, ¡pero funciona!


Es una solución tmp, creo que deberíamos encontrar o esperar a una mejor manera :)
AlexZd

@AlexZd, absolutamente, espero que lo incluyan rápidamente ... Pero por ahora, si lo necesitas, ¡listo!
tcd

4

Esto se puede extender a cualquier clase que se ajuste al protocolo de apariencia UIA, no solo a UIViews. Así que aquí hay una versión más genérica:

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

He creado un repositorio para ustedes que quieran usar CocoaPods:

  1. Agregue esto a su Podfile:

    pod 'UIViewAppearanceSwift'
  2. Importa en tu clase:

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


1

Swift 4: iOS 9+

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

0

Parece que Swift (al menos a partir de Beta5) no puede soportarlo por razones desconocidas para mí. Quizás la función de idioma requerida todavía está en progreso, ya que solo puedo suponer que la dejaron fuera de la interfaz por una buena razón. Como dijiste, según los documentos todavía está disponible en ObjC. Realmente decepcionante.


Esto funcionó para mí en Beta 5 usando el método @spinillos.
Jason Crump

Correcto, pero appearanceWhenContainedIn:todavía está fuera de la mesa.
hlfcoding

-3

Puedes usar esto:

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

Editar: aparienciaWhenContainedIn se eliminó en Swift. Esta respuesta fue para la Beta 5 para cambiar la apariencia del texto de todos los botones de barra.


1
Además, no es necesario usarlo UIControlState.Normal, solo puede usar .NormalSwift conoce el tipo por inferencia.
Ben Lachman

12
esto cambiará la apariencia de todos los UIBarButtonItems, no para uno específico
Kostiantyn Koval

@KonstantinKoval Exactamente - ese es el propósito de los representantes de apariencia. Puede diseñar toda su aplicación sin necesidad de contener el código repetitivo / llamadas al método en cada controlador de vista.
Craig Otis

3
Esto en realidad no responde la pregunta, en Swift appearanceWhenContainedInse ha eliminado.
Tim Windsor Brown

-7

Debería poder traducir la Objective-Csintaxis a Swiftsintaxis.

En rápido los métodos deben declararse así:

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

Entonces puedes probar esto:

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

Todavía tengo que averiguar si esta es la forma limpia de llamar a un método de clase Swift.

Espero que esto ayude,


1
No existe la apariencia de este método cuando Contiene In no se compila rápidamente. Error: 'UIBarButtonItem.Type' no tiene un miembro llamado 'aparienciaWhenContainedIn'
AlexZd

Hola @AlexZd, tu comentario se basa en el XCode 6 Beta real, pero si miras la UIAppearancedocumentación del protocolo (a la que se UIBarButtonItemajusta), existe el método `aparienciaWhenContainedIn (_ :) (todavía no está implementado en Swift): developer.apple .com / library / prerelease / ios / documentation / UIKit / ...
Zedenem

@ Zedenem Lo sé, es realmente tonto y no quieres creernos, pero este método literalmente no se puede llamar desde Swift, consulta la documentación: developer.apple.com/library/ios/documentation/UIKit/Reference/… - el método está oculto de Swift
powerj1984

Hola @ powerj1984, no es que no quiera creerte. En el momento en que escribí mi respuesta, esperaba que esto se debiera al estado beta de Swift. El hecho de que el método no haya quedado en desuso, sino que esté oculto a Swift es realmente extraño, y no tener ninguna explicación de Apple lo hace aún peor ... Pero tienes razón, incluso si no entiendo por qué, mi respuesta Está Mal. Tal vez hay una característica en Swift en la que no estoy pensando que nos permita hacer precisamente eso ...
Zedenem

Jaja, lo siento, quiero decir que no quiero creerme. Es una tontería que Apple se equivoque. Es raro como diablos!
powerj1984
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.