I'd like to use new system fonts available since iOS 13 in my React Native app. In particular, I need rounded, serif and monospaced ones. On the native side it is done using UIFontDescriptor.SystemDesign
https://developer.apple.com/videos/play/wwdc2019/227/?time=142
On React Native side we can use { fontFamily: 'System' }
with StyleSheet
but it only gives the default sans-serif design.
Is it possible to use some Swift code to modify the font descriptor of a Text component? Or should I file an issue in React Native repo with a feature request?
React Native doesn't use UIFontDescriptor
with the specified design on iOS but you can use next runtime hackery technique - "Method Swizzling" to intercept the systems call to UIFont
and return a needed one but it should be implemented in ObjC.
Just add this ObjC code to your XCode project:
// UIFont+SystemDesign.m
#import <objc/runtime.h>
@implementation UIFont (SystemDesign)
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Class class = object_getClass((id)self);
SEL originalSelector = @selector(fontWithName:size:);
Method originalMethod = class_getClassMethod(class, originalSelector);
SEL swizzledSelector = @selector(_fontWithName:size:);
Method swizzledMethod = class_getClassMethod(class, swizzledSelector);
BOOL didAddMethod = class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));
if (didAddMethod) {
class_replaceMethod(class, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
}
else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
});
}
#pragma mark - Method Swizzling
+ (UIFont *)_fontWithName:(NSString *)fontName size:(CGFloat)fontSize {
NSString* const systemRounded = @"System-Rounded";
NSString* const systemSerif = @"System-Serif";
NSString* const systemMonospaced = @"System-Monospaced";
NSArray* fonts = @[systemRounded, systemSerif, systemMonospaced];
if ([fonts containsObject:fontName]) {
if (@available(iOS 13.0, *)) {
NSDictionary* designs = @{systemRounded : UIFontDescriptorSystemDesignRounded,
systemSerif : UIFontDescriptorSystemDesignSerif,
systemMonospaced : UIFontDescriptorSystemDesignMonospaced};
UIFontDescriptor *fontDescriptor = [UIFont systemFontOfSize:fontSize].fontDescriptor;
fontDescriptor = [fontDescriptor fontDescriptorWithDesign: designs[fontName]];
return [UIFont fontWithDescriptor:fontDescriptor size:fontSize];
}
else {
return [UIFont systemFontOfSize:fontSize];
}
}
return [self _fontWithName:fontName size:fontSize];
}
@end
Then you can use 'System-Rounded', 'System-Serif' and 'System-Monospaced' fonts into your React Native files:
export default function App() {
return (
<View style={styles.container}>
<Text style={styles.systemDefault}>Default</Text>
<Text style={styles.systemRounded}>Rounded</Text>
<Text style={styles.systemSerif}>Serif</Text>
<Text style={styles.systemMonospaced}>Monospaced</Text>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
systemDefault: {
fontFamily: 'System',
fontSize: 20,
},
systemRounded: {
fontFamily: 'System-Rounded',
fontSize: 20,
},
systemSerif: {
fontFamily: 'System-Serif',
fontSize: 20,
},
systemMonospaced: {
fontFamily: 'System-Monospaced',
fontSize: 20,
},
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With