亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

懶人進階-activitys選項

2019-11-09 17:34:45
字體:
來源:轉載
供稿:網友

先引用網友的成果

1、概述

上一篇文章,已經初步對Android Studio的模板有了初步的介紹及使用,以及一些開源模板的推薦:

本文將對如何編寫Template,進行詳細的介紹(以activity模板為例)

2、模板的文件結構

學習編寫模板最好的方式呢,就是參考IDE中已經提供的最簡單的模板,那么在Android Studio中最簡單的activity模板就是:Empty Activity了,我們打開該模板文件,首先對文件結構有個直觀的了解,如圖:

Empty Activity 文件結構

可以看到每個插件對應一個文件夾,文件夾包含:

template.xmlrecipe.xml.ftlglobals.xml.ftlroot效果縮略圖

下面我們逐一對上述每個文件的作用進行介紹

template.xml

首先看源碼

<?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" name="Activity Name" type="string" constraints="class|unique|nonempty" suggest="${layoutToActivity(layoutName)}" default="MainActivity" help="The name of the activity class to create" /> <!-- 省略N個 parameter 標簽--> <!-- 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>

其中

<template> 標簽的name屬性,對應新建Activity時顯示的名字<category> 對應New的類的類別為Activity

剩下的,對應我們Android Studio新建Empty Activity的界面就很好理解了,如圖:

Configure Activity

看到這個界面大部分屬性都出來了,我們重點看parameter,界面上每個框出來的部分對應一個parameter部分屬性介紹:

id:唯一標識,最終通過該屬性的值,獲取用戶輸入的值(文本框內容 || 是否選中)name:界面上類似Label的提示語type:輸入值類型constraints:填寫值的約束suggest:建議值,比如填寫ActivityName的時候,會給出一個布局文件的建議值。default:默認值help:底部顯示的提示語

這個部分對應界面還是非常好理解的,大家可以簡單的修改一些字符串,或者添加一個<parameter>,重啟AS,看看效果。

template.xml的最下面的部分引入了globals.xml.ftl和recipe.xml.ftl。這兩個我們會詳細介紹。

globals.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>

通過名稱可以猜出它是用于定義一些全局的變量,可以看到其內部有<global>標簽分別定義id,type,value。同理,我們可以通過id訪問到該值,例如:${hasNoactionBar} 的值為false

recipe.xml.ftl

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

為了介紹,我們將幾個重要標簽都列出來

include 此文件包含其它文件內容,和xml布局include作用一致merge 合并的意思,比如將我們使用到的strings.xml合并到我們的項目的stirngs.xml中open 在代碼生成后,打開指定的文件,比如我們新建一個Activity后,默認就會將該Activity打開。instantiate 實例化,生成相應文件??梢钥吹缴侠噷tl->java文件的,也就是說中間會通過一個步驟,將ftl中的變量都換成對應的值,那么完整的流程是ftl->freemarker PRocess -> java

在介紹instantiate時,涉及到了freemarker,不可避免的需要對它進行簡單的介紹。目前我們已經基本了解了一個模板其內部的文件結構了,以及每個文件大致包含的東西,我們簡單做個總結:

template 中parameter標簽,主要用于提供參數global.xml.ftl 主要用于提供參數recipe.xml.ftl 主要用于生成我們實際需要的代碼,資源文件等;例如,利用參數+MainActivity.java.ftl -> MainActivity.java;其實就是利用參數將ftl中的變量進行替換。

那么整體的關系類似下圖:

Template Variable Dataflow

3、簡單的freemarker語法

上面我們已經基本了解模板生成的大致的流程以及涉及到的文件,大致了解了我們生成的源碼或者xml文件,需要經過:ftl -> freemarker process -> java/xml這樣的流程,那么我們必須對freemarker有個簡單的了解。

一個簡單的例子比如我們有個變量user=art有個ftl文件內容:helloL${user}最后經過freemarker的輸出結果即為 hello:artif語法<# if generateLayout> //生成Layout文件</#if>

看一眼就知道大概的意思了~有一定的編程經驗,即使不知道這個東西叫freemarker,對于這些簡單的語法還是能看懂的。

我們最后以Empty Activity模板中的SimpleActivit為例:

// root/src/app_package/SimpleActivity.java.ftlpackage ${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> }}

可以看到其內部包含很多變量,這些變量的值一般來源于用戶的輸入和global.xml.ftl中預定義的值,經過recipe.xml.ftl中instantiate標簽的處理,將變量換成實際的值,即可在我們的項目的指定位置,得到我們期望的Activity。

流程大致可用下圖說明:

圖片來源:http://www.slideshare.net/murphonic/custom-android-code-templates-15537501

看到這,最起碼理解了,當我們能選擇創建不同的Activity類型,最終得到的不同的效果其中的原理原來在這。

4、具體的模板實例

了解了基本的理論之后,下面我們可以通過一個實例來將上面的知識點整合。

我們編寫了一個Activity模板叫做:Splash Activity,用于創建一個全屏自動finish的activity,效果如下:

Paste_Image.png

當我們點擊New | Activity | Fragment Activity 就可以完成上面的Activity的創建,而避免了編寫布局文件,引入design庫以及一些簡單的編碼。

是不是感覺還是不錯的,大家可以針對自己的需求,按照規范的格式歲月指定模板。

建議大家copy一個現有的模板,再其基礎上修改即可,比如本例是在Empty Activity基礎上修改的。

下面我們看上栗的具體的實現。

4.1 template.xml的編寫

通過上面的學習我們知道template.xml中可以定義我們創建面板的控件布局等,本例我們創建Activity的界面如下:

對應的template.xml如下:

<?xml version="1.0"?><template format="5" revision="5" name="Splash Activity" requireAPPTheme="true" minApi="7" minBuildApi="14" description="Creates a new Splash activity"> <category value="Activity" /> <formfactor value="Mobile" /> <parameter id="activityClass" name="Activity Name" type="string" constraints="class|unique|nonempty" default="SplashActivity" 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_splash" 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_splash_activity.png</thumb> </thumbs> <globals file="globals.xml.ftl" /> <execute file="recipe.xml.ftl" /></template>

PS:注意Activity Name那里變化

經過前面的學習應該很好理解,每個parameter對應界面上的一個控件,控件的這個id最終可以得到用戶輸入值,后面會用于渲染ftl文件

4.2、用到的類

本例中最終要生成Activityu,也就是說對應會有一個ftl文件用于最終生成這個類。

// root/src/app_package/SplashActivity.java.ftlpackage ${packageName};import ${superClassFqcn};import android.os.Bundle;import android.os.Handler;<#if applicationPackage??>import ${applicationPackage}.R;</#if>public class ${activityClass} extends ${superClass} { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.${layoutName}); } @Override protected void onPostCreate(Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); delayedHide(2000); } @Override protected void onDestroy() { super.onDestroy(); mHideHandler.removeCallbacks(mHideRunnable); } private void hide() { finish(); } private final Handler mHideHandler = new Handler(); private final Runnable mHideRunnable = new Runnable() { @Override public void run() { hide(); } }; /** * Schedules a call to hide() in [delay] milliseconds, canceling any * previously scheduled calls. */ private void delayedHide(int delayMillis) { mHideHandler.removeCallbacks(mHideRunnable); mHideHandler.postDelayed(mHideRunnable, delayMillis); } @Override public void finish() { super.finish(); mHideHandler.removeCallbacks(mHideRunnable); overridePendingTransition(0, 0); }}

注意不是.java文件而是.ftl文件,可以看到上面的代碼基礎上和Java代碼沒什么區別,實際上就是Java代碼,把可變的部分編程了 ${變量名}的方式而已。例如:類名是用戶填寫的,我們就使用${activityClass}替代,其它同理。

4.3、 用到的布局文件

//root/res/layout/activity_splash.xml.ftl<FrameLayout 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:background="@android:color/white" tools:context="${relativePackage}.${activityClass}"> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:src="@mipmap/ic_launcher"/></FrameLayout>

4.4、用到的AndroidManifest.xml.ftl

//root/AndroidManifest.xml.ftl<manifest xmlns:android="http://schemas.android.com/apk/res/android" > <application> <activity android:name="${relativePackage}.${activityClass}" <#if isNewProject> android:label="@string/app_name" <#else> android:label="@string/title_${simpleName}" </#if> android:configChanges="orientation|keyboardHidden|screenSize" android:theme="@style/SplashTheme"> <#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>

4.5、用到的values

//root/res/values/styles.xml.ftl<resources> <style name="SplashTheme" parent="${themeName}"> <!-- 隱藏狀態欄 --> <<item name="android:windowFullscreen">true</item> <!-- 隱藏標題欄 --> <item name="android:windowNoTitle">true</item> <item name="android:windowBackground">@null</item> </style></resources>// root/res/values/strings.xml.ftl<resources> <#if !isNewProject> <string name="title_${simpleName}">${escapeXmlString(activityTitle)}</string> </#if></resources>

發現和我們真正編寫的Activity并無多大區別。

看完用到的類和布局文件的ftl,大家心里應該有個底了,這模板幾乎就和我們平時寫的java類一樣,只是根據用戶據在新建Activity界面所輸入的參數進行換一些變量或者做一些簡單的操作而已。

4.6、recipe.xml.ftl的編寫

除了template.xml還有gobals.xml和recipe.xml.ftl,gobals.xml.ftl中基本上沒有修改任何內容就不介紹了。

recipe.xml.ftl中定義的東西比較關鍵,例如將ftl->java,copy,merge資源文件等。內容較長,我們拆開描述。

<?xml version="1.0"?><recipe> <#if appCompat && !(hasDependency('com.android.support:appcompat-v7'))> <dependency mavenUrl="com.android.support:appcompat-v7:${buildApi}.+" /> </#if> <merge from="root/AndroidManifest.xml.ftl" to="${escapeXmlAttribute(manifestOut)}/AndroidManifest.xml" /> <merge from="root/res/values/styles.xml.ftl" to="${escapeXmlAttribute(resOut)}/values/styles.xml" /> <instantiate from="root/res/layout/activity_splash.xml.ftl" to="${escapeXmlAttribute(resOut)}/layout/${layoutName}.xml" /> <instantiate from="root/src/app_package/SplashActivity.java.ftl" to="${escapeXmlAttribute(srcOut)}/${activityClass}.java" /> <open file="${escapeXmlAttribute(srcOut)}/${activityClass}.java" /> <open file="${escapeXmlAttribute(resOut)}/layout/${layoutName}.xml" /></recipe>

本例依賴v7庫,我們需要在這里定義引入;上例,轉化了

${activityClass}.java/layout/${layoutName}.xml合并了AndroidManifest.xmlstyles.xml

剩下的是open標簽,主要就是用于新建完成后,自動打開該文件。

ok,到這,我們整個模板的編寫介紹就結束了。

如何創建自己activity并直接繼承的BaseActivity

1、修改....Activity.java.ftl文件創建的activity就是以此為模板的如:
package ${packageName};import ${superClassFqcn};import android.os.Bundle;<#if includeCppSupport!false>import android.widget.TextView;</#if>public class ${activityClass} extends ${superClass} {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);<#if generateLayout>        setContentView(R.layout.${layoutName});</#if><#include "../../../../common/jni_code_usage.java.ftl"> startRun();    }<#include "../../../../common/jni_code_snippet.java.ftl">  @Override    public void findView() {    }    @Override    public void initData() {    }    @Override    public void initView() {    }    @Override    public void initClicked() {    }    @Override    public void updateUI() {    }}
2、修改template.xml文件 創建activity時的界面選項名由此配置3、修改globals.xml.ftl文件 創建activity是模板中的變量由此文件定義值如:
<?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" />    		<#assign theme=getApplicationTheme()!{ "name": "AppTheme", "isAppCompat": true }>    <#assign themeName=theme.name!'AppTheme'>    <#assign themeNameNoActionBar=theme.nameNoActionBar!'AppTheme.NoActionBar'>    <#assign appCompat=backwardsCompatibility!(theme.isAppCompat)!false>	<#assign baseActivity=appCompat && (buildApi gte 22)>    <#assign espresso=hasDependency('com.android.support.test.espresso:espresso-core', 'androidTestCompile')>    <#assign supportRunner=hasDependency('com.android.support.test:runner', 'androidTestCompile')>    <#assign testSupportLib=espresso && supportRunner>    <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="${appCompat?string}" />	<global id="baseActivity" type ="boolean" value="${baseActivity?string}"/>    <global id="hasAppBar" type="boolean" value="${baseActivity?string}" />    <global id="hasNoActionBar" type="boolean" value="${baseActivity?string}" />    <global id="testSupportLib" type="boolean" value="${testSupportLib?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 baseActivity>	<global id="superClass" type="string" value="BaseActivity"/>    <global id="superClassFqcn" type="string" value="com.zaxxkj.utils.base.BaseActivity"/>    <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>

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产裸体写真av一区二区| 久久成人国产精品| 国产精品久久久久一区二区| 91精品国产色综合久久不卡98口| 国产成人精品视频在线观看| 国产精品成久久久久三级| 成人精品福利视频| 久久国产精品亚洲| 精品国产福利视频| 91探花福利精品国产自产在线| 久久国产一区二区三区| 精品国产自在精品国产浪潮| 亚洲高清一二三区| 精品一区二区三区电影| 亚洲国产精品热久久| 亚洲一区二区免费在线| 久久91精品国产91久久久| 欧美成在线视频| 日韩精品久久久久久福利| 久久五月情影视| 免费99精品国产自在在线| 亚洲欧美中文日韩v在线观看| 欧美日韩成人在线观看| 久久久久久久影视| 日韩在线视频线视频免费网站| 久久精品成人欧美大片古装| 97精品国产91久久久久久| 日韩精品欧美激情| 亚洲性视频网址| 欧美精品在线观看91| 国产97在线|日韩| 国产精品久久久久久亚洲影视| 欧美成人网在线| 韩国福利视频一区| 亚洲最大福利视频| 欧美xxxx18国产| 日韩在线播放一区| 亚洲第一视频网站| 日韩欧美精品中文字幕| 国产成人精品久久亚洲高清不卡| 欧美肥老妇视频| 日韩精品在线观看视频| 亚洲国内高清视频| 国产精品mp4| 亚洲欧美一区二区三区情侣bbw| 国产v综合ⅴ日韩v欧美大片| xx视频.9999.com| 亚洲精品97久久| 国产精品日韩欧美大师| 5566成人精品视频免费| 97国产真实伦对白精彩视频8| 97视频在线免费观看| 日韩成人xxxx| 欧美日韩国产成人在线观看| 青青草国产精品一区二区| 亚洲精品美女视频| 久久久久久久久综合| 91国偷自产一区二区三区的观看方式| 亚洲国产精品网站| 日韩一区视频在线| 亚洲精品福利在线观看| 久久精品电影网站| 青青草成人在线| 5566成人精品视频免费| 欧美极品少妇xxxxⅹ免费视频| 爱福利视频一区| 在线精品91av| 国产欧美在线播放| 久久久精品2019中文字幕神马| 欧美日韩精品在线观看| 日韩av免费看| 欧美国产乱视频| 国产一区二区日韩| 欧日韩不卡在线视频| 欧美日韩裸体免费视频| 久久久亚洲影院| 欧美视频中文在线看| 18久久久久久| 97热在线精品视频在线观看| 国产精品欧美日韩一区二区| 一本色道久久综合狠狠躁篇怎么玩| 一本大道亚洲视频| 日韩不卡中文字幕| 亚洲在线免费观看| 国内免费精品永久在线视频| yw.139尤物在线精品视频| 中文字幕欧美日韩精品| 欧美激情精品久久久久久免费印度| 国产精品99久久久久久久久久久久| 91精品在线播放| 欧美久久精品一级黑人c片| 91wwwcom在线观看| 日本高清视频一区| 欧美第一淫aaasss性| 成人在线视频网站| 97免费视频在线| 欧美裸体男粗大视频在线观看| 久久久久久久久久久人体| 亚洲无亚洲人成网站77777| 亚洲一区二区中文字幕| 国产三级精品网站| 久久人人爽人人爽人人片av高请| 欧美日韩国产激情| 亚洲影影院av| 亚洲一区亚洲二区| 欧美福利视频在线| 国产成人免费av电影| 日韩精品有码在线观看| 久久韩剧网电视剧| 亚洲日本中文字幕| 日本精品免费观看| 日韩在线观看视频免费| 中文字幕亚洲精品| 欧美国产日产韩国视频| 国产一区二区三区在线播放免费观看| 久久精品国产久精国产思思| 欧美尤物巨大精品爽| 亚洲黄在线观看| 午夜剧场成人观在线视频免费观看| 欧美与欧洲交xxxx免费观看| 国产精品69av| 亚洲va欧美va在线观看| 久久精品亚洲热| 人九九综合九九宗合| 国产精品视频99| 一区二区三区动漫| 成人激情电影一区二区| 亚洲人成免费电影| 国产精品久久久久久久久免费| 亚洲精品视频在线播放| 国产欧美久久久久久| 成人午夜激情免费视频| 亚洲精品电影久久久| 欧美日韩视频免费播放| 欧美日韩精品二区| 午夜精品一区二区三区视频免费看| 日韩视频―中文字幕| 色阁综合伊人av| 久久99国产精品久久久久久久久| 亚洲欧美国产精品专区久久| 精品日本美女福利在线观看| 91在线免费视频| 国产成人一区二区三区小说| 亚洲欧洲日韩国产| 欧美激情2020午夜免费观看| 亚洲国产一区二区三区四区| 国产成人久久久精品一区| 中文字幕在线国产精品| 国产欧美一区二区白浆黑人| 久久精品一偷一偷国产| 亚洲中国色老太| 国产精品啪视频| 91超碰caoporn97人人| 欧美性xxxx极品hd满灌| 亚洲欧美资源在线| 久久国产一区二区三区| 青青久久aⅴ北条麻妃| 久久97精品久久久久久久不卡| 国模gogo一区二区大胆私拍| 亚洲一区二区久久久| 国产精品网址在线| 国外成人在线直播| 45www国产精品网站| 国内精久久久久久久久久人|