การปรากฏเมื่อมีอยู่ในใน 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 เนื่องจากวิธี Obj-C varargs ไม่สามารถทำงานร่วมกับ 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 และจำเป็นต้องขยายแยกต่างหาก
Sergey Skoblikov

7
โปรดทราบว่าอย่างน้อยใน iOS8 UIAppearance + Swift.h ควรนำเข้า UIKit / UIKit.h
Chase

สามารถรองรับ UIBarButtonItem ได้หากคุณสร้างวิธีการอื่นที่กำหนดเป้าหมายเป็น UIBarButtonItem แทน UIView @interface UIBarButtonItem (UIViewAppearance_Swift)
Michael Peterson

1
@rptwsthi: ฉันได้เพิ่มตัวอย่างสำหรับ Swift 3 แล้วมันแตกต่างกันเล็กน้อย
Alex Pretzlav

1
เวอร์ชัน iOS 9 สำหรับ Swift 3.2 คือ UIBarButtonItem.appearance (whenContainedInInstancesOf: [UISearchBar.self]). title = "เสร็จสิ้น"
Eli Burke


14

สำหรับ iOS 8 และ 7:

ฉันใช้หมวดหมู่ตามคำตอบของ Alex เพื่อระบุหลายคอนเทนเนอร์ นี่เป็นวิธีแก้ปัญหาจนกว่า Apple จะสนับสนุนอย่างเป็นทางการappearanceWhenContainedInใน 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

จากนั้นเพิ่ม#import "UIAppearance+Swift.h"ในส่วนหัวเชื่อมของคุณ

วิธีใช้จาก Swift :

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

เป็นการดีถ้าฉันสามารถหาวิธีโดยใช้CVarArgTypeได้ แต่ฉันไม่พบวิธีแก้ปัญหาที่สะอาด


วิธีแก้ปัญหาที่ดีสำหรับความเสียหายของ varargs! แย่จริงๆไม่มีวิธีแก้ปัญหาทั่วไปนอกจาก (ตอนนี้) โดยใช้วิธี iOS 9 เท่านั้นของ Apple
Alex Pretzlav

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 Cocoa Touch Class (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 ไม่ใช่แค่ UIViews ดังนั้นนี่คือเวอร์ชันทั่วไปเพิ่มเติม:

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

ฉันได้สร้าง repo สำหรับพวกคุณที่ต้องการใช้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

ดูเหมือนว่า Swift (อย่างน้อยที่สุดใน Beta5) ไม่สามารถรองรับได้ด้วยเหตุผลที่ฉันไม่รู้จัก บางทีคุณสมบัติภาษาที่จำเป็นยังอยู่ระหว่างดำเนินการเนื่องจากฉันสามารถสันนิษฐานได้ว่าพวกเขาปล่อยมันออกจากอินเทอร์เฟซด้วยเหตุผลที่ดีเท่านั้น อย่างที่คุณพูดตามเอกสารยังมีอยู่ใน ObjC น่าผิดหวังจริงๆ.


สิ่งนี้ใช้ได้ผลสำหรับฉันใน Beta 5 โดยใช้วิธี @spinillos
Jason Crump

ถูกต้อง แต่appearanceWhenContainedIn:ยังคงอยู่นอกตาราง
hlfcoding

-3

คุณสามารถใช้สิ่งนี้:

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

แก้ไข: AppearanceWhenContainedIn ถูกลบออกใน Swift คำตอบนี้สำหรับ Beta 5 ในการเปลี่ยนลักษณะของข้อความของปุ่มแถบทั้งหมด


1
นอกจากนี้ไม่จำเป็นต้องใช้UIControlState.Normalคุณสามารถใช้.NormalSwift รู้ประเภทโดยการอนุมาน
Ben Lachman

12
สิ่งนี้จะเปลี่ยนรูปลักษณ์สำหรับ UIBarButtonItems ทั้งหมดไม่ใช่สำหรับรายการที่เฉพาะเจาะจง
Kostiantyn Koval

@KonstantinKoval แน่นอน - นั่นคือจุดประสงค์ของพร็อกซีที่ปรากฏ คุณสามารถจัดรูปแบบแอปพลิเคชันทั้งหมดของคุณโดยไม่จำเป็นต้องมีการเรียกรหัสต้นแบบ / วิธีการในตัวควบคุมมุมมองทุกตัว
Craig Otis

3
สิ่งนี้ไม่ได้ตอบคำถามจริงใน Swift appearanceWhenContainedInถูกลบออก
Tim Windsor Brown

-7

คุณควรจะแปลObjective-Cไวยากรณ์เป็นSwiftไวยากรณ์ได้

อย่างรวดเร็วควรประกาศวิธีการดังนี้:

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

คุณสามารถลองสิ่งนี้:

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

ฉันยังคงต้องหาว่านี่เป็นวิธีที่สะอาดในการเรียกเมธอดคลาสSwiftหรือไม่

หวังว่านี่จะช่วยได้


1
ไม่มีลักษณะของเมธอดนี้ WhenContainedIn อย่างรวดเร็วมันไม่ได้รวบรวม ข้อผิดพลาด: 'UIBarButtonItem.Type' ไม่มีสมาชิกชื่อ '
AppearanceWhenContainedIn

สวัสดี @AlexZd ความคิดเห็นของคุณอ้างอิงจาก XCode 6 Beta จริง แต่ถ้าคุณดูUIAppearanceเอกสารโปรโตคอล (ที่เป็นไปตามนั้นUIBarButtonItem) จะมีเมธอด `AppearanceWhenContainedIn (_ :) (ยังไม่ได้ใช้ใน Swift): developer.apple .com / library / prerelease / ios / documentation / UIKit / …
Zedenem

@ Zedenem ฉันรู้ว่ามันโง่จริงๆและคุณไม่อยากเชื่อเรา - แต่วิธีนี้ไม่สามารถเรียกจาก Swift ได้อย่างแท้จริงตรวจสอบเอกสาร: developer.apple.com/library/ios/documentation/UIKit/Reference/… - วิธีนี้ถูกซ่อนจาก Swift
powerj1984

สวัสดี @ powerj1984 ไม่ใช่ว่าฉันไม่อยากเชื่อคุณ ฉันแค่หวังว่าในตอนนั้นฉันจะเขียนคำตอบว่านี่เป็นเพราะสถานะเบต้าของ Swift ความจริงที่ว่าวิธีนี้ไม่ได้ถูกเลิกใช้งาน แต่ถูกซ่อนไว้จาก Swift นั้นแปลกจริงๆและการไม่มีคำอธิบายจาก Apple ทำให้แย่ที่สุด ... แต่คุณพูดถูกแม้ว่าฉันจะไม่เข้าใจว่าทำไมคำตอบของฉัน มันผิด. อาจจะมีฟีเจอร์ใน Swift ที่ฉันไม่คิดว่าจะทำให้เราทำแบบนั้นได้ ...
Zedenem

ฮ่า ๆ ขอโทษ - ฉันหมายความว่าไม่อยากจะเชื่อฉันจริงๆ มันเป็นเรื่องโง่ ๆ สำหรับ Apple ที่จะทำผิด มันแปลกมาก!
powerj1984
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.