android studio的自定義模板詳解
前言
最近看到有關技術博客,發現了關于androidstudio的模板的有關文章,表示感興趣。
包括文中的引用部分。
關于自定義模板
在新建Activity的時候都有許多的模板供我們選擇,大牛可以自定義模板,減少開發時候的重復工作。
比如這樣:
圖片來自鴻洋的csdn博客
其實模板不僅限于activity 包括圖片自由 布局文件 fragment service 以及一個類都可以制作成模板。
這里只想看下Activity模板:
模板制作學習
分為三個步驟:
-
分析系統模板
-
改寫系統模板
-
自己創造模板
分析和改寫系統模板
Activity的模板地址在AS的 plugins\android\lib\templates\activities 目錄下:
比如我的電腦在
C:\Program Files\Android\Android Studio\plugins\android\lib\templates\activities
Login界面用的比較多,就從他開始吧。
點開文件夾,看到以下目錄:
模板LoginActivity.png
下面來一一分析這些文件:
template.xml
這個是模板配置文件,打開可以看到:
<?xml version="1.0"?>
<template
format="5"
revision="6"
name="Login Activity"
description="Creates a new login activity, allowing users to optionally sign in with Google+ or enter an email address and password to log in to or register with your application."
requireAppTheme="true"
minApi="8"
minBuildApi="14">
<dependency name="android-support-v4" revision="8" />
<category value="Activity" />
<formfactor value="Mobile" />
<parameter
id="activityClass"
name="Activity Name"
type="string"
constraints="class|unique|nonempty"
default="LoginActivity"
help="The name of the activity class to create" />
<parameter
id="layoutName"
name="Layout Name"
type="string"
constraints="layout|unique|nonempty"
suggest="${activityToLayout(activityClass)}"
default="activity_login"
help="The name of the layout to create for the activity" />
<parameter
id="activityTitle"
name="Title"
type="string"
constraints="nonempty"
default="Sign in"
help="The name of the activity." />
<parameter
id="parentActivityClass"
name="Hierarchical Parent"
type="string"
constraints="activity|exists|empty"
default=""
help="The hierarchical parent activity, used to provide a default implementation for the 'Up' button" />
<parameter
id="packageName"
name="Package name"
type="string"
constraints="package"
default="com.mycompany.myapp" />
<thumbs>
<thumb>template_login_activity.png</thumb>
</thumbs>
<globals file="globals.xml.ftl" />
<execute file="recipe.xml.ftl" />
</template></code></pre>
- 最外面的template標簽寫的是基本的配置:包括模板名,描述,是否請求系統主題等等。我們可以將其修改為中文。
<template
format="5"
revision="6"
name="登陸界面"
description="創建一個新的登陸界面"
requireAppTheme="true"
minApi="8"
minBuildApi="14">
- parameter標簽
參數,也就是要在創建的時候自己設置的東西。每一個 parameter標簽對應一個參數。這些參數會顯示在創建頁面上。也修改為中文。 . id :唯一標識,最終通過該屬性的值,獲取用戶輸入值(文本框內容,是否選中)
. name:界面上的類似label的提示語
. type : 輸入值類型
. constraints:填寫值的約束
. suggest:建議值,比如填寫ActivityName的時候,會給出一個布局文件的建議值。
. default:默認值
. help:底部顯示的提升語
<parameter
id="activityClass"
name="活動類名"
type="string"
constraints="class|unique|nonempty"
default="LoginActivity"
help="填寫所創建的活動類的名稱" />
<parameter
id="layoutName"
name="布局文件名"
type="string"
constraints="layout|unique|nonempty"
suggest="${activityToLayout(activityClass)}"
default="activity_login"
help="填寫所創建的布局文件的名稱" />
<parameter
id="activityTitle"
name="標題欄標題"
type="string"
constraints="nonempty"
default="Sign in"
help="The name of the activity." />
<parameter
id="parentActivityClass"
name="父活動類"
type="string"
constraints="activity|exists|empty"
default=""
help="配置父活動類,用于返回上一級按鈕" />
<parameter
id="packageName"
name="包名"
type="string"
constraints="package"
default="com.mycompany.myapp" /></code></pre>
3.thumbs
里面放置了樣例圖,可以嘗試更換。
4.最后指定了兩個引用文件
<globals file="globals.xml.ftl" />
<execute file="recipe.xml.ftl" />
可以測試一下修改的效果:

my.gif
globals.xml.ftl和recipe.xml.ftl
在這之前先了解一下ftl結尾的文件是什么:
freemarker的文件一般以后綴ftl.
freemarker確實是不錯的模版語言引擎,尤其是處理對象圖很方便,處理xml也很方便,還支持xpath
FreeMarker 是一個模版引擎,一個基于文本的模板輸出工具(生成任意的HTML表單代碼)。它是一個Java package,面向Java程序員的class library。它本身并不是針對最終用戶的應用,而是允許程序員將其嵌入到他們的產品中。
FreeMarker被設計用來生成HTML Web頁面,特別是基于MVC(Model View Controller)模式的應用程序。使用 MVC 模式作為動態的WEB頁面的想法,是為了分隔頁面設計者 (HTML 設計者) 和程序員。.每個人做自己擅長的那一部分。設計者可以不通過程序員的改變或修改代碼來改變網頁的樣子,因為應用邏輯(Java程序)和頁面設計(FreeMarker 模版)是分開的。模板不會被復雜繁瑣的程序框架所破壞。即使當一個項目的程序員和HIMTL頁面的制作者是同一個人時,這種分隔也是很有用,因為這樣有助于保持應用的清晰并易于維護。
不知道大家寫過網頁沒有,不管是jsp還是asp還是asp.net
都會有這種在標簽語言里面插入編程語言的方式,大概類似。
關于ftl的語法:
組成部分
一、整體結構
1、注釋:<#--注釋內容-->,不會輸出。
2、文本:直接輸出。
3、interpolation:由 ${var} 或 #{var} 限定,由計算值代替輸出。
4、FTL標記
二、指令:
freemarker指令有兩種:
1、預定義指令:引用方式為<#指令名稱>
2、用戶定義指令:引用方式為<@指令名稱>,引用用戶定義指令時須將#換為@。
注意:如果使用不存在的指令,FreeMarker不會使用模板輸出,而是產生一個錯誤消息。
freemarker指令由FTL標記來引用,FTL標記和HTML標記類似,名字前加#來加 以區分。如HTML標記的形式為
則FTL標記的形式是<#list>< /#list>(此處h1標記和list指令沒有任何功能上的對應關系,只是做為說明使用一下)。
有三種FTL標記:
1)、開始標記:<#指令名稱>
2)、結束標記:</#指令名稱>
3)、空標記:<#指令名稱/>
注意:
1) FTL會忽略標記之中的空格,但是,<#和指令 與 </#和指令 之間不能有空格。
2) FTL標記不能夠交叉,必須合理嵌套。每個開始標記對應一個結束標記,層層嵌套。 如:
<#list>
- ${數據}
<#if 變量>
game over!
</#if>
</#list>
注意事項:
1)、FTL對大小寫敏感。 所以使用的標記及interpolation要注意大小寫。name與NAME就是不同的對象。<#list>是正確的標記,而<#List>則不是。
2)、interpolation只能在文本部分使用,不能位于FTL標記內。如<#if ${var}>是錯誤的,正確的方法是:<#if var>,而且此處var必須為布爾值。
3)、FTL標記不能位于另一個FTL標記內部,注釋例外。注釋可以位于標記及interpolation內部。
其實只要知道if即可以了,這里只用if來判斷。
globals.xml.ftl
定義了全局變量,并引用了一個內置的通用globals.xml.ftl
<?xml version="1.0"?>
<globals>
<global id="hasNoActionBar" type="boolean" value="false" />
<global id="isLauncher" type="boolean" value="${isNewProject?string}" />
<global id="includePermissionCheck" type="boolean" value="${(targetApi gte 23)?string}" />
<global id="GenericStringArgument" type="string" value="<#if buildApi lt 19>String</#if>" />
<#include "../common/common_globals.xml.ftl" />
</globals>
recipe.xml.ftl
指定資源文件的路徑并相應的生成到我們的項目目錄去:
<recipe>
<#if appCompat && !(hasDependency('com.android.support:appcompat-v7'))>
<dependency mavenUrl="com.android.support:appcompat-v7:${buildApi}.+" />
</#if>
<#if (buildApi gte 22) && appCompat && !(hasDependency('com.android.support:design'))>
<dependency mavenUrl="com.android.support:design:${buildApi}.+" />
</#if>
<merge from="root/AndroidManifest.xml.ftl"
to="${escapeXmlAttribute(manifestOut)}/AndroidManifest.xml" />
<merge from="root/res/values/dimens.xml"
to="${escapeXmlAttribute(resOut)}/values/dimens.xml" />
<merge from="root/res/values/strings.xml.ftl"
to="${escapeXmlAttribute(resOut)}/values/strings.xml" />
<instantiate from="root/res/layout/activity_login.xml.ftl"
to="${escapeXmlAttribute(resOut)}/layout/${layoutName}.xml" />
<instantiate from="root/src/app_package/LoginActivity.java.ftl"
to="${escapeXmlAttribute(srcOut)}/${activityClass}.java" />
<open file="${escapeXmlAttribute(srcOut)}/${activityClass}.java" />
</recipe>
. copy :從root中copy文件到我們的目標目錄,比如我們的模板Activity需要使用一些圖標,那么可能就需要使用copy標簽將這些圖標拷貝到我們的項目對應文件夾。
. merge : 合并的意思,比如將我們使用到的strings.xml合并到我們的項目的stirngs.xml中
. instantiate : 和copy類似,但是可以看到上例試將ftl->java文件的,也就是說中間會通過一個步驟,將ftl中的變量都換成對應的值,那么完整的流程是ftl->freemarker process -> java。
. open:在代碼生成后,打開指定的文件,比如我們新建一個Activity后,默認就會將該Activity打開。
那么整體的關系類似下圖:

這里只是指定了生成的路徑的文件名,但是如何生成呢,這就要根據前面創建的選項來設置生成的目標文件。
root文件夾
里面都是加了ftl的java文件和XML文件,所以我們用if來判斷生成的方式。
兩個步驟:
取值--->判斷-->生成
xml文件中:
配置文件:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" >
<!-- To auto-complete the email text field in the login form with the user's emails -->
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.READ_PROFILE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<application>
<activity android:name=".${activityClass}"
<#if isNewProject>
android:label="@string/app_name"
<#else>
android:label="@string/title_${simpleName}"
</#if>
<#if hasNoActionBar>
android:theme="@style/${themeNameNoActionBar}"
</#if>
<#if buildApi gte 16 && parentActivityClass != "">android:parentActivityName="${parentActivityClass}"</#if>>
<#if parentActivityClass != "">
<meta-data android:name="android.support.PARENT_ACTIVITY"
android:value="${parentActivityClass}" />
</#if>
<#if isLauncher && !(isLibraryProject!false)>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</#if>
</activity>
</application>
</manifest>
獲取值,包括設定值和全局變量:
- 設定值:activityClass獲取,${activityClass}
全局變量:isNewProject,hasNoActionBar
if判斷
<#if isNewProject>
android:label="@string/app_name"
<#else>
android:label="@string/title_${simpleName}"
</#if>
java文件中
代碼太長不貼
也是類似的方式:
比如包名引入 package ${packageName};
判斷:
<#if parentActivityClass != "">
setupActionBar();
</#if>
最后系統根據這些東西來生成最終的文件:
流程大致可用下圖說明:

自己創造模板
分析改寫已經完成了,下面開始創造
寫個自己的登錄界面
不用完全從頭開始。我們就拿LoginActivity模板來寫。
來自:http://www.jianshu.com/p/c76facb61d69