@TOC
在项目中使用框架Arms时候,带有一键生成页面模板,很方面。最近在练习MVVM,于是尝试编写一套页面模板。
IDE 自带很多模板,可以看到内置了很多模板,减少了部分代码的编写,我们可以根据这些模板代码去学习如何定制页面模板
以==EmptyActivity==进行分析,模板放置路径为:==/plugins/android/lib/templates/activities== 可以看到每一个模板都包含如图所示的文件
- root 资源文件、模板文件
- src
- app_package
- SimpleActivity.kt.ftl
- app_package
- res
- layout
- src
- globals.xml.ftl 主要用于提供参数
- recipe.xml.ftl 主要用于生成我们实际需要的代码,资源文件等
- template.xml parameter标签,主要用于为图形界面提供参数
- template_balnk_activity.png 缩略图
我们可以看到主要代码如下
<?xml version="1.0"?>
<template
format="5"
revision="5"
name="Empty Activity" 模板名称
minApi="9"
minBuildApi="14"
description="Creates a new empty activity">
<category value="Activity" /> 模板类型
<formfactor value="Mobile" />
<parameter 参数变量
id="activityClass" 变量名, 变量的唯一标识
name="Activity Name" 在创建Activity时展示的变量名
type="string" 类型
constraints="class|unique|nonempty" 变量约束
suggest="${layoutToActivity(layoutName)}" 推荐值,未修改变量时根据其他变量生成
default="MainActivity" 默认值
help="The name of the activity class to create" /> 当编辑一个变量时,显示在下方的提示
<!-- 128x128 thumbnails relative to template.xml -->
<thumbs> 缩略图
<!-- default thumbnail is required -->
<thumb>template_blank_activity.png</thumb>
</thumbs>
<globals file="globals.xml.ftl" />
<execute file="recipe.xml.ftl" />
</template>
globals 存储的一些全局变量
<?xml version="1.0"?>
<globals>
<global id="hasNoActionBar" type="boolean" value="false" />
<global id="parentActivityClass" value="" />
<global id="simpleLayoutName" value="${layoutName}" />
<global id="excludeMenu" type="boolean" value="true" />
<global id="generateActivityTitle" type="boolean" value="false" />
<#include "../common/common_globals.xml.ftl" />
</globals>
<?xml version="1.0"?>
<#import "root://activities/common/kotlin_macros.ftl" as kt>
<recipe>
<#include "../common/recipe_manifest.xml.ftl" />
<@kt.addAllKotlinDependencies />
<#if generateLayout>
<#include "../common/recipe_simple.xml.ftl" />
<open file="${escapeXmlAttribute(resOut)}/layout/${layoutName}.xml" />
</#if>
<instantiate from="root/src/app_package/SimpleActivity.${ktOrJavaExt}.ftl"
to="${escapeXmlAttribute(srcOut)}/${activityClass}.${ktOrJavaExt}" />
<open file="${escapeXmlAttribute(srcOut)}/${activityClass}.${ktOrJavaExt}" />
</recipe>
recipe中主要使用以下五种指令:
- copy: 将from属性指定文件或一整个文件夹复制到to指定的位置。如果to属性不写,会采用from属性相同的路径并把文件名的.ftl后缀去掉(如果是ftl后缀的话)。
- instantiate:实例化,类似copy,但在复制前会对文件进行预处理,也就是计算文件里的插值和执行里面的指令。
- merge: 合并文件,一般用于string.xml, color.xml等资源文件和 AndroidManifest.xml
- open:完成所有复制工作后在Android Studio打开这些文件
- dependency:依赖库,会自动下载mavenUrl所指定的library。
freemaker基本语法:
<#if needActivity>
...
<#/if>
<#if needActivity && needFragment>
...
</#if>
<#if needActivity>
...
<#elseif needFragment>
...
<#else>
...
</#if>
<?xml version="1.0"?>
<template
name="MVVM全家桶 "
description="一键创建MVVM单个页面所需的全部组件,结合Kotlin + Kodein + Databinding + ViewModel"
format="5"
minApi="9"
minBuildApi="15"
revision="1">
<category value="Activity" />
<formfactor value="Mobile" />
<parameter
name="Page Name"
constraints="unique|nonempty"
default="Main"
help="请填写页面名,如填写 Main,会自动生成 MainActivity, MainModule 等文件"
id="pageName"
type="string" />
<parameter
name="Root Package Name"
constraints="package"
default="com.mycompany.myapp"
help="请填写你的项目包名,请认真核实此包名是否是正确的项目包名,不能包含子包,正确的格式如:com.rain.music"
id="packageName"
type="string" />
<parameter
name="Generate Activity"
default="true"
help="是否需要生成 Activity ? 不勾选则不生成"
id="needActivity"
type="boolean" />
<parameter
name="Activity Layout Name"
constraints="layout|nonempty"
default="activity_main"
help="Activity 创建之前需要填写 Activity 的布局名,若布局已创建就直接填写此布局名,若还没创建此布局,请勾选下面的单选框"
id="activityLayoutName"
suggest="${activityToLayout(pageName)}"
type="string"
visibility="needActivity" />
<parameter
name="Generate Activity Layout"
default="true"
help="是否需要给 Activity 生成布局? 若勾选,则使用上面的布局名给此 Activity 创建默认的布局"
id="generateActivityLayout"
type="boolean"
visibility="needActivity" />
<parameter
name="Ativity Package Name"
constraints="package"
help="Activity 将被输出到此包下,请认真核实此包名是否是你需要输出的目标包名"
id="ativityPackageName"
suggest="${packageName}.view.activity"
type="string"
visibility="needActivity" />
<parameter
name="Generate Fragment"
default="false"
help="是否需要生成 Fragment ? 不勾选则不生成"
id="needFragment"
type="boolean" />
<parameter
name="Fragment Layout Name"
constraints="layout|nonempty"
default="fragment_main"
help="Fragment 创建之前需要填写 Fragment 的布局名,若布局已创建就直接填写此布局名,若还没创建此布局,请勾选下面的单选框"
id="fragmentLayoutName"
suggest="fragment_${classToResource(pageName)}"
type="string"
visibility="needFragment" />
<parameter
name="Generate Fragment Layout"
default="true"
help="是否需要给 Fragment 生成布局? 若勾选,则使用上面的布局名给此 Fragment 创建默认的布局"
id="generateFragmentLayout"
type="boolean"
visibility="needFragment" />
<parameter
name="Fragment Package Name"
constraints="package"
help="Fragment 将被输出到此包下,请认真核实此包名是否是你需要输出的目标包名"
id="fragmentPackageName"
suggest="${packageName}.view.fragment"
type="string"
visibility="needFragment" />
<parameter
name = "Generate DataSourceRepository"
default = "true"
help = "是否需要生成 needDataSourceRepository ? 不勾选则不生成"
id = "needDataSourceRepository"
type = "boolean"/>
<parameter
name = "DataSourceRepository Package Name"
constraints = "package"
help= "DataSourceRepository 将被输出到此包下,请认真核实此包名是否是你需要输出的目标包名"
id="DataSourcePackageName"
suggest="${packageName}.data.source"
type="string"
visibility="needDataSourceRepository" />
<parameter
name="DataSourceRepository class name"
constraints="nonempty|class|unique"
default="MyDataSourceRepository"
id="dataSourceRepositoryName"
suggest="${extractLetters(pageName)}DataSourceRepository"
type="string"
visibility="false" />
<parameter
name = "Generate RemoteDataSource"
default = "true"
help = "是否需要生成 RemoteDataSource ? 不勾选则不生成"
id = "needRemoteDataSource"
type = "boolean"/>
<parameter
name="RemoteDataSource class name"
constraints="nonempty|class|unique"
default="MyRemoteDataSource"
id="remoteDataSourceName"
suggest="${extractLetters(pageName)}RemoteDataSource"
type="string"
visibility="false" />
<parameter
name = "Generate LocalDataSource"
default = "false"
help = "是否需要生成 LocalDataSource ? 不勾选则不生成"
id = "needLocalDataSource"
type = "boolean"/>
<parameter
name="LocalDataSource class name"
constraints="nonempty|class|unique"
default="MyLocalDataSource"
id="localDataSourceName"
suggest="${extractLetters(pageName)}LocalDataSource"
type="string"
visibility="false" />
<parameter
name="Generate ViewModel"
default="true"
help="是否需要生成 ViewModel ? 不勾选则不生成"
id="needViewModel"
type="boolean" />
<parameter
name="ViewModule Package Name"
constraints="package"
help="ViewModel 将被输出到此包下,请认真核实此包名是否是你需要输出的目标包名"
id="VideModelPackageName"
suggest="${packageName}.viewmodel"
type="string"
visibility="needViewModel" />
<parameter
name="Generate DI module of Kodein"
default="true"
help="是否需要生成 Kodein Module组件? 不勾选则不生成"
id="needKodeinModule"
type="boolean" />
<parameter
name="Module Package Name"
constraints="package"
help="DI Module 将被输出到此包下,请认真核实此包名是否是你需要输出的目标包名"
id="ModulePackageName"
suggest="${packageName}.di"
type="string"
visibility="needKodeinModule" />
<!-- 128x128 thumbnails relative to template.xml -->
<thumbs>
<!-- default thumbnail is required -->
<thumb>template_blank_activity.png</thumb>
</thumbs>
<globals file="globals.xml.ftl" />
<execute file="recipe.xml.ftl" />
</template>
模板代码已上传至Github:MVVMTemplate
有问题或者不足之处欢迎指出! 顺便点个赞吧~