Ignoring the dynamic type in iOS: Accessibility

2020-02-05 18:42发布

问题:

Is there a way to completely ignore dynamic type/font size settings in iOS apps? I mean is there a way like a plist entry so that I can disable it completely. I understand there is a notification we can observe and re-configure the font whenever there is change in the settings. I am looking for a simpler solution. I am using iOS8. Thanks.

回答1:

There's no need to swizzle UIApplication. Just subclass UIApplication and provide your own implementation of preferredContentSizeCategory:

Swift:

class MyApplication: UIApplication {

    override var preferredContentSizeCategory: UIContentSizeCategory {
        get { return UIContentSizeCategory.large }
    }
}

UIApplicationMain(
    CommandLine.argc,
    CommandLine.unsafeArgv,
    NSStringFromClass(MyApplication.self),
    NSStringFromClass(AppDelegate.self)
)

Objective-C:

@interface MyApplication : UIApplication
@end

@implementation MyApplication

- (UIContentSizeCategory) preferredContentSizeCategory
{
    return UIContentSizeCategoryLarge;
}

@end

int main(int argc, char * argv[]) {
    @autoreleasepool {
        return UIApplicationMain(argc, argv, NSStringFromClass([MyApplication class]), NSStringFromClass([AppDelegate class]));
    }
}


回答2:

The swift equivalent to the answer of @meaning-matters looks as follows:

In your AppDelegate:

@objc func swizzled_preferredContentSizeCategory() -> UIContentSizeCategory {
    return UIContentSizeCategory.small
}

open func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    let originalMethod = class_getInstanceMethod(UIApplication.self, #selector(preferredContentSizeCategory))
    let swizzledMethod = class_getInstanceMethod(UIApplication.self, #selector(swizzled_preferredContentSizeCategory))
    method_exchangeImplementations(originalMethod, swizzled_preferredContentSizeCategory)
}


回答3:

In your AppDelegate add:

#import <objc/runtime.h>

@implementation AppDelegate

NSString* swizzled_preferredContentSizeCategory(id self, SEL _cmd)
{
    return UIContentSizeCategoryLarge;  // Set category you prefer, Large being iOS' default.
}

- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
{
    Method method = class_getInstanceMethod([UIApplication class], @selector(preferredContentSizeCategory));
    method_setImplementation(method, (IMP)swizzled_preferredContentSizeCategory);

    ...
}


回答4:

Just provide Swift 4 fix to @gebirgsbärbel answer. "preferredContentSizeCategory" in Objective-C is a method, but in Swift it is a read-only variable. So in your AppDelegate is like this:

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    // MARK: - UIApplicationDelegate

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {

        UIApplication.classInit

        self.window = UIWindow(frame: UIScreen.main.bounds)
        ...
        self.window?.makeKeyAndVisible()
        return true
    }
}

// MARK: - Fix Dynamic Type

extension UIApplication {

    static let classInit: Void = {
        method_exchangeImplementations(
            class_getInstanceMethod(UIApplication.self, #selector(getter: fixedPreferredContentSizeCategory))!,
            class_getInstanceMethod(UIApplication.self, #selector(getter: preferredContentSizeCategory))!
        )
    }()

    @objc
    var fixedPreferredContentSizeCategory: UIContentSizeCategory {
        return .large
    }
}