xml_layout 2.3.15
xml_layout: ^2.3.15 copied to clipboard
XML layout for flutter. Layout your widgets with xml at runtime.
xml_layout #
XML layout for flutter. Layout your UI via xml at runtime. and support extending any customer widget. Here is a online preview.
Getting Started #
write xml layout file like:
xml
<Text mainAxisAlignment="center">
<for count="6">
<Text>$item, You have pushed the button this many times:</Text>
</for>
<Text id="text-id">
<attr:style>
<TextStyle color="red"/>
</attr:style>
$counter
</Text>
</Column>
dart
XMLLayout(
temp: snapshot.data,
objects: {
"counter": _counter
},
)
In this case
$counter for passing argument to the layout.
id attribute for selecting the widget or state.
XMLLayoutState state = ...;
// find the key of the Text
GlobalKey key = state.find('text-id');
Registers #
register- description: Register a constructor. It could convert a xml element to target object.
/**
* Register a constructor
*
* xml:
* <MyClass width="10" height="10" />
*
*/
XMLLayout.register('MyClass', (node, key) {
return MyClass(
key: key,
child: node.child<Widget>(),
width: node.s<double>("width"),
height: node.s<double>("height"),
);
});
registerEnum- description: A shortcat to register a enum class. It could convert a attribute to the enum.
/**
* Register a enum type
*
* xml:
* <Text textAlign="center">str</Text>
*/
XMLLayout.registerEnum(TextAlign.values);
registerInline(Type type, String name, bool field, InlineItemConstructor constructor)- description: Register a constructor which could convert a attribute to target type.
- arguments:
fieldthis constructor is for a static field or a constructor.
/**
* <Text fontWeight="w200">str</Text>
*/
XmlLayout.registerInline(FontWeight, "w200", true, (node, method) {
return FontWeight.w200;
});
/**
* <Text textHeightBehavior="fromEncoded(20)">str</Text>
*/
XmlLayout.registerInline(TextHeightBehavior, "fromEncoded", false,
(node, method) {
return TextHeightBehavior.fromEncoded(int.tryParse(method[0]));
});
node.s<T>("name"), node.attribute<T>("name") convert subnode to target type
node.t<T>(), node.convert<T>() convert this node to target type
node.v<T>("value"), node.value<T>("value") convert text to target type
Widget Builder #
<ListView.separated itemCount="$itemCount">
<attr:itemBuilder>
<Function returnType="Widget">
<!-- get arguments of function via args -->
<SetArgument return="index" argument="${args[1]}"/>
<Call function="$getItem" return="itemData">
<!-- pass argument to getItem function -->
<Argument value="$index"/>
</Call>
<!-- The last element of Function tag would be the final result -->
<Text>${itemData.title}</Text>
</Function>
</attr:itemBuilder>
</ListView.separated>
Script #
<Function>
<Script>
set("index", ${args[1]})
set("itemData", getItem($index))
</Script>
<!-- same as -->
<SetArgument return="index" argument="${args[1]}"/>
<Call function="$getItem" return="itemData">
<Argument value="$index"/>
</Call>
<!-- end(same as) -->
<Text>${itemData.title}</Text>
</Function>
Method #
Method could be registerd via XmlLayout.registerInlineMethod, and
can be used in a Xml attribute or Script tag.
Default methods:
isEmpty(a)=> a.isEmpty()isNotEmpty(a)=> a.isNotEmpty()equal(a, b, ...)=> a == b ...net(a, b)=> a != bmod(a, b)=> a % bdiv(a, b)=> a / bset(name, a)=> env[name] = anot(a)=> !alt(a, b)=> a < bnlt(a, b)=> a >= bgt(a, b)=> a > bngt(a, b)=> a <= bplus(a, b, ...)=> a + b ...minus(a, b, ...)=> a - b ...multiply(a, b, ...)=> a * b ...divide(a, b, ...)=> a / b ...
Control Flow #
A util to control the rendering logic. like:
<for count="$counter">
<Text>$item, You have pushed the button this many times:</Text>
<if candidate="equal(1, mod($item, 2))">
<Text>Test text</Text>
</if>
</for>
iftag is a if control flow.- attributes:
candidatea Boolean value, if true the children would be rendered, otherwise not be rendered.
- attributes:
elsetag is a else control flow, could be placed afterifor anotherelsetag.- attributes:
candidatesame asiftag.
- attributes:
fortag is a loop control flow.- attributes:
arraya List value, iterates over array elements, each element for children one time.counta Integer value, iterates children the value times. It is mutually exclusive with thearrayattribute.itema String value, the name of each element, default isitem.indexa String value, the name of the index of element, default isindex.
- attributes:
Builder #
You can write a script to generate the constructor code.
In the example test.dart is the builder script.
Builder options:
entry_name- default:
types - type:
List<Type> - description: types in this list which will be processed.
- default:
collections_name- default:
collections - type:
List<Collection> - description: Collection type is used to process the collection class, such as:
ColorsandIcons.
- default:
ps: Colors and Icons is preprocessed just import it via:
import 'package:xml_layout/types/colors.dart' as colors;
import 'package:xml_layout/types/icons.dart' as icons;
// ...
colors.register();
icons.register();
coverts_name- default:
converts - type:
Map<String, String> - description: Every import uri will be test by the key value pair in this variable. if a import source uri is start with the key then it will be convert to the value.
- default:
imports_name- default:
imports - type:
List<String> - description: Extension import uris which will be write to the generated code.
- default:
Example
lib/test.dart
import 'package:flutter/material.dart';
const List<Type> types = [
Text,
];
build.yaml
targets:
$default:
builders:
xml_layout:
generate_for:
- lib/test.dart
Create the files above, then just run flutter pub run build_runner build.
And you will get the generated code in lib/test.xml_layout.dart.