Android Template(模板) 编写(二)

转载请注明出处:http://blog.csdn.net/zhaodai11?viewmode=contents

上篇文章介绍的方法只能创建类模板,不能创建xml文件等资源文件以及配置文件等,这篇文章来介绍创建可以一次创建多个文件多种类型文件的方法。

我们在使用AndroidStudio创建Activity的时候一般java文件,xml文件,以及在androidmanifest.xml配置文件中配置已经完成。

上篇文章讲到AndroidStudio的文件模板放在安装目录下/plugins/Android/lib/templates 文件夹下面。

可以看到里面那些正是AndroidStudio默认提供的Activity类型(我截图里面多了几个,是我自己测试写的)。

下面我们分析最简单的一个模板EmptyActivity,EmptyActivity文件夹下面包括:

Android Studio 使用的是freeMaker模板引擎,所以文件夹下面的文件后缀名都是.ftl。

  • globals.xml.ftl 全局变量文件 存放的是一些全局变量
  • recipe.xml.ftl 配置要引用的模板路径以及生成文件的路径
  • template.xml 模板的配置信息,以及要输入的参数.定义了模板的流程框架 基本结构
  • template_blank_activity.png 显示的缩略图(只是展示用)
  • SimpleActivity.java.ftl Activity模板文件

    globals.xml.ftl 定义了一些全局变量 以及将 common_globals.xml.ftl 文件中的全局变量引入


" data-snippet-id="ext.92f36db2c46b34e406fed5b0312d1880" data-snippet-saved="false" data-codota-status="done"><?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>

common_globals.xml.ftl


    ${relativePackage}${packageName}" />
" data-snippet-id="ext.b6d80b7566793fa3b77c1d5cdee4312c" data-snippet-saved="false" data-codota-status="done"><globals>
    <#assign theme=getApplicationTheme()!{ "name": "AppTheme", "isAppCompat": true }>
    <#assign themeName=theme.name!‘AppTheme‘>
    <#assign themeNameNoActionBar=theme.nameNoActionBar!‘AppTheme.NoActionBar‘>
    <#assign appCompat=theme.isAppCompat!false>
    <#assign appCompatActivity=appCompat && (buildApi gte 22)>

    <global id="themeName" type="string" value="${themeName}" />
    <global id="implicitParentTheme" type="boolean" value="${(themeNameNoActionBar?starts_with(themeName+‘.‘))?string}" />
    <global id="themeNameNoActionBar" type="string" value="${themeNameNoActionBar}" />
    <global id="themeExistsNoActionBar" type="boolean" value="${(theme.existsNoActionBar!false)?string}" />
    <global id="themeNameAppBarOverlay" type="string" value="${theme.nameAppBarOverlay!‘AppTheme.AppBarOverlay‘}" />
    <global id="themeExistsAppBarOverlay" type="boolean" value="${(theme.existsAppBarOverlay!false)?string}" />
    <global id="themeNamePopupOverlay" type="string" value="${theme.namePopupOverlay!‘AppTheme.PopupOverlay‘}" />
    <global id="themeExistsPopupOverlay" type="boolean" value="${(theme.existsPopupOverlay!false)?string}" />

    <global id="appCompat" type="boolean" value="${((isNewProject!false) || (theme.isAppCompat!false))?string}" />
    <global id="appCompatActivity" type="boolean" value="${appCompatActivity?string}" />
    <global id="hasAppBar" type="boolean" value="${appCompatActivity?string}" />
    <global id="hasNoActionBar" type="boolean" value="${appCompatActivity?string}" />
    <global id="manifestOut" value="${manifestDir}" />
    <global id="buildVersion" value="${buildApi}" />

<#if !appCompat>
    <global id="superClass" type="string" value="Activity"/>
    <global id="superClassFqcn" type="string" value="android.app.Activity"/>
    <global id="Support" value="" />
    <global id="actionBarClassFqcn" type = "string" value="android.app.ActionBar" />
<#elseif appCompatActivity>
    <global id="superClass" type="string" value="AppCompatActivity"/>
    <global id="superClassFqcn" type="string" value="android.support.v7.app.AppCompatActivity"/>
    <global id="Support" value="Support" />
    <global id="actionBarClassFqcn" type = "string" value="android.support.v7.app.ActionBar" />
<#else>
    <global id="superClass" type="string" value="ActionBarActivity"/>
    <global id="superClassFqcn" type="string" value="android.support.v7.app.ActionBarActivity"/>
    <global id="Support" value="Support" />
    <global id="actionBarClassFqcn" type = "string" value="android.support.v7.app.ActionBar" />
</#if>

    <global id="srcOut" value="${srcDir}/${slashedPackageName(packageName)}" />
    <global id="resOut" value="${resDir}" />
    <global id="menuName" value="${classToResource(activityClass!‘‘)}" />
    <global id="simpleName" value="${activityToLayout(activityClass!‘‘)}" />
    <global id="relativePackage" value="<#if relativePackage?has_content>${relativePackage}<#else>${packageName}</#if>" />
</globals>

recipe.xml.ftl 、recipe_manifest.xml.ftl、recipe_simple.xml.ftl 配置要引用的模板路径以及生成文件的路径


//recipe_manifest.xml.ftl

//recipe_simple.xml.ftl

" data-snippet-id="ext.9c51c88df8b1f3cc18ae53da8752202c" data-snippet-saved="false" data-codota-status="done"><?xml version="1.0"?>
<recipe>
    <#include "../common/recipe_manifest.xml.ftl" />

<#if generateLayout>
    <#include "../common/recipe_simple.xml.ftl" />
    <open file="${escapeXmlAttribute(resOut)}/layout/${layoutName}.xml" />
</#if>

    <instantiate from="root/src/app_package/SimpleActivity.java.ftl"
                   to="${escapeXmlAttribute(srcOut)}/${activityClass}.java" />

    <open file="${escapeXmlAttribute(srcOut)}/${activityClass}.java" />
</recipe>

//recipe_manifest.xml.ftl
<recipe folder="root://activities/common">

    <merge from="root/AndroidManifest.xml.ftl"             to="${escapeXmlAttribute(manifestOut)}/AndroidManifest.xml" />

    <merge from="root/res/values/manifest_strings.xml.ftl"
             to="${escapeXmlAttribute(resOut)}/values/strings.xml" />

</recipe>

//recipe_simple.xml.ftl
<recipe folder="root://activities/common">

<#if appCompat && !(hasDependency(‘com.android.support:appcompat-v7‘))>
    <dependency mavenUrl="com.android.support:appcompat-v7:${buildApi}.+"/>
</#if>

    <instantiate from="root/res/layout/simple.xml.ftl"
                 to="${escapeXmlAttribute(resOut)}/layout/${simpleLayoutName}.xml" />

<#if (isNewProject!false) && !(excludeMenu!false)>
    <#include "recipe_simple_menu.xml.ftl" />
</#if>

    <#include "recipe_simple_dimens.xml" />
</recipe>

这里<#if >是freeMaker的if判断标签,对freeMaker我也不太熟悉,大家感兴趣可以去看一下freeMaker语法。

" data-snippet-id="ext.dd737281142d983327dd743be6c2d12c" data-snippet-saved="false" data-codota-status="done"><instantiate from="root/src/app_package/SimpleActivity.java.ftl"           to="${escapeXmlAttribute(srcOut)}/${activityClass}.java" />

这句是根据root/src/app_package/SimpleActivity.java.ftlSimpleActivity.java.ftl模板文件生成escapeXmlAttribute(srcOut)目录下对应${activityClass}.java文件,escapeXmlAttribute(srcOut)这个是指你选择的目录即你点击右键时的目录。

" data-snippet-id="ext.8e45494a18bdcfad59c56e6856c59485" data-snippet-saved="false" data-codota-status="done"> <open file="${escapeXmlAttribute(srcOut)}/${activityClass}.java" />
</recipe>

同样这句的作用是生成后打开这个文件。

" data-snippet-id="ext.4281a6efa443224bb56081c6ce151575" data-snippet-saved="false" data-codota-status="done"><merge from="root/AndroidManifest.xml.ftl"             to="${escapeXmlAttribute(manifestOut)}/AndroidManifest.xml" />

merge标签代表是将AndroidManifest.xml.ftl模板文件中的内容添加到AndroidManifest.xml文件中,并不是覆盖。

template.xml 模板的配置信息,以及要输入的参数.定义了模板的流程框架 基本结构

 界面中显示描述 

       模板所属类型  这个可以自定义 

     界面提示文字 

    缩略图

        template_blank_activity.png

    引入全局配置文件

    根据模板生成对应的文件

" data-snippet-id="ext.152fa9bd671d3135d26d98dc261d416e" data-snippet-saved="false" data-codota-status="done"><?xml version="1.0"?>
<template
    format="5"
    revision="5"
    name="Empty Activity"  在向导界面中显示的模板名称
    minApi="7"
    minBuildApi="14"
    description="Creates a new empty activity"> 界面中显示描述 

    <category value="Activity" />   模板所属类型  这个可以自定义
    <formfactor value="Mobile" />

    <parameter
        id="activityClass"  唯一标示,可以用${activityClass}获取value
        name="Activity Name" 界面输入框前的提示文字
        type="string" 类型 界面显示为输入框
        constraints="class|unique|nonempty" 约束 class必须是类名 unique唯一 nonempty不能为空
        suggest="${layoutToActivity(layoutName)}" 建议的名称 默认生成的名称和布局文件名称关联  不太确定 汗
        default="MainActivity" 默认值
        help="The name of the activity class to create" /> 界面提示文字 

    <parameter
        id="generateLayout"
        name="Generate Layout File"
        type="boolean" 界面显示为勾选框  type="enum" 在界面中为下拉选择框
        default="true"
        help="If true, a layout file will be generated" />

    <parameter
        id="layoutName"
        name="Layout Name"
        type="string"
        constraints="layout|unique|nonempty"
        suggest="${activityToLayout(activityClass)}"
        default="activity_main"
        visibility="generateLayout"
        help="The name of the layout to create for the activity" />

    <parameter
        id="isLauncher"
        name="Launcher Activity"
        type="boolean"
        default="false"
        help="If true, this activity will have a CATEGORY_LAUNCHER intent filter, making it visible in the launcher" />

    <parameter
        id="packageName"
        name="Package name"
        type="string"
        constraints="package"
        default="com.mycompany.myapp" />

    缩略图
    <!-- 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>

下面配一张图

SimpleActivity.java.ftl Activity模板文件

        setContentView(R.layout.${layoutName});

    }
}
" data-snippet-id="ext.f0bce80cb146a93c3e8e062a10380bfa" data-snippet-saved="false" data-codota-status="done">package ${packageName};  

import ${superClassFqcn};
import android.os.Bundle;

public class ${activityClass} extends ${superClass} {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
<#if generateLayout>
        setContentView(R.layout.${layoutName});
</#if>
    }
}

${activityClass} ${superClass} 其他文件中对变量的引用,都是前面定义的一些参数,一般主要出自两个地方,一个是globals.xml 全局变量文件,第二个是template.xml 界面中定义变量。

这种根据模板生成更类似于一种文件拷贝,不会检查语法。

上面是理论基础。下面我们来实战一下,顺便解决一下上篇文章的问题如何生成多个文件,以及不同类型的文件。

实战须知:

建议大家在修改之前,现将整个文件夹备份一下,免得改乱了。文件夹也不大。


" data-snippet-id="ext.6b112a4fbe9f71db3964b42d9f99b540" data-snippet-saved="false" data-codota-status="done"><?xml version="1.0"?>
<globals>
    <global id="resOut" value="${resDir}" />
    <global id="srcOut" value="${srcDir}/${slashedPackageName(packageName)}" />
    <global id="collection_name" value="${extractLetters(itemClass?lower_case)}" />
</globals>

**recipe.xml.ftl 配置要引用的模板路径以及生成文件的路径。

一次性生成多个文件,在于使用<instantiate>标签,只要写好引用模板文件和输出文件路径和文件名。**


" data-snippet-id="ext.4909b2fe51c6bd914f2abee30008eb10" data-snippet-saved="false" data-codota-status="done"><?xml version="1.0"?>
<recipe>
    <!-- 生成Adapter 文件-->
    <instantiate from="src/app_package/CustomAdapter.java.ftl"                       to="${escapeXmlAttribute(srcOut)}/adapter/${itemClass}Adapter.java" />

    <open file="${escapeXmlAttribute(srcOut)}/adapter/${itemClass}Adapter.java" />

    <!-- 生成Fragment 文件-->
    <instantiate from="src/app_package/Fragment.java.ftl"                       to="${escapeXmlAttribute(srcOut)}/fragment/${itemClass}Fragment.java" />

    <open file="${escapeXmlAttribute(srcOut)}/fragment/${itemClass}Fragment.java" />

    <!-- 生成Presenter 文件-->
    <instantiate from="src/app_package/BasePresenter.java.ftl"                       to="${escapeXmlAttribute(srcOut)}/presenter/${itemClass}Presenter.java" />

    <open file="${escapeXmlAttribute(srcOut)}/presenter/${itemClass}Presenter.java" />

<!-- 生成Contract 文件-->
    <instantiate from="src/app_package/BaseContract.java.ftl"                       to="${escapeXmlAttribute(srcOut)}/presenter/${itemClass}Contract.java" />

    <open file="${escapeXmlAttribute(srcOut)}/presenter/${itemClass}Contract.java" />

<!-- 生成InteractorImpl 文件-->
    <instantiate from="src/app_package/BaseInteractor.java.ftl"                      to="${escapeXmlAttribute(srcOut)}/interactor/${itemClass}InteractorImpl.java" />

    <open file="${escapeXmlAttribute(srcOut)}/interactor/${itemClass}Interactor.java" />

<!-- 生成model 文件-->
    <instantiate from="src/app_package/BaseModel.java.ftl"                       to="${escapeXmlAttribute(srcOut)}/model/${itemClass}.java" />

    <open file="${escapeXmlAttribute(srcOut)}/model/${itemClass}.java" />

<!-- 生成item布局 文件-->
    <instantiate from="res/layout/item_simple.xml.ftl"           to="${escapeXmlAttribute(resOut)}/layout/${layoutName}.xml" />
<!-- 生成fragment布局 文件-->
    <instantiate from="res/layout/fragment_simple.xml.ftl"            to="${escapeXmlAttribute(resOut)}/layout/${fragment_layoutName}.xml" />
</recipe>

template.xml 模板的配置信息,以及要输入的参数.定义了模板的流程框架 基本结构


     -->

     -->

        template_basic_activity_fragment.png

" data-snippet-id="ext.ede01ec198caadbb70cc88a5bbd17839" data-snippet-saved="false" data-codota-status="done"><?xml version="1.0"?>
<template
    format="4"
    revision="1"
    name="ListFragmentAchieve"
    description="Creates a new ListFragmentAchieve"
    minApi="7"
    minBuildApi="14">

    <category value="ListFragmentAchieveName" />

    <!--  <parameter
        id="adapterClass"
        name="Adapter Name"
        type="string"
        constraints="class|unique|nonempty"
        default="CustomAdapter"
        help="The name of the adapter class to create" /> -->

    <parameter
        id="itemClass"
        name="Item Name"
        type="string"
        constraints="class|nonempty"
        default="String"
        help="The name of the item class to use" />

    <parameter
        id="layoutName"
        name="item_layout"
        type="string"
        constraints="layout|nonempty"
        default="item_layout"
        help="The name of the row layout to use" />

    <!-- fragment 类文件名称 后来使用 itemClass 拼接完成了-->
    <!-- <parameter
        id="fragmentClass"
        name="fragment Name"
        type="string"
        constraints="class|unique|nonempty"
        default="Fragment"
        help="The name of the fragment class to create" /> -->

    <!-- fragment 布局文件名 -->
    <parameter
        id="fragment_layoutName"
        name="fragment_layout"
        type="string"
        constraints="layout|nonempty"
        default="fragment_layout"
        help="The name of the row layout to use" />

    <!-- 128x128 thumbnails relative to template.xml -->
    <thumbs>
        <!-- default thumbnail is required -->
        <thumb>template_basic_activity_fragment.png</thumb>
    </thumbs>

    <globals file="globals.xml.ftl" />
    <execute file="recipe.xml.ftl" />

</template>

剩下的模板资源文件就不一一列举贴代码了 ,这些文件大家可以根据自己的需求去自己定义。

.

效果图:

代码上传到了github:

https://github.com/zhaodaizheng/AndroidTemplates

这个demo自动生成的文件,是根据我自己的框架生成的,大家本地生成后的文件肯定会出现错误,大家可以根据自己封装的框架进行修改。

对FreeMarker不太了解 有错误的地方欢迎反馈。

时间: 2024-10-18 21:13:18

Android Template(模板) 编写(二)的相关文章

Android Studio 模板用法与自定义模板

本文gif图比较多,可能会导致页面加载缓慢,请大家耐心等待 今天我们来学习下Android Studio这款软件的一些秘密,这些就是Template,就是我们输出一些特定的字符就可以实现自动编写一大堆代码,额,什么意思了?下面还是看图来理解吧! Live Template 这种模板用法就是输入特定字符,按下Tab键即可,此键可自定义设置 在方法中输入"Toast"并按下Tab键 快速编写TAG,在类中输入"logt"并按下Tab键 常量的编写,详细见图 输出语句的书

C++模板(二)【转】

本文转自:http://www.cnblogs.com/gw811/archive/2012/10/25/2738929.html C++模板 模板是C++支持参数化多态的工具,使用模板可以使用户为类或者函数声明一种一般模式,使得类中的某些数据成员或者成员函数的参数.返回值取得任意类型. 模板是一种对类型进行参数化的工具: 通常有两种形式:函数模板和类模板: 函数模板针对仅参数类型不同的函数: 类模板针对仅数据成员和成员函数类型不同的类. 使用模板的目的就是能够让程序员编写与类型无关的代码.比如

Android架构分析之Android智能指针(二)

作者:刘昊昱 博客:http://blog.csdn.net/liuhaoyutz Android版本:4.4.2 在上一篇文章中,我们分析了Android智能指针中的强指针sp,本文我们来分析弱指针wp.为什么需要弱指针wp呢?我们来考虑下面一种场景:有两个类CParent和CChild,CParent类中有一个智能指针指向CChild对象,CChild类中有一个智能指针指向CParent对象 class CParent :public LightRefBase<CParent> { --

ubuntu下进行android的开发(二):android开发环境搭建

android开发环境搭建主要分两个步骤:安装JDK及安装集成开发环境. 一.安装JDK ubuntu系统自带的有openJDK,要开发android还是需要去官网下载JDK(1.6以上).当前系统JDK版本可以通过java -version指令来查看. 到oracle官网http://www.oracle.com/technetwork/java/javase/downloads/index.html下载最新的JAVA SE开发环境(JDK),我这里下载的是jdk-8u11-linux-x64

Android架构分析之Android消息处理机制(二)

作者:刘昊昱 博客:http://blog.csdn.net/liuhaoyutz Android版本:4.4.2 在上一篇文章中我们看了一个使用Handler处理Message消息的例子,本文我们来分析一下其背后隐藏的Android消息处理机制. 我们可能比较熟悉Windows操作系统的消息处理模型: while(GetMessage(&msg,NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } 1.消息

Android学习路线(二)创建Android项目

一个Android项目包含了Android app代码在内的所有文件.Android SDK工具提供默认的项目目录和文件让创建一个项目变得很简单. 这篇课程会向大家展示,如何通过Eclipse(包含ADT插件)或者通过在命令行使用SDK工具来创建一个新项目. 提示: 你必须得先安装好Android SDK,如果你使用的是Eclipse,那么你还必须安装了ADT 插件(22.6.2版本或更高).如果你没有这些,可以通过Android SDK安装向导安装好,然后再回到这片课程. 通过Eclipse创

WPF模板(二)应用

原文:WPF模板(二)应用 本次内容来源于电子书,和上一篇一样. 在WPF中有三大模板ControlTemplate,ItemsPanelTemplate,DataTemplate.其中ControlTemplate和ItemsPanelTemplate是控件模板,DataTemplate是数据模板,他们都派生自FrameworkTemplate抽象类. 1.ControlTemplate ControlTemplate:控件模板主要有两个重要属性:VisualTree内容属性和Triggers

「luogu3380」【模板】二逼平衡树(树套树)

「luogu3380」[模板]二逼平衡树(树套树) 传送门 我写的树套树--线段树套平衡树. 线段树上的每一个节点都是一棵 \(\text{FHQ Treap}\) ,然后我们就可以根据平衡树的基本操作以及线段树上区间信息可合并的性质来实现了,具体细节看代码都懂. 参考代码: #include <algorithm> #include <cstdlib> #include <cstdio> #define rg register #define file(x) freo

android产品研发(二十一)--&gt;UI优化

转载请标明出处:一片枫叶的专栏 上一篇文章中我们讲解了android产品研发过程中的代码Review.通过代码Review能够提高产品质量,增强团队成员之间的沟通,提高开发效率,所以良好的产品开发迭代过程中,代码Review是一个必不可少的步骤.那么如何进行代码Review呢?我们主要讲解了团队成员之间的代码Review,代码lint检查,开发规范等方面的知识点,更多关于代码Review相关的知识可参考我的:android产品研发(二十)–>代码Review 本文我们将讲解一下android U