出现在Swift中


125

我正在尝试将我的应用程序转换为Swift语言。

我有这行代码:

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

如何将其转换为Swift?

Apple的文档中,没有这种方法。


1
@LukeTheObscure在下面查看我的答案...丑陋,但可以。
tcd

Answers:


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而不是UIView,也可以支持UIBarButtonItem。@interface UIBarButtonItem(UIViewAppearance_Swift)
迈克尔·彼得森,

1
@rptwsthi:我添加了一个例子斯威夫特3,这是非常略有不同
亚历Pretzlav

1
Swift 3.2的iOS 9版本是UIBarButtonItem.appearance(whenContainedInInstancesOf:[UISearchBar.self])。title =“ Done”
Eli Burke


14

对于iOS 8和7:

我使用基于Alex回答的类别来指定多个容器。在Apple正式支持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

然后添加#import "UIAppearance+Swift.h"到您的桥接头中。

要在Swift中使用

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

如果可以找到一种使用CVarArgType的方法,那很好,但是我没有找到干净的解决方案。


解决varargs破损的好方法!真是太糟糕了,除了(现在)使用Apple的仅iOS 9的方法之外,没有其他通用的解决方案。
Alex Pretzlav 2015年

12

这是一个受@tdun启发的丑陋但仍然丑陋的解决方法。

  1. 创建一个类来保留您的Objective-C外观。出于本示例的目的,我们称之为AppearanceBridger
  2. 将此类添加到您的桥接头中。如果您没有桥接头,请创建一个
  3. AppearanceBridgernamed中创建一个类方法,并将+(void)setAppearanceObjective-C外观代码放入该方法中。例如:


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

  1. 在您设置外观的Swift代码中,调用AppearanceBridger.setAppearance(),一切都会好起来!

希望这对看到它的人有用。


4

这是我使用的一个丑陋的解决方法。

只需创建一个Objective-C可可触摸类(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项目创建一个桥接标头,然后在您的Swift代码中初始化Objective-C ViewController,就像这样(同样,这只是我的示例):

var work : WorkaroundViewController = WorkaroundViewController()

这样就完成了!让我知道它是否对您有用...就像我说的那样,它很难看,但是可以!


这是tmp解决方案,我认为我们应该找到或等待更好的方法:)
AlexZd 2014年

@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

我为想要使用的人创建了一个仓库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方法为我工作。
杰森·克鲁普

对,但appearanceWhenContainedIn:仍然不在桌子上。
hlfcoding

-3

您可以使用此:

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

编辑:appearanceWhenContainedIn在Swift中已删除。答案是Beta 5更改了所有条形按钮的文本外观。


1
另外,不需要使用UIControlState.Normal就可以使用.NormalSwift通过推断知道类型。
Ben Lachman 2014年

12
这将更改所有UIBarButtonItem的外观,而不是特定的外观
Kostiantyn Koval

@KonstantinKoval确实-这是外观代理的目的。您可以对整个应用程序进行样式设置,而不必在每个视图控制器中都包含样板代码/方法调用。
Craig Otis 2014年

3
这实际上并不能回答问题,因为Swift appearanceWhenContainedIn已被删除。
蒂姆·温莎·布朗

-7

您应该能够将Objective-C语法转换为Swift语法。

快速地,方法应该这样声明:

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

因此,您可以尝试以下操作:

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

我仍然必须弄清楚这是否是调用类方法的干净方法Swift

希望这可以帮助,


1
没有这种方法外观,当它很快被编译时,不会被编译。错误:“ UIBarButtonItem.Type”没有名为“ appearanceWhenContainedIn”的成员
AlexZd 2014年

@AlexZd,您好,您的评论基于实际的XCode 6 Beta,但如果您查看UIAppearance协议文档(与之相符UIBarButtonItem),则存在`appearanceWhenContainedIn(_ :)'方法(它尚未在Swift中实现):developer.apple .com / library /
prerelease

@Zedenem我知道,它真的很愚蠢,您不想相信我们-但是从字面上不能从Swift调用此方法,请查看文档:developer.apple.com/library/ios/documentation/UIKit/Reference / ...- 该方法是从夫特隐藏
powerj1984

@ powerj1984您好,这不是我不想相信您。我只是希望在我写答案的时候,这仅仅是由于Swift的beta状态。该方法尚未被弃用,只是被Swift隐藏了,这一事实真的很奇怪,而且苹果公司也没有作出解释,这甚至使情况变得更糟。。。但是,您是对的,即使我不明白为什么,我的回答是错的。Swift也许有一个功能,我没想到,这会让我们做到这一点……
Zedenem 2014年

哈哈,对不起-我的意思是我真的不想相信我。苹果公司搞砸了,真是太愚蠢了。太奇怪了!
powerj1984
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.