特別說明
當(dāng)前博客平臺(tái)賬號(hào)已廢棄,如果有使用細(xì)節(jié)問題請(qǐng)前往我新博客平臺(tái)進(jìn)行討論交流。
個(gè)人博客平臺(tái) HuRuWo的技術(shù)小站
文章首發(fā)于個(gè)人博客HuRuWo的技術(shù)小站,如果本文非vip用戶無法完全瀏覽或者圖片無法打開跷车,可前往個(gè)人博客文章地址查看文章并留言討論。
個(gè)人博客文章地址android studio的自定義工程模板詳解---讓你開發(fā)神速的技巧
更多技術(shù)文章訪問本人博客HuRuWo的技術(shù)小站唁毒,包括 Electron從零開發(fā) Android 逆向 app 微信數(shù)據(jù)抓取 抖音數(shù)據(jù)抓取 閑魚數(shù)據(jù)抓取 小紅書數(shù)據(jù)抓取 其他軟件爬蟲 等技術(shù)文章
前言
最近看到有關(guān)技術(shù)博客蘑辑,發(fā)現(xiàn)了關(guān)于androidstudio的模板的有關(guān)文章,表示感興趣浇冰。
參考資料:Android Studio自定義模板 寫頁(yè)面竟然可以如此輕松
包括文中的引用部分贬媒。
關(guān)于自定義模板
在新建Activity的時(shí)候都有許多的模板供我們選擇,大胖庀埃可以自定義模板际乘,減少開發(fā)時(shí)候的重復(fù)工作。
比如這樣:
其實(shí)模板不僅限于activity 包括圖片自由 布局文件 fragment service 以及一個(gè)類都可以制作成模板漂佩。
這里只想看下Activity模板:
模板制作學(xué)習(xí)
分為三個(gè)步驟:
- 分析系統(tǒng)模板
- 改寫系統(tǒng)模板
- 自己創(chuàng)造模板
分析和改寫系統(tǒng)模板
Activity的模板地址在AS的plugins\android\lib\templates\activities
目錄下:
比如我的電腦在
C:\Program Files\Android\Android Studio\plugins\android\lib\templates\activities
Login界面用的比較多脖含,就從他開始吧。
點(diǎn)開文件夾投蝉,看到以下目錄:
下面來一一分析這些文件:
template.xml
這個(gè)是模板配置文件养葵,打開可以看到:
<?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>
- 最外面的template標(biāo)簽寫的是基本的配置:包括模板名,描述瘩缆,是否請(qǐng)求系統(tǒng)主題等等关拒。我們可以將其修改為中文。
<template
format="5"
revision="6"
name="登陸界面"
description="創(chuàng)建一個(gè)新的登陸界面"
requireAppTheme="true"
minApi="8"
minBuildApi="14">
- parameter標(biāo)簽
參數(shù)庸娱,也就是要在創(chuàng)建的時(shí)候自己設(shè)置的東西着绊。每一個(gè) parameter標(biāo)簽對(duì)應(yīng)一個(gè)參數(shù)。這些參數(shù)會(huì)顯示在創(chuàng)建頁(yè)面上熟尉。也修改為中文归露。
. id :唯一標(biāo)識(shí),最終通過該屬性的值斤儿,獲取用戶輸入值(文本框內(nèi)容剧包,是否選中)
. name:界面上的類似label的提示語
. type : 輸入值類型
. constraints:填寫值的約束
. suggest:建議值腮考,比如填寫ActivityName的時(shí)候,會(huì)給出一個(gè)布局文件的建議值玄捕。
. default:默認(rèn)值
. help:底部顯示的提升語
<parameter
id="activityClass"
name="活動(dòng)類名"
type="string"
constraints="class|unique|nonempty"
default="LoginActivity"
help="填寫所創(chuàng)建的活動(dòng)類的名稱" />
<parameter
id="layoutName"
name="布局文件名"
type="string"
constraints="layout|unique|nonempty"
suggest="${activityToLayout(activityClass)}"
default="activity_login"
help="填寫所創(chuàng)建的布局文件的名稱" />
<parameter
id="activityTitle"
name="標(biāo)題欄標(biāo)題"
type="string"
constraints="nonempty"
default="Sign in"
help="The name of the activity." />
<parameter
id="parentActivityClass"
name="父活動(dòng)類"
type="string"
constraints="activity|exists|empty"
default=""
help="配置父活動(dòng)類踩蔚,用于返回上一級(jí)按鈕" />
<parameter
id="packageName"
name="包名"
type="string"
constraints="package"
default="com.mycompany.myapp" />
3.thumbs
里面放置了樣例圖,可以嘗試更換。
4.最后指定了兩個(gè)引用文件
<globals file="globals.xml.ftl" />
<execute file="recipe.xml.ftl" />
可以測(cè)試一下修改的效果:
globals.xml.ftl和recipe.xml.ftl
在這之前先了解一下ftl結(jié)尾的文件是什么:
freemarker的文件一般以后綴ftl.
freemarker確實(shí)是不錯(cuò)的模版語言引擎枚粘,尤其是處理對(duì)象圖很方便馅闽,處理xml也很方便,還支持xpath
FreeMarker 是一個(gè)模版引擎馍迄,一個(gè)基于文本的模板輸出工具(生成任意的HTML表單代碼)福也。它是一個(gè)Java package,面向Java程序員的class library攀圈。它本身并不是針對(duì)最終用戶的應(yīng)用暴凑,而是允許程序員將其嵌入到他們的產(chǎn)品中。
FreeMarker被設(shè)計(jì)用來生成HTML Web頁(yè)面赘来,特別是基于MVC(Model View Controller)模式的應(yīng)用程序现喳。使用 MVC 模式作為動(dòng)態(tài)的WEB頁(yè)面的想法,是為了分隔頁(yè)面設(shè)計(jì)者 (HTML 設(shè)計(jì)者) 和程序員犬辰。.每個(gè)人做自己擅長(zhǎng)的那一部分嗦篱。設(shè)計(jì)者可以不通過程序員的改變或修改代碼來改變網(wǎng)頁(yè)的樣子,因?yàn)閼?yīng)用邏輯(Java程序)和頁(yè)面設(shè)計(jì)(FreeMarker 模版)是分開的幌缝。模板不會(huì)被復(fù)雜繁瑣的程序框架所破壞灸促。即使當(dāng)一個(gè)項(xiàng)目的程序員和HIMTL頁(yè)面的制作者是同一個(gè)人時(shí),這種分隔也是很有用涵卵,因?yàn)檫@樣有助于保持應(yīng)用的清晰并易于維護(hù)浴栽。
不知道大家寫過網(wǎng)頁(yè)沒有,不管是jsp還是asp還是asp.net
都會(huì)有這種在標(biāo)簽語言里面插入編程語言的方式轿偎,大概類似典鸡。
關(guān)于ftl的語法:
組成部分
一、整體結(jié)構(gòu)
1贴硫、注釋:<#--注釋內(nèi)容-->椿每,不會(huì)輸出。
2英遭、文本:直接輸出间护。
3、interpolation:由 ${var} 或 #{var} 限定挖诸,由計(jì)算值代替輸出汁尺。
4、FTL標(biāo)記
二多律、指令:
freemarker指令有兩種:
1痴突、預(yù)定義指令:引用方式為<#指令名稱>
2搂蜓、用戶定義指令:引用方式為<@指令名稱>,引用用戶定義指令時(shí)須將#換為@辽装。
注意:如果使用不存在的指令帮碰,F(xiàn)reeMarker不會(huì)使用模板輸出,而是產(chǎn)生一個(gè)錯(cuò)誤消息拾积。
freemarker指令由FTL標(biāo)記來引用殉挽,F(xiàn)TL標(biāo)記和HTML標(biāo)記類似,名字前加#來加 以區(qū)分拓巧。如HTML標(biāo)記的形式為<h1></h1>則FTL標(biāo)記的形式是<#list>< /#list>(此處h1標(biāo)記和list指令沒有任何功能上的對(duì)應(yīng)關(guān)系斯碌,只是做為說明使用一下)。
有三種FTL標(biāo)記:
1)肛度、開始標(biāo)記:<#指令名稱>
2)傻唾、結(jié)束標(biāo)記:</#指令名稱>
3)、空標(biāo)記:<#指令名稱/>
注意:
- FTL會(huì)忽略標(biāo)記之中的空格承耿,但是冠骄,<#和指令 與 </#和指令 之間不能有空格。
- FTL標(biāo)記不能夠交叉瘩绒,必須合理嵌套猴抹。每個(gè)開始標(biāo)記對(duì)應(yīng)一個(gè)結(jié)束標(biāo)記,層層嵌套锁荔。 如:
<#list>
<li>
{var}>是錯(cuò)誤的,正確的方法是:<#if var>,而且此處var必須為布爾值骡湖。
3)贱纠、FTL標(biāo)記不能位于另一個(gè)FTL標(biāo)記內(nèi)部,注釋例外响蕴。注釋可以位于標(biāo)記及interpolation內(nèi)部谆焊。
其實(shí)只要知道if即可以了,這里只用if來判斷浦夷。
globals.xml.ftl
還要引入的依賴和包辖试。
定義了全局變量辜王,并引用了一個(gè)內(nèi)置的通用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
指定資源文件的路徑并相應(yīng)的生成到我們的項(xiàng)目目錄去:
<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文件到我們的目標(biāo)目錄,比如我們的模板Activity需要使用一些圖標(biāo)罐孝,那么可能就需要使用copy標(biāo)簽將這些圖標(biāo)拷貝到我們的項(xiàng)目對(duì)應(yīng)文件夾呐馆。
. merge : 合并的意思,比如將我們使用到的strings.xml合并到我們的項(xiàng)目的stirngs.xml中
. instantiate : 和copy類似莲兢,但是可以看到上例試將ftl->java文件的汹来,也就是說中間會(huì)通過一個(gè)步驟,將ftl中的變量都換成對(duì)應(yīng)的值怒见,那么完整的流程是ftl->freemarker process -> java俗慈。
. open:在代碼生成后,打開指定的文件遣耍,比如我們新建一個(gè)Activity后闺阱,默認(rèn)就會(huì)將該Activity打開。
那么整體的關(guān)系類似下圖:
圖片來源:http://www.slideshare.net/murphonic/custom-android-code-templates-15537501
這里只是指定了生成的路徑的文件名舵变,但是如何生成呢酣溃,這就要根據(jù)前面創(chuàng)建的選項(xiàng)來設(shè)置生成的目標(biāo)文件。
root文件夾
里面都是加了ftl的java文件和XML文件纪隙,所以我們用if來判斷生成的方式赊豌。
兩個(gè)步驟:
取值--->判斷-->生成
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>
獲取值,包括設(shè)定值和全局變量:
- 設(shè)定值:activityClass獲取绵咱,${activityClass}
全局變量:isNewProject,hasNoActionBar - if判斷
<#if isNewProject>
android:label="@string/app_name"
<#else>
android:label="@string/title_${simpleName}"
</#if>
java文件中
代碼太長(zhǎng)不貼
也是類似的方式:
比如包名引入package ${packageName};
判斷:
<#if parentActivityClass != "">
setupActionBar();
</#if>
最后系統(tǒng)根據(jù)這些東西來生成最終的文件:
流程大致可用下圖說明:
圖片來源:http://www.slideshare.net/murphonic/custom-android-code-templates-15537501
自己創(chuàng)造模板
分析改寫已經(jīng)完成了碘饼,下面開始創(chuàng)造
寫個(gè)自己的登錄界面
不用完全從頭開始。我們就拿LoginActivity模板來寫悲伶。
先寫一個(gè)簡(jiǎn)單的登錄系統(tǒng):
像這樣:
把相應(yīng)的文件復(fù)制到root目錄下:
包括所用的資源文件和java文件.
template修改艾恼,添加3個(gè)東西,一個(gè)是否含有記住密碼選項(xiàng)麸锉,一個(gè)是否含有注冊(cè)選項(xiàng)钠绍,還有一個(gè)是標(biāo)題。
都是bool類型:
<parameter
id="titleString"
name="標(biāo)題名"
type="string"
constraints="nonempty"
default="默認(rèn)標(biāo)題" />
<parameter
id="isRemember"
name="是否含有記住密碼"
type="boolean"
default="false"
help="為真則添加一個(gè)checkbox在登錄按鈕上面" />
<parameter
id="isRegiste"
name="是否含有注冊(cè)選項(xiàng)"
type="boolean"
default="false"
help="為真則添加一個(gè)注冊(cè)按鈕在登錄按鈕上面" />
java文件改寫花沉,我這里沒有寫很多邏輯柳爽,簡(jiǎn)單的引入包名就可以了。加上布局文件碱屁。
package ${packageName};
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
public class ${activityClass} extends ${superClass} {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.${layoutName});
}
}
這里主要是layout文件要根據(jù)選項(xiàng)創(chuàng)建:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
tools:context="com.example.administrator.demo.MainActivity"
android:orientation="vertical"
android:background="#cccccc"
>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="10dp"
android:text="${titleString}"
android:textColor="#FF4500"
android:textSize="40sp"
android:typeface="monospace" />
<EditText
android:id="@+id/edt_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/rounded_editview"
android:drawableLeft="@drawable/ic_name"
android:hint="輸入用戶名"
android:textSize="30sp" />
<View
android:layout_width="match_parent"
android:layout_height="20dp" />
<EditText
android:id="@+id/edt__"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/rounded_editview"
android:drawableLeft="@drawable/ic_pass"
android:hint="輸入密碼"
android:inputType="textPassword"
android:textSize="30sp" />
<#if isRemember>
<CheckBox
android:padding="20dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="記住密碼"
android:textColor="#000079"
android:textSize="20sp" />
</#if>
<#if isRegiste>
<TextView
android:textColor="#000079"
android:padding="20dp"
android:text="沒有賬號(hào)?點(diǎn)此注冊(cè)"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</#if>
<Button
android:id="@+id/angry_btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/bg_edittext"
android:shadowColor="#A89A7B"
android:shadowDx="0"
android:shadowDy="0"
android:shadowRadius="5"
android:text="登錄"
android:textColor="#ffffff"
android:textSize="30sp" />
</LinearLayout>
最后檢查recipe文件對(duì)應(yīng)的名字和目錄有沒有問題以及生成方式磷脯。
<merge from="root/AndroidManifest.xml.ftl"
to="${escapeXmlAttribute(manifestOut)}/AndroidManifest.xml" />
<copy from="root/res/drawable/ic_password.png"
to="${escapeXmlAttribute(resOut)}/drawable/ic_password.png" />
<copy from="root/res/drawable/ic_user.png"
to="${escapeXmlAttribute(resOut)}/drawable/ic_user.png" />
<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/MainActivity.java.ftl"
to="${escapeXmlAttribute(srcOut)}/${activityClass}.java" />
<open file="${escapeXmlAttribute(srcOut)}/${activityClass}.java" />
主要是兩個(gè)copy 就是復(fù)制文件到目錄下,然后布局文件中就可以調(diào)用了忽媒。
測(cè)試:
這時(shí)候老板叫你開發(fā)一個(gè)登錄頁(yè)面争拐,你只需要慢慢的泡一杯茶,然后點(diǎn)擊幾下鼠標(biāo)。
當(dāng)然這是個(gè)簡(jiǎn)單的模板架曹,不過各位學(xué)會(huì)了之后可以寫一些符合自己需求的模板隘冲。
推薦一些開源的模板地址
如果大家有時(shí)間逛github,直接搜索Android Studio Template即可绑雄。
https://github.com/kanytu/Android-studio-material-template
A template for Android Studio to create applications with material design and Navigation Drawer.包含:MaterialNavigationDrawerActivity展辞。
https://github.com/gabrielemariotti/AndroidStudioTemplate
包含SwipeRefreshLayout,還有一些常用的模板万牺。
https://github.com/intrications/material-design-icons-adt-template
用于創(chuàng)建Material Design Icon罗珍,可以非常方便的創(chuàng)建Icon,再也不需要自己去找下載各種尺寸了脚粟。
hoangyang的例子
一個(gè)ViewPage的模板
最后的總結(jié)
- 模板雖好覆旱,切勿濫用
- 寫模板盡量寫的通用一些。一些具體的東西還是要手寫核无。
- 注意備份模板扣唱,重裝系統(tǒng)的軟件都會(huì)丟失模板。
我的開發(fā)工具用的是sublime2团南,理論上任何一個(gè)文本編輯器都可以噪沙,但是我有Notepad++會(huì)有格式上的報(bào)錯(cuò)。
附上本文中我寫的模板吐根,當(dāng)然我也會(huì)繼續(xù)開發(fā)好用的模板上傳正歼。
https://github.com/HuRuWo/Android-Studio-Template
放置到Android Studio\plugins\android\lib\templates\activities 目錄下,重啟as即可拷橘。