PenampilanWhenContainedIn in Swift

125

Saya mencoba mengonversi aplikasi saya ke bahasa Swift.

Saya memiliki baris kode ini:

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

Bagaimana cara mengubahnya ke Swift?

Dalam dokumen Apple , tidak ada metode seperti itu.

AlexZd
sumber
1
@LukeTheObscure periksa jawaban saya di bawah ini ... jelek, tapi berhasil.
tcd

Jawaban:

230

Pembaruan untuk iOS 9:

Jika Anda menargetkan iOS 9+ (pada Xcode 7 b1), ada metode baru dalam UIAppearanceprotokol yang tidak menggunakan varargs:

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

Yang bisa digunakan seperti ini:

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

Jika Anda masih perlu mendukung iOS 8 atau yang lebih lama, gunakan jawaban asli berikut untuk pertanyaan ini.

Untuk iOS 8 & 7:

Metode ini tidak tersedia untuk Swift karena metode Obj-C varargs tidak kompatibel dengan Swift (lihat http://www.openradar.me/17302764 ).

Saya menulis solusi non-variadik yang bekerja di Swift (saya mengulangi metode yang sama untuk UIBarItem, yang tidak turun dari 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

Pastikan untuk berada #import "UIAppearance+Swift.h"di header bridging Anda.

Kemudian, untuk menelepon dari Swift (misalnya):

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

# Swift 3.x:
UITextField.my_appearanceWhenContained(in: MyViewController.self).keyboardAppearance = .light
Alex Pretzlav
sumber
15
UIBarButtonItem bukan UIView dan perlu diperpanjang secara terpisah
Sergey Skoblikov
7
Perhatikan bahwa setidaknya di iOS8, UIAppearance + Swift.h harus mengimpor UIKit / UIKit.h
Mengejar
UIBarButtonItem dapat didukung juga jika Anda hanya membuat metode lain yang menargetkan UIBarButtonItem alih-alih UIView. @interface UIBarButtonItem (UIViewAppearance_Swift)
Michael Peterson
1
@ rptwsthi: Saya telah menambahkan contoh untuk Swift 3, ini sedikit berbeda
Alex Pretzlav
1
Versi iOS 9 untuk Swift 3.2 adalah UIBarButtonItem.appearance (whenContainedInInstancesOf: [UISearchBar.self]). Title = "Done"
Eli Burke
31

ios 10 swift 3

UIBarButtonItem.appearance(whenContainedInInstancesOf: [UISearchBar.self]).title = "Kapat"
Piotr Tomasik
sumber
1
Tidak tahu mengapa ini downvote karena ini adalah cara untuk melakukannya di iOS10 swift 3 ... Terima kasih
Vassily
14

Untuk iOS 8 & 7:

Saya menggunakan kategori berdasarkan jawaban Alex untuk menentukan beberapa wadah. Ini adalah solusi sampai Apple secara resmi mendukungappearanceWhenContainedIn di Swift.

Penampilan UIA + Swift.h

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

Penampilan 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

Lalu tambahkan #import "UIAppearance+Swift.h" ke header bridging Anda.

Untuk digunakan dari Swift :

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

Itu baik jika saya dapat menemukan cara menggunakan CVarArgType , tetapi saya tidak menemukan solusi bersih.

Yoichi Tagaya
sumber
Solusi yang bagus untuk memecahkan kerusakan varargs! Sayang sekali tidak ada solusi umum selain (sekarang) menggunakan metode iOS 9-only Apple.
Alex Pretzlav
12

Ini solusi yang kurang jelek, tapi masih jelek, terinspirasi oleh @tdun.

  1. Buat kelas untuk menahan penampilan Objective-C Anda. Untuk keperluan contoh ini, sebut saja AppearanceBridger.
  2. Tambahkan kelas ini ke header bridging Anda. Jika Anda tidak memiliki header penghubung, buatlah satu .
  3. Buat metode kelas dengan AppearanceBridgernama +(void)setAppearancedan masukkan kode penampilan Objective-C dalam metode ini. Sebagai contoh:


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

  1. Dalam kode Swift tempat Anda mengatur tampilan, panggil AppearanceBridger.setAppearance()dan Anda harus siap berangkat!

Semoga ini bekerja dengan baik untuk orang yang melihatnya.

Baub
sumber
4

Inilah solusi buruk yang saya gunakan ....

Buat saja Object Touch-Cocoa Touch Class (UIViewController), beri nama apa pun yang Anda inginkan.

Saya menamai milik saya WorkaroundViewController...

Sekarang di ( WorkaroundViewController.m):

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

Jalankan kode penampilan Objective-C untuk .appearanceWhenContainedIn()(inilah contoh saya):

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

Kemudian buat header penghubung untuk proyek Swift Anda dan kemudian inisialisasi ViewController Objective-C Anda dalam kode Swift Anda, seperti ini (sekali lagi, hanya contoh saya):

var work : WorkaroundViewController = WorkaroundViewController()

Lalu kamu selesai! Biarkan saya tahu jika itu bekerja untuk Anda ... Seperti saya katakan, itu jelek, tapi berhasil!

tcd
sumber
Ini adalah solusi tmp, saya pikir kita harus mencari atau menunggu cara yang lebih baik :)
AlexZd
@AlexZd, tentu saja, saya harap mereka memasukkannya dengan cepat ... Tapi untuk sekarang, jika Anda membutuhkannya, ini dia!
tcd
4

Ini dapat diperluas ke kelas apa saja yang sesuai dengan protokol UIApearance - bukan hanya UIViews. Jadi inilah versi yang lebih umum:

Penampilan UIA + Swift.h

#import <UIKit/UIKit.h>

@interface NSObject (UIAppearance_Swift)

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

@end

Penampilan 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
Eddie K.
sumber
3

Saya telah membuat repo untuk Anda yang ingin menggunakan CocoaPods:

  1. Tambahkan ini ke Anda Podfile:

    pod 'UIViewAppearanceSwift'
  2. Impor di kelas Anda:

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

Tai Le
sumber
1

Swift 4: iOS 9+

UIProgressView.appearance(whenContainedInInstancesOf: [LNPopupBar.self]).tintColor = .red
Maksim Kniazev
sumber
0

Tampaknya Swift (setidaknya pada Beta5) tidak dapat mendukungnya karena alasan yang tidak saya ketahui. Mungkin fitur bahasa yang diperlukan masih dalam proses, karena saya hanya bisa berasumsi mereka meninggalkannya karena alasan yang baik. Seperti yang Anda katakan, menurut dokumen itu masih tersedia di ObjC. Sangat mengecewakan.

hlfcoding
sumber
Ini bekerja untuk saya dalam Beta 5 menggunakan metode @spinillos.
Jason Crump
Benar, tetapi appearanceWhenContainedIn:masih dari meja.
hlfcoding
-3

Anda bisa menggunakan ini:

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

Sunting: penampilanWhenContainedIn dihapus di Swift. Jawaban ini adalah untuk Beta 5 untuk mengubah tampilan teks dari semua tombol bar.

spinillos
sumber
1
Juga, tidak perlu menggunakan UIControlState.NormalAnda hanya dapat menggunakan .NormalSwift tahu jenisnya dengan inferensi.
Ben Lachman
12
ini akan mengubah tampilan untuk semua UIBarButtonItems, bukan untuk yang spesifik
Kostiantyn Koval
@KonstantinKoval Persis - itulah tujuan dari proksi penampilan. Anda dapat menata seluruh aplikasi tanpa perlu memuat kode boilerplate / panggilan metode di setiap pengontrol tampilan.
Craig Otis
3
Ini sebenarnya tidak menjawab pertanyaan, di Swift appearanceWhenContainedIntelah dihapus.
Tim Windsor Brown
-7

Anda seharusnya bisa menerjemahkan Objective-Csintaks ke dalamSwift sintaksis.

Dalam cepat metode harus dinyatakan seperti ini:

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

Jadi Anda dapat mencoba ini:

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

Saya masih harus mencari tahu apakah ini adalah cara yang bersih untuk memanggil metode kelas Swift.

Semoga ini membantu,

Zedenem
sumber
1
Tidak ada metode ini penampilanWhenContainedIn di cepat itu tidak dikompilasi. Kesalahan: 'UIBarButtonItem.Type' tidak memiliki anggota bernama 'appearanceWhenContainedIn'
AlexZd
Hai @AlexZd, komentar Anda didasarkan pada XCode 6 Beta yang sebenarnya tetapi jika Anda melihat UIAppearancedokumentasi protokol (yang UIBarButtonItemsesuai), metode `appearanceWhenContainedIn (_ :) ada (itu belum diterapkan di Swift): developer.apple .com / perpustakaan /
pra
@ Zedenem Saya tahu, ini benar-benar bodoh dan Anda tidak ingin mempercayai kami - tetapi metode ini benar-benar tidak dapat dipanggil dari Swift, periksa dokumentasi: developer.apple.com/library/ios/documentation/UIKit/Reference/… - metode ini disembunyikan dari Swift
powerj1984
Hai @ powerj1984, bukan karena aku tidak ingin percaya padamu. Saya hanya berharap pada saat saya menulis jawaban saya bahwa ini hanya karena status beta Swift. Fakta bahwa metode ini tidak ditinggalkan tetapi hanya disembunyikan dari Swift benar-benar aneh, dan tidak memiliki penjelasan dari Apple menjadikannya lebih buruk ... Tapi Anda benar, bahkan jika saya tidak mengerti mengapa, jawaban saya salah. Mungkin ada fitur di Swift yang tidak saya pikirkan yang memungkinkan kami melakukan hal itu ...
Zedenem
Haha, maaf - maksud saya, saya tidak ingin mempercayai saya. Sungguh konyol bagi Apple untuk mengacau. Aneh sekali!
powerj1984