Resources
Resources are externalized data that XWidget loads at initialization — either from local assets or from XWidget Cloud. There are two categories: value resources and fragment resources.
Value Resources
Value resources define named constants in XML files stored in your values directory
(default: resources/values/). They provide a centralized place to manage strings,
colors, and other primitives that your fragments reference.
Defining Values
Create XML files in your values directory. Each file uses a <resources xmlns="https://xwidget.dev/values"> root element
containing typed entries:
<!-- resources/values/strings.xml -->
<resources xmlns="https://xwidget.dev/values">
<string name="app_title">My App</string>
<string name="welcome_message">Welcome to XWidget!</string>
</resources>
<!-- resources/values/colors.xml -->
<resources xmlns="https://xwidget.dev/values">
<color name="primarySwatch">#2196F3</color>
<color name="background">#FFFFFF</color>
<color name="textDark">#262626</color>
</resources>
Supported Types
| Element | Dart Type | Example |
|---|---|---|
<string> |
String |
<string name="title">Hello</string> |
<bool> |
bool |
<bool name="darkMode">true</bool> |
<int> |
int |
<int name="maxRetries">3</int> |
<double> |
double |
<double name="opacity">0.85</double> |
<color> |
Color |
<color name="primary">#2196F3</color> |
Every entry requires a name attribute, which serves as the lookup key.
Accessing Values in Dart
Values are accessed through the Resources singleton using type-specific getters:
final title = Resources.instance.getString("app_title");
final primary = Resources.instance.getColor("primarySwatch");
final retries = Resources.instance.getInt("maxRetries");
final darkMode = Resources.instance.getBool("darkMode");
final opacity = Resources.instance.getDouble("opacity");
If a requested resource does not exist, an exception is thrown.
Accessing Values in Fragments
Value resources are referenced in XML fragments using @ directives. The format is
@type/name, where type matches the resource element type and name matches the
name attribute in your value resource XML.
Strings
<!-- resources/values/strings.xml -->
<resources xmlns="https://xwidget.dev/values">
<string name="app_title">My App</string>
<string name="welcome_message">Welcome to XWidget!</string>
</resources>
Colors
<!-- resources/values/colors.xml -->
<resources xmlns="https://xwidget.dev/values">
<color name="primary">#2196F3</color>
<color name="background">#FFFFFF</color>
</resources>
<!-- fragment usage -->
<Container color="@color/background">
<Text data="Hello" color="@color/primary"/>
</Container>
Booleans
<!-- resources/values/flags.xml -->
<resources xmlns="https://xwidget.dev/values">
<bool name="showWelcome">true</bool>
<bool name="debugMode">false</bool>
</resources>
Integers and Doubles
<!-- resources/values/dimensions.xml -->
<resources xmlns="https://xwidget.dev/values">
<int name="maxItems">25</int>
<double name="defaultPadding">16.0</double>
<double name="borderRadius">8.0</double>
</resources>
<!-- fragment usage -->
<Padding padding="@double/defaultPadding">
<Container borderRadius="@double/borderRadius"/>
</Padding>
Directives vs. Expressions
The @ directive and the expression language ${} serve different purposes.
Directives reference static resource values. Expressions evaluate dynamic data
from dependencies. They cannot be combined in the same attribute value.
<!-- Directive — static resource value -->
<Text data="@string/app_title"/>
<!-- Expression — dynamic dependency value -->
<Text data="${user.name}"/>
Use directives for values that are defined at build time and shared across fragments (colors, labels, dimensions, feature flags). Use expressions for runtime data that comes from controllers and dependencies.
Multiple Value Files
You can organize values across multiple XML files. All files in the values directory are loaded and merged at initialization:
Resource names must be unique within each type across all files.
Fragment Resources
Fragment resources are the XML files that define your UI. They are stored in your
fragments directory (default: resources/fragments/).
Directory Structure
resources/fragments/
├── my_app.xml
├── home.xml
├── settings/
│ ├── index.xml
│ └── profile.xml
└── auth/
├── login.xml
└── register.xml
Fragment Resolution
When inflating a fragment by name, XWidget resolves the file using these rules:
- If the name ends with
.xml, look up the exact path. - Otherwise, try
<name>/index.xmlfirst, then<name>.xml.
// Resolves to "home.xml" or "home/index.xml"
XWidget.inflateFragment("home", dependencies);
// Resolves to "settings/profile.xml"
XWidget.inflateFragment("settings/profile", dependencies);
Registering Asset Directories
All fragment directories (including subdirectories) must be registered in pubspec.yaml:
flutter:
assets:
- resources/fragments/
- resources/fragments/settings/
- resources/fragments/auth/
- resources/values/
Tip
The xc init command automatically registers resources/fragments/ and
resources/values/. You only need to add subdirectories manually.
Custom Resource Bundles
For advanced use cases, you can create custom resource bundle types by extending
ResourceBundle. Register them from a custom Resources subclass during load():
class MyCustomResources extends ResourceBundle {
MyCustomResources() : super('custom');
@override
Future<void> loadFromAssetBundle(
String fileName,
String resPath,
String resName,
String resExt,
AssetBundle assetBundle,
) async {
// Load and parse your custom resource format
}
@override
void loadFromString(
String resPath,
String resName,
String resExt,
String content,
) {
// Parse from string (used by cloud resource loading)
}
}
class MyResources extends LocalResources {
@override
Future<void> load() async {
await super.load();
final custom = MyCustomResources();
// Load or populate the custom bundle here, then register it.
addResourceBundles([custom]);
}
}
await XWidget.initialize(
register: registerXWidgetComponents,
resources: MyResources(),
);
Resources.instance is only available after XWidget.initialize() activates the
resource provider, so custom bundles must be registered by the active provider
itself. Built-in providers load fragment and value bundles; custom bundle loading
is the responsibility of your custom Resources implementation.