Mastering Dark Mode in ROMA: A Complete Guide to Cross‑Platform Theme Adaptation
This article explains how the ROMA cross‑platform framework implements dark mode, covering configuration options, theme‑mode attributes, color mapping, iOS trait handling, and practical code examples for seamless UI theme switching.
Background
Dark mode reduces blue light in low‑light environments, eases eye fatigue, improves contrast and readability, and saves battery life. JD Finance App supports dark mode from version 8.0.20, and the ROMA framework fully supports dark‑mode settings. This article details the ROMA adaptation process.
ROMA Configuration and Usage
The app offers three dark‑mode options: force light, force dark, and follow system. Switching to dark mode does not recreate the view hierarchy, resulting in a smooth transition.
1. View Display Mode Setting
ROMA provides a theme-mode attribute for all tags and pages, indicating the current display mode. Three modes are available:
1 – force light mode
2 – force dark mode
3 – follow mode (inherit from parent or system)
Example:
<template theme-mode=3>
<div style="align-self: stretch; height: 100px; margin: 10px;" theme-mode="1">
<text style="color:#000000; font-size: 12px;">Text test</text>
</div>
</template>Setting theme-mode on a node lets business flexibly customize the display mode for the whole view or individual elements.
2. View Color Setting
Ideally, business can adapt to dark mode without code changes by using a complete color‑mapping table (e.g., color ↔ color-dark) and designing UI according to that table.
For more complex scenarios ROMA offers xxx-dark style properties, such as background-color-dark, color-dark, and src-dark:
<div style="background-color: white; background-color-dark: '#EF4034';">
<text style="color: '#666666'; color-dark:'#F9F9F9';">Text test</text>
<img src="https://img0.baidu.com/it/u=3838093562,4126749835&fm=253&fmt=auto&app=138&f=JPEG?w=1144&h=500" src-dark="https://imgs.699pic.com/images/500/465/562.jpg!list1x.v2">
</div>View Mode Switching Principle Analysis
ROMA simplifies dark‑mode adaptation with simple configuration, but the underlying process involves the entire view hierarchy. The iOS example illustrates how trait changes propagate.
1. UITraitEnvironment Protocol Details
UITraitEnvironment is a fundamental iOS protocol implemented by views and view controllers to monitor interface trait changes such as dark/light mode, device rotation, or size class changes.
@protocol UITraitEnvironment <NSObject>
@property (nonatomic, readonly) UITraitCollection *traitCollection API_AVAILABLE(ios(8.0));
- (void)traitCollectionDidChange:(nullable UITraitCollection *)previousTraitCollection API_DEPRECATED("Use the trait change registration APIs declared in the UITraitChangeObservable protocol", ios(8.0, 17.0), visionos(1.0, 1.0)) API_UNAVAILABLE(watchos);
@endFrom iOS 17 onward, UITraitChangeObservable is recommended for finer‑grained monitoring.
API_AVAILABLE(ios(17.0), tvos(17.0)) API_UNAVAILABLE(watchos) NS_SWIFT_UI_ACTOR
@protocol UITraitChangeObservable
- (id<UITraitChangeRegistration>)registerForTraitChanges:(NSArray<UITrait> *)traits withHandler:(UITraitChangeHandler)handler;
- (id<UITraitChangeRegistration>)registerForTraitChanges:(NSArray<UITrait> *)traits withTarget:(id)target action:(SEL)action;
- (id<UITraitChangeRegistration>)registerForTraitChanges:(NSArray<UITrait> *)traits withAction:(SEL)action;
- (void)unregisterForTraitChanges:(id<UITraitChangeRegistration>)registration;
@end2. Impact of System Trait Changes on View Hierarchy
The trait collection propagates from top to bottom:
System traits are provided by
UIScreen UIWindowinherits traits from UIScreen Root view controller inherits from UIWindow Child view controllers inherit from their parent controllers
Views inherit traits from their view controller
Subviews inherit traits from their parent view
Layer objects listen to the corresponding view’s traits to adjust themselves
3. Setting View Colors Dynamically
Direct color properties (e.g., textColor, backgroundColor) can be set with UIColor dynamic providers so that the appropriate color is automatically used when the interface style changes.
UIColor *dycolor = [UIColor colorWithDynamicProvider:^UIColor * _Nonnull(UITraitCollection * _Nonnull traitCollection) {
if ([traitCollection userInterfaceStyle] == UIUserInterfaceStyleLight) {
return lightResolvedColor;
} else {
return darkResolvedColor ? darkResolvedColor : (lightResolvedColor ? lightResolvedColor : [UIColor clearColor]);
}
}];
view.backgroundColor = dycolor;4. Other View Settings
For layer colors, image resources, Lottie assets, etc., register a theme‑change callback on the view and adjust the layer properties when the mode changes.
UIColor *borderColor = jr_themeColorForTrans(_bordercolor_light, _bordercolor_dark);
CAShapeLayer *borderLayer = [[CAShapeLayer alloc] init];
__weak CAShapeLayer *weakBorderLayer = borderLayer;
[self.view jr_registerForJRThemeChangesWithHandler:^(JRThemeModeStyle style) {
[CATransaction begin];
[CATransaction setDisableActions:YES];
weakBorderLayer.strokeColor = borderColor.CGColor;
[CATransaction commit];
} key:@"jr_trans_layer_border_color_key"];Conclusion
ROMA, as a modern cross‑platform framework, treats dark‑mode adaptation as a comprehensive consideration of user experience, device compatibility, and technical trends. The provided mechanisms give developers flexibility and enable rapid multi‑theme implementation, ultimately delivering higher‑quality products to users.
JD Tech Talk
Official JD Tech public account delivering best practices and technology innovation.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
