美文网首页
走马观花- AS 自定义模板

走马观花- AS 自定义模板

作者: OkCoco | 来源:发表于2019-01-19 14:52 被阅读0次

    公司有自己的一套 MVP 架构,每次创建新的 MVP ActivityMVP Fragment 时,都需要写相对应的 PresenterContract,想到 AS 内嵌的 Activity、Fragment、AIDL 等模板,便捷好用。就想自己将这个 MVP 整成一个模板,这样就能节省不少写模板代码的时间了。

    FreeMarker Template Language(FTL)

    FreeMarker 模板语言,是一台基于模板和要改变的数据,并用来生成输出文本的(HTML 网页、电子邮件、配置文件、源代码等 ) 的通用的工具,意味着要准备数据在真实编程语言中来显示, 之后模板显示已经准备好的数据。在模板中,你可以专注于如何展现数据, 而在模板之外可以专注于要展示什么数据。

    FTL 基本语法
    • 标签

    FTL 标签与 HTML 标签有相似之处,但是不是从属关系。FTL 标签都是以 # 开头的。用户自定义 FTL 标签需要使用 @ 符号替代 #

    <#include "xxx.tfl"/>
    
    • 注释
    <#--  这是注释 -->
    
    • if 、 else 指令
    <#if 变量名>
        ......
    <#elseif 变量名>
        ......
    <#else>
        ......
    </#if>
    
    例如:
    <#if generateKotlin>
        <instantiate from="root/src/app_package/SimpleActivity.kt.ftl"
                       to="${escapeXmlAttribute(srcOut)}/${activityClass}.kt" />
        <open file="${escapeXmlAttribute(srcOut)}/${activityClass}.kt" />
    <#else>
        <instantiate from="root/src/app_package/SimpleActivity.java.ftl"
                       to="${escapeXmlAttribute(srcOut)}/${activityClass}.java" />
        <open file="${escapeXmlAttribute(srcOut)}/${activityClass}.java" />
    </#if>
    
    • 访问变量值
    ${变量名}   例如:${packageName}
    
    • 引入其他文件
    <#include "xxx.ftl"/> 
    例如:
    <#include "../common/common_globals.xml.ftl" />
    
    • list 变量
    <#list variables as loopVariable>
        repeatThis
    </#list>
    例:
    <#list fruits as fruit>
        <li>${fruit}
    </#list>
    

    模板格式

    按照惯例,模板目录结构中由 FreeMarker 处理的任何文件都应具有 .ftl 文件扩展名。因此,如果你的一个源文件是 MyActivity.java ,并且它包含 FreeMarker 指令,那么它应该被命名为 MyActivity.java.ftl

    目录结构

    模板是包含许多XML和FreeMarker文件的目录。只有两个必填文件是template.xml和recipe.xml.ftl。模板源文件(PNG文件,模板化Java和XML文件等)属于root/子目录。下面是模板的示例目录结构:

    image
    • root

    存放我们的代码模板文件和资源文件

    • globals.xml.ftl

    定义全局变量

    • recipe.xml.ftl

    配置需要应用的模板路径和生成的文件的路径

    • template.xml

    定义模板参数。

    template.xml

    每个模板目录必须包含一个 template.xml 文件。此 XML 文件包含有关模板的元数据,包括 IDE 将作为用户选项显示的名称,描述,类别和用户可见参数。XML 文件还指示 recipe.xml.ftl 的名称,以及 globals.xml 文件

    下面是一个 template.xml 文件示例:

    <?xml version="1.0"?>
    <template
        format="5"
        revision="5"
        name="MVP Activity"
        minApi="9"
        minBuildApi="14"
        description="Creates a new MVP activity">
    
        <category value="Activity" />
        <formfactor value="Mobile" /> # 如同我们在创建module时所显示的类型,如:Wear、TV等。
    
        <parameter
            id="activityClass"
            name="Activity Name"
            type="string"
            constraints="class|unique|nonempty"
            suggest="${layoutToActivity(layoutName)}"
            default="MainActivity"
            help="The name of the activity class to create" />
    
        <thumbs>
            <!-- default thumbnail is required -->
            # 可选,用于创建模板时,在左边显示名为template_blank_activity的预览图片
            <thumb>template_blank_activity.png</thumb>
        </thumbs>
    
        # 可选,将工程定义的全局变量包含进来
        <globals file="globals.xml.ftl" />
        # 开始执行模板渲染
        <execute file="recipe.xml.ftl" />
    
    </template>
    
    image

    以下是 template.xml 支持的标签列表:

    • format 此模板遵循的模板格式版本
    • revision 此模板的整数版本(您可以在更新模板时递增),可选
    • name 模板名称。在 AS 操作 File --> New --> Activity 可找到对应的 Activity
    • description 模板的描述。见图
    • minApi

    模板所需的最小 API 值,IDE 将确保在实例化模板之前,目标工程的 minSdkVersion 不低于这个值,可选

    • minBuildApi

    此模板所需的最小构建目标 API。在实例化模板之前,IDE 将确保目标项目的目标是大于或等于此值的 API 级别。这可确保模板可以安全地使用较新的 API( 可选择由运行时 API 级别检查保护 ,而不会将编译时错误引入目标项目,可选

    • <dependency>

    表示模板要求目标项目中存在给定库。如果不存在,IDE 将向项目添加依赖项。

    name : 库的名称。目前接受的值有:
        1、android-support-v4
        2、android-support-v13
    
    revision : 此模板所需的库的最低版本。
    例如:
    <dependency name =“android-support-v4”revision =“8”/>
    
    • <category>

    模板类型。此元素是可选的

    value : 模板类型。应该是以下值之一:
        1、Applications
        2、Activities
        3、UI Components
    例 :
    <category value =“Activities”/>
    
    • <parameter>

    用户可自定义的模板参数

    id : 表示此变量的标识符在 FreeMarker 文件中作为全局变量提供。如果标识符是 foo,则参数值将在 FreeMarker 文件中通过 ${foo} 可得到
    name : 模板参数的显示名称。假设 <category value = "Activities"  />,则在 AS 中通过 File  --> New --> Activity 可找到对应的 Activity
    type : 参数的数据类型。要么string,boolean,enum,或 separator
    help : 操作 <parameter/> 时,底部显示的提示语
    default : 参数的默认值
    suggest : 建议值
    visibility : 根据其他 View 的 ${id} 定义该 View 是应该可见还是消失
    constraints : 属性值约束
    android:inputType : text|textEmailAddress|number|textPassword
    

    type

    定义了实际的视图属性,分别有EditText、SpinnerCheckBox 类型

    string : 表示对应的实际视图是一个EditText
    enum : 表示对应的实际视图是一个Spinner
    boolean : 表示对应的实际视图是一个 CheckBox
    

    constraints

    可选属性。强加于参数值的约束。可以使用组合约束 |。有效的约束类型有:

    class : 该值应表示有效的Java类名称,例如(Activity、Fragment、Presenter、Model、Utility等类名)
    nonempty : 该属性字段不能为 null 或 empty。此约束仅在指定其他约束时才有意义,例如layout,这意味着该值不应表示现有布局资源名称
    unique : 这个确保包中不会存在相同的名称。(也就是说,假设项目中已经存在 MainActivity,则通过显示 Main2Activity 等简单建议,避免使用重复的 Activity 名称)
    apilevel : 数字化的 API 级别
    package : 有效的 java 类名
    layout : 有效的 layout 名称
    drawable : 有效的 drawable 名称
    string : 有效的 string 
    id : 有效 id 资源名称
    exists : 值必须已经存在; 此约束仅在指定其他约束时才有意义,例如layout,这意味着该值应表示现有布局资源名称
    

    suggest

    可选的。表示自动建议参数值的 FreeMarker 表达式(“ 动态默认值 ”)。当用户修改其他参数值时,如果此参数的值未从其默认值更改,则该值将更改为此表达式的结果。这似乎是循环的,因为参数是可以与 suggest 相互对照的值,但这些表达式仅针对未编辑的值进行更新,因此这种方法允许用户编辑任一参数值,而另一个将自动更新为合理的默认值

    属性的内置方法 :

    1、suggest="${layoutToActivity(layoutName)}"  
    
        layoutName="activity_main"  -->  MainActivity
        layoutName="main"           -->  MainActivity
    
    2、suggest="${activityToLayout(activityClass)}"
    
        activityClass=“MainActivity”    -->  activity_main
        activityClass=“Main”            -->  activity_main
    
    3、suggest="${underscoreToCamelCase(classToResource(activityClass))}Adapter" //首字母是大写
    
        activityClass=“MainActivity”    -->  MainAdapter
        activityClass=“Main”            -->  MainAdapter
    
    4、suggest="item_${classToResource(activityClass)}"  //首字母变成了小写
    
        activityClass=“MainActivity”    -->  item_main
        activityClass=“Main”            -->  item_main
    
    

    classToResource(activityClass):这句话的意思是,当我们在创建该模板后,在 activityClass 对应的文本框中输入某个值,比如:test,它会直接在 layoutName 对应的文本框中显示,即:test,所以以完整的语句 suggest="${classToResource(activityClass)}_activity" 而言,此时 layoutName 对应的文本框中显示的应该是 test_activity

    • <option>

    类型的参数enum,表示值的选择.

    id : 如果选择此选项,则设置的参数值
    minApi : 可选的。选择此选项时所需的最低API级别。minSdkVersion在实例化模板之前,IDE将确保目标项目的值不低于此值
    [text] : 此元素的文本内容表示选择的显示值
    
    <parameter
            id="navType"
            name="Navigation Type"
            type="enum"
            default="none">
            <option id="none" default="true">None</option>
            <option id="tabs" minApi="11">Tabs</option>
            <option id="pager" minApi="11">Swipe Views</option>
            <option id="dropdown" minApi="11">Dropdown</option>
        </parameter>
    
    • <thumb>

    表示模板的缩略图。<thumb> 元素应包含在 <thumbs> 元素内。此元素的文本内容表示缩略图的路径。如果此元素具有多个属性,则它们将被视为参数值的选择器。例如,如果有两个缩略图:

    <thumbs>
        <thumb>template.png</thumb>
        <thumb navType="tabs">template_tabs.png</thumb>
    </thumbs>
    

    如果值 navType 模板参数是 tabsname 模板“预览”缩略图将显示template_tabs.png ,否则显示 template.png

    global.xml.ftl
    <?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>
    

    这个文件用于定义一些全局变量。

    1. <global> 定义一个全局变量
    2. id : 变量名称
    3. type : 变量类型
    4. value : 默认值

    访问这些变量的方法:${变量id}。例如:

    ${hasNoActionBar};
    
    recipe.xml.ftl

    recipe.xml.ftl 包含从此模板生成代码时应执行的各个指令。例如,您可以复制某些文件或目录( copy 指令 ,可选地通过 FreeMarker 运行源文件( instantiate 指令,并在生成代码( open 指令 后要求 ADTEclipse 中打开文件。

    注意: recipe.xml.ftl 的名称可自定义,但必须在 template.xml 声明。但按照惯例,最好称之为 recipe.xml.ftl

    注意:全局变量 globals.xml.ftl 可用于recipe.xml.ftl

    <?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>
    
    <#if generateKotlin>
        <instantiate from="root/src/app_package/SimpleActivity.kt.ftl"
                       to="${escapeXmlAttribute(srcOut)}/${activityClass}.kt" />
        <open file="${escapeXmlAttribute(srcOut)}/${activityClass}.kt" />
    <#else>
        <instantiate from="root/src/app_package/SimpleActivity.java.ftl"
                       to="${escapeXmlAttribute(srcOut)}/${activityClass}.java" />
        <open file="${escapeXmlAttribute(srcOut)}/${activityClass}.java" />
    </#if>
    
    </recipe>
    

    该文件用于定义如何生成文件和代码。

    • <copy>

    用于从 root 文件夹复制文件到目标文件

    唯一必需的参数是 from 指定要在 root/ 目录下复制的源文件的位置。如果需要,将自动创建所有必需的祖先目录。

    默认目标位置是输出目录根目录下的相同路径(即目标项目的位置)。如果提供了可选 to 参数,则指定输出目录。请注意,如果 from 路径以 ... 结尾 .ftl ,则会自动删除它。例如 <instantiate from="res/values/strings.xml.ftl" /> 是足够的; 这将创建一个名为的文件 strings.xml,而不是 strings.xml.ftl

    此参数以递归方式工作,因此如果 from 是目录,则以递归方式复制该目录。

    • <instantiate>

    .ftl 文件转化成为 .java.kt 文件

    • <merge>

    用于合并文件,如将模板文件的 string.xml 合并到我们项目的 string.xml

    • <open>

    在代码生成后打开指定文件,例如:当我们创建一个 Activity 时,AS 会自动打开 Activity 以及布局文件

    • <#include>

    导入另一个 ftl 文件

    额外模板功能

    FreeMarker 几个重要函数 :

    • string activityToLayout(string)

    作用:

    此函数将类似 activity calss 的标识符字符串 例如 FooActivity)转换为对应的资源标识符字符串,例如 activity_foo

    参数:

    activityClass,活动类名称,例如FooActivity重新格式化。

    • string camelCaseToUnderscore(string)

    作用 :

    此函数将 camel-case 标识符字符串例如 FooBar)转换为其对应的下划线分隔标识符字符串,例如 foo_bar

    参数 :

    camelStr,驼峰式字符串,例如 FooBar 转换为下划线分隔的字符串。

    • string escapeXmlAttribute(string)

    作用 :

    此函数用来转义字符串,例如 Android's,它可以用作 XML 属性值:Android&apos;s。特别是,它将转义'"<

    参数 :

    str,要转义的字符串。

    • string escapeXmlText(string)

    作用 :

    此函数用来转义字符串,例如 A & B's 可以将其用作 XML 文本。这意味着它将转义 <>,但不像 escapeXmlAttribute 它将不会转义'"。在前面的示例中,它将转义字符串为 A &amp; B\s。请注意,如果您想要使用 XML 文本作为 <string> 资源的值,您应该考虑使用 escapeXmlString,因为它执行额外的所需的字符串资源转义

    参数 :

    str,转义为正确XML文本的字符串。

    • string escapeXmlString(string)

    作用 :

    此函数用来转义字符串,例如 A & B's ,它适合作为 XML 文本插入字符串资源文件中,例如 A &amp; B\s 。除了转义 < 之类的 XML 字符外,它还执行其他Android 特定的转义,例如使用反斜杠转义撇号,等等

    参数 :

    str,例如,Activity's Title 以转义为适当的资源 XML 值。

    • string extractLetters(string)

    作用 :

    此函数从字符串中提取所有字母,有效删除任何标点符号和空白字符。

    参数 :

    str,从中提取字母的字符串。

    • string classToResource(string)

    作用 :

    此函数将 Android 类名称 例如 FooActivityFooFragment)转换为相应的资源标识符字符串,例如 foo ,删除 activityfragment 后缀。目前删除的后缀列在下面:

    • Activity
    • Fragment
    • Provider
    • Service

    参数 :

    className,类名,例如 FooActivity 重新格式化为下划线分隔的字符串,后缀已删除。

    • string layoutToActivity(string)

    作用 :

    此函数将资源标识符字符串 例如 activity_foo)转换为对应的 Java 类标识符字符串,例如 FooActivity

    参数 :

    resourceName,资源名称,例如 activity_foo 重新格式化。

    • string slashedPackageName(string)

    作用 :

    此函数将完整 Java 包名称转换为其对应的目录路径。例如,如果给定的参数是 com.example.foo ,则返回值为 com/example/foo

    参数 :

    packageName,要重新格式化的包名称,例如 com.example.foo

    • string underscoreToCamelCase(string)

    作用 :

    此函数将下划线分隔的字符串 例如 foo_bar)转换为其对应的驼峰字符串,例如 FooBar

    参数 :

    underStr,下划线分隔的字符串,例如 foo_bar 转换为驼峰字符串。

    工具元数据

    创建活动布局时,请确保在布局的根视图中包含活动名称作为 tools 命名空间的一部分,如以下示例所示

    <TextView xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:text="@string/hello_world"
        android:padding="@dimen/padding_medium"
        tools:context=".${activityClass}" />
    

    我们在布局中使用此属性来维护到用于布局的活动活动的映射。是的,可以有多个,但是此属性显示您要编辑布局的活动上下文。例如,它将用于查找主题注册 这是每个活动而不是每个布局 ) ) 在清单文件中,我们将来会将其用于其他功能 - 例如预览操作栏,这也需要我们知道活动上下文。

    具体参考

    Android ADT Template Format Document

    Android模板制作

    相关文章

      网友评论

          本文标题:走马观花- AS 自定义模板

          本文链接:https://www.haomeiwen.com/subject/ueqzdqtx.html