xuất hiệnWhenContainedIn trong Swift


125

Tôi đang cố gắng chuyển đổi ứng dụng của mình sang ngôn ngữ Swift.

Tôi có dòng mã này:

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

Làm thế nào để chuyển đổi nó thành Swift?

Trong các tài liệu của Apple , không có phương pháp nào như vậy.


1
@LukeTheObscure kiểm tra câu trả lời của tôi dưới đây ... xấu, nhưng hoạt động.
tcd

Câu trả lời:


230

Cập nhật cho iOS 9:

Nếu bạn đang nhắm mục tiêu iOS 9+ (kể từ Xcode 7 b1), có một phương thức mới trong UIAppearancegiao thức không sử dụng varargs:

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

Mà có thể được sử dụng như vậy:

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

Nếu bạn vẫn cần hỗ trợ iOS 8 hoặc sớm hơn, hãy sử dụng câu trả lời ban đầu sau cho câu hỏi này.

Dành cho iOS 8 & 7:

Các phương thức này không có sẵn cho Swift vì các phương thức varargs Obj-C không tương thích với Swift (xem http://www.openradar.me/17302764 ).

Tôi đã viết một cách giải quyết khác không hoạt động trong Swift (Tôi đã lặp lại cùng một phương thức UIBarItem, không xuất phát từ đó 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

Chỉ cần chắc chắn #import "UIAppearance+Swift.h"trong tiêu đề bắc cầu của bạn.

Sau đó, để gọi từ Swift (ví dụ):

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

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

15
UIBarButtonItem không phải là một UIView và cần được gia hạn riêng
Serge Skoblikov

7
Lưu ý rằng ít nhất trong iOS8, UIAppparent + Swift.h nên nhập UIKit / UIKit.h
Đuổi theo

UIBarButtonItem cũng có thể được hỗ trợ nếu bạn chỉ thực hiện một phương pháp khác nhắm mục tiêu UIBarButtonItem thay vì UIView. @interface UIBarButtonItem (UIViewAppparent_Swift)
Michael Peterson

1
@rptwsthi: Tôi đã thêm một ví dụ cho Swift 3, nó hơi khác một chút
Alex Pretzlav

1
Phiên bản iOS 9 cho Swift 3.2 là UIBarButtonItem.appparent (khiContainedInInstancesOf: [UISearchBar.elf]). Title = "Xong"
Eli Burke

31

ios 10 swift 3

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

1
Không biết lý do tại sao điều này là downvote vì đó là cách để làm điều đó trong iOS10 swift 3 ... Cảm ơn
Vassily

14

Dành cho iOS 8 & 7:

Tôi sử dụng một danh mục dựa trên câu trả lời của Alex để chỉ định nhiều container. Đây là một cách giải quyết cho đến khi Apple chính thức hỗ trợ appearanceWhenContainedIntrong Swift.

UIAppurdy + Swift.h

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

UIAppurdy + 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

Sau đó thêm #import "UIAppearance+Swift.h"vào tiêu đề bắc cầu của bạn.

Để sử dụng từ Swift :

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

Thật tốt nếu tôi có thể tìm cách sử dụng CVarArgType , nhưng tôi không tìm thấy giải pháp sạch nào.


Cách giải quyết tốt đẹp cho sự thất bại của varargs! Thật sự quá tệ khi không có giải pháp chung nào ngoài (hiện tại) sử dụng phương pháp chỉ dành cho iOS 9 của Apple.
Alex Pretzlav

12

Đây là một cách giải quyết ít xấu xí hơn nhưng vẫn xấu xí được lấy cảm hứng từ @tdun.

  1. Tạo một lớp để giữ giao diện Objective-C của bạn. Đối với mục đích của ví dụ này, hãy gọi nó AppearanceBridger.
  2. Thêm lớp này vào tiêu đề bắc cầu của bạn. Nếu bạn không có tiêu đề bắc cầu, hãy tạo một tiêu đề .
  3. Tạo một phương thức lớp AppearanceBridgerđược đặt tên +(void)setAppearancevà đặt mã xuất hiện Objective-C trong phương thức này. Ví dụ:


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

  1. Trong mã Swift của bạn nơi bạn đặt giao diện, hãy gọi AppearanceBridger.setAppearance()và bạn sẽ thấy ổn!

Hy vọng điều này hoạt động tốt cho những người nhìn thấy nó.


4

Đây là một giải pháp khắc phục xấu xí mà tôi đã sử dụng ....

Chỉ cần tạo Lớp cảm ứng Cive Objective-C (UIViewContoder), đặt tên bất cứ thứ gì bạn muốn.

Tôi đặt tên cho tôi WorkaroundViewController...

Bây giờ trong ( WorkaroundViewController.m):

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

Chạy mã xuất hiện Objective-C cho .appearanceWhenContainedIn()(đây là ví dụ của tôi):

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

Sau đó, tạo một tiêu đề bắc cầu cho dự án Swift của bạn và sau đó khởi tạo ViewContoder Objective-C của bạn trong mã Swift của bạn, như thế này (một lần nữa, chỉ là ví dụ của tôi):

var work : WorkaroundViewController = WorkaroundViewController()

Vậy là xong! Hãy cho tôi biết nếu nó hoạt động cho bạn ... Như tôi đã nói, nó xấu, nhưng hoạt động!


Đó là giải pháp tmp, tôi nghĩ chúng ta nên tìm hoặc chờ một cách tốt hơn :)
AlexZd

@AlexZd, hoàn toàn, tôi hy vọng họ đưa nó vào swift ... Nhưng bây giờ, nếu bạn cần nó, bạn sẽ đi!
tcd

4

Điều này có thể được mở rộng cho bất kỳ lớp nào phù hợp với giao thức UIAppurdy - không chỉ UIViews. Vì vậy, đây là một phiên bản chung hơn:

UIAppurdy + Swift.h

#import <UIKit/UIKit.h>

@interface NSObject (UIAppearance_Swift)

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

@end

UIAppurdy + 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

Tôi đã tạo một repo cho các bạn muốn sử dụng CocoaPods:

  1. Thêm phần này vào Podfile:

    pod 'UIViewAppearanceSwift'
  2. Nhập trong lớp của bạn:

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


1

Swift 4: iOS 9+

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

0

Có vẻ như Swift (ít nhất là Beta5) không thể hỗ trợ nó vì những lý do mà tôi không biết. Có lẽ tính năng ngôn ngữ cần thiết vẫn đang được tiến hành, vì tôi chỉ có thể giả sử họ rời khỏi giao diện vì một lý do chính đáng. Như bạn đã nói, theo các tài liệu, nó vẫn có sẵn trong ObjC. Thật đáng thất vọng.


Điều này làm việc cho tôi trong bản Beta 5 bằng phương pháp @spinillos.
Jason Crump

Phải, nhưng appearanceWhenContainedIn:vẫn ra khỏi bàn.
hlfcoding

-3

Bạn có thể sử dụng điều này:

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

Chỉnh sửa: xuất hiệnWhenContainedIn đã bị xóa trong Swift. Câu trả lời này là dành cho Beta 5 để thay đổi giao diện của văn bản của tất cả các nút trên thanh.


1
Ngoài ra, không cần sử dụng, UIControlState.Normalbạn chỉ cần sử dụng .NormalSwift là biết loại bằng suy luận.
Ben Lachman

12
điều này sẽ thay đổi ngoại hình cho tất cả UIBarButtonItems, không phải cho một người cụ thể
Kostiantyn Koval

@KonstantinKoval Chính xác - đó là mục đích của các proxy xuất hiện. Bạn có thể định kiểu toàn bộ ứng dụng của mình mà không cần phải chứa các lệnh gọi mã / phương thức soạn sẵn trong mọi bộ điều khiển xem.
Craig Otis

3
Điều này không thực sự trả lời câu hỏi, trong Swift appearanceWhenContainedInđã bị xóa.
Tim Windsor Brown

-7

Bạn sẽ có thể chỉ cần dịch Objective-Ccú pháp thành Swiftcú pháp.

Trong swift các phương thức nên được khai báo như thế này:

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

Vì vậy, bạn có thể thử điều này:

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

Tôi vẫn phải tìm hiểu xem đây có phải là cách sạch để gọi một phương thức lớp hay không Swift.

Hi vọng điêu nay co ich,


1
Không có phương thức này xuất hiệnWhenContainedIn trong swift nó không được biên dịch. Lỗi: 'UIBarButtonItem.Type' không có thành viên có tên 'ngoại
hìnhWhenContainedIn

Xin chào @AlexZd, nhận xét của bạn dựa trên XCode 6 Beta thực tế nhưng nếu bạn xem UIAppearancetài liệu giao thức ( UIBarButtonItemtuân thủ), thì phương thức `ngoại hìnhWhenContainedIn (_ :) vẫn chưa được triển khai trong Swift): developer.apple .com / library / prerelease / ios / Tài liệu / UIKit / Sự
Zedenem 23/07/14

@Zedenem Tôi biết, nó thực sự ngu ngốc và bạn không muốn tin chúng tôi - nhưng phương thức này theo nghĩa đen không thể được gọi từ Swift, hãy kiểm tra tài liệu: developer.apple.com/l Library / ios / document / UIKit / Reference / / - - phương thức được ẩn khỏi Swift
powerj1984

Xin chào @ powerj1984, không phải tôi không muốn tin bạn. Tôi chỉ hy vọng vào thời điểm tôi viết câu trả lời của mình rằng đây chỉ là do trạng thái beta của Swift. Thực tế là phương pháp này không bị phản đối nhưng chỉ bị ẩn khỏi Swift thực sự kỳ lạ và không có lời giải thích nào từ Apple khiến nó trở nên tồi tệ nhất ... Nhưng bạn đã đúng, ngay cả khi tôi không hiểu tại sao, câu trả lời của tôi sai. Có lẽ có một tính năng trong Swift Tôi không nghĩ về điều đó sẽ cho phép chúng tôi làm điều đó ...
Zedenem

Haha, xin lỗi - tôi thực sự có nghĩa là tôi không muốn tin tôi. Đó chỉ là một điều ngớ ngẩn để Apple làm hỏng việc. Thật là kỳ quái!
powerj1984
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.