Android Template学习笔记

栏目: IOS · Android · 发布时间: 5年前

内容简介:Android Studio的Template,可以从复杂程度上分为三种:Live Template,File Template和Android Studio工程模板,前两种模板在Jetbrain家的其他IDE中也可以使用,可以看做是依赖于IDE本身的功能,最后一个则需要复杂的模板代码支持。用几个字母+tab展开成一段代码,然后在需要的位置填上自定义内容。设置入口:Settings->Editor->Live Templates

Android Studio的Template,可以从复杂程度上分为三种:Live Template,File Template和Android Studio工程模板,前两种模板在Jetbrain家的其他IDE中也可以使用,可以看做是依赖于IDE本身的功能,最后一个则需要复杂的模板代码支持。

Live Template

用几个字母+tab展开成一段代码,然后在需要的位置填上自定义内容。

设置入口:Settings->Editor->Live Templates

Android Template学习笔记

右侧点击 + 号之后填写下面的信息,代码中的 $name$ 表示这段代码中可以自定义的部分,在第一个 $name$ 处输入,所有的 $name$ 占位部分都会同时变化。第一处占位符输入完成按 enter 后会自动跳转到第二处占位符输入下一个变量。 代码和缩写字母定义完毕后,一定要选左下角的生效语言范围才会生效,右下角是设置触发的按键(一般是 tab

File Template

以模板生成文件 设置入口:Settings->Editor->File Templates

Android Template学习笔记
点击 +

创建新模板。编写模板会使用一些占位符语法,在创建文件时自动转换成代码。

预定义的变量

预定义的变量可以直接在文件模板中使用:

${PACKAGE_NAME}
${NAME}
${USER}
${DATE}
${TIME}
${YEAR}
${MONTH}
${MONTH_NAME_SHORT}
${MONTH_NAME_FULL}
${DAY}
${DAY_NAME_SHORT}
${DAY_NAME_FULL}
${HOUR}
${MINUTE}
${PROJECT_NAME}

include其他模板

使用 #parse 可以在模板中包括进其他模板的内容,例如通用的文件创建人和创建时间信息,可以放在一个header文件中,在第二个 Includes tab中定义:

Android Template学习笔记

代码如下

/**
 *
 * Created by ${USER} on ${DATE}.
 */
复制代码

在使用时就可以在其他模板中使用 #parse("Kt File Header.kt") 引入这个header,生成文件时自动转换成这样的注释代码。

自定义变量

除了以上预定义的变量,用 ${xxx} 的格式自定义一些变量名,在创建文件时会同时提示填写这些变量:

#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME}
#end

import androidx.room.Entity

#parse("Kt File Header.kt")
@Entity(tableName = "${tableName}s")
data class ${NAME}(var ${props}: String): BaseModel()
复制代码

在这段代码中自定义了tableName和props两个变量,在新建文件时就会要求填写:

Android Template学习笔记

最后生成的代码:

package info.zhufree.windwhite.bean

import androidx.room.Entity

/**
 *
 * Created by zhufree on 2019/4/26.
 */
@Entity(tableName = "tests")
data class TestModel(var title: String) : BaseModel()
复制代码

ActivityTemplate

最后一种也是最复杂的模板,可以直接生成多个配套文件,典型的例子就是新建Activity,会直接生成一个Activity文件+layout文件,如果是复杂的带Fragment的,带ViewModel的,则会自动生成Fragment以及ViewModel文件等:

Android Template学习笔记

除了Activity,也可以直接创建Project等等:

Android Template学习笔记

这种模板不能直接在设置中定义,需要自己编写,放在AndroidStudio的模板文件夹中,重启Studio即可使用。编写模板需要用到Free Marker语言。 文件夹路径: MacOS: /Applications/Android Studio.app/Contents/plugins/android/lib Windows: [Android Studio安装目录]/plugins/android/lib/templates

模板文件夹中不同文件的作用:

template.xml

这个文件可以看做定义Activity模板的清单文件,列出在创建Activity时需要填的所有变量,对应这个页面:

Android Template学习笔记
<?xml version="1.0"?>
<template
    format="5"
    revision="5"
    name="Empty Activity"
    minApi="9"
    minBuildApi="14"
    description="Creates a new empty activity">
    <!--定义模板本身的一些属性-->

	<!--模板类型-->
    <category value="Activity" />
    <!--适用于手机,相对的还有平板,TV,可穿戴设备等-->
    <formfactor value="Mobile" />

	<!--parameter标签定义需要填的参数-->
	<!--id 在后面引用时使用-->
	<!--name 解释这个参数意义的名字-->
	<!--type 填的数据类型-->
	<!--constraints 填的内容限制(类名,独一,不可为空)-->
	<!--suggest 在填写其他参数时可以根据其他参数的变化自动填充(根据layoutName进行下划线转驼峰命名生成)-->
	<!--default 默认值-->
	<!--help 显示在左下角的提示文字-->
    <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" />

	<!--boolean类型显示的是一个勾选框+Name-->
    <parameter
        id="generateLayout"
        name="Generate Layout File"
        type="boolean"
        default="true"
        help="If true, a layout file will be generated" />

	<!--visibility 可见性,这里意思是勾选了上面的generateLayout才会显示填写布局文件名这一行-->
    <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="backwardsCompatibility"
        name="Backwards Compatibility (AppCompat)"
        type="boolean"
        default="true"
        help="If false, this activity base class will be Activity instead of AppCompatActivity" />

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

    <parameter
        id="includeInstantAppUrl"
        name="Associate a URL with this Activity"
        type="boolean"
        default="false"
        visibility="isInstantApp!false"
        help="If true, this activity will be associated with URL, improving discovery of your Instant App" />

    <parameter
        id="instantAppActivityHost"
        name="Instant App URL Host"
        type="string"
        suggest="${companyDomain}"
        default="instantapp.example.com"
        visibility="isInstantApp!false"
        enabled="includeInstantAppUrl"
        help="The domain to use in the Instant App route for this activity"/>

    <parameter
        id="instantAppActivityRouteType"
        name="Instant App URL Route Type"
        type="enum"
        default="pathPattern"
        visibility="isInstantApp!false"
        enabled="includeInstantAppUrl"
        help="The type of route to use in the Instant App route for this activity" >
        <option id="path">Path</option>
        <option id="pathPrefix">Path Prefix</option>
        <option id="pathPattern">Path Pattern</option>
    </parameter>

    <parameter
        id="instantAppActivityRoute"
        name="Instant App URL Route"
        type="string"
        default="/.*"
        visibility="isInstantApp!false"
        enabled="includeInstantAppUrl"
        help="The route to use in the Instant App route for this activity"/>

    <!-- 128x128 thumbnails relative to template.xml -->
    <!-- 显示在左边的缩略图 -->
    <thumbs>
        <!-- default thumbnail is required -->
        <thumb>template_blank_activity.png</thumb>
    </thumbs>

	<!-- 声明一些全局定义的global变量 -->
    <globals file="globals.xml.ftl" />
    <!-- 执行recipe.xml.ftl文件来生成目标文件 -->
    <execute file="recipe.xml.ftl" />
</template>
复制代码

在这个页面用户填写的变量值,将和 globals.xml.ftl 中预定义的全局变量值一起作为可用的变量在后面编写模板代码的过程中使用。

recipe.xml

recipe文件中定义以哪个文件为模板来生成哪个文件:

<?xml version="1.0"?>
<#import "root://activities/common/kotlin_macros.ftl" as kt>
<recipe>
    <#include "../common/recipe_manifest.xml.ftl" />
    <@kt.addAllKotlinDependencies />
<!-- 根据generateLayout判断是否要生成layout文件 -->
<#if generateLayout>
	<!-- 在recipe_simple中处理生成layout文件的逻辑,和下面的instantiate一样 -->
    <#include "../common/recipe_simple.xml.ftl" />
    <!-- 文件创建完之后用open打开 -->
    <open file="${escapeXmlAttribute(resOut)}/layout/${layoutName}.xml" />
</#if>
	<!-- from 模板文件位置 to 目标文件位置 -->
    <instantiate from="root/src/app_package/SimpleActivity.${ktOrJavaExt}.ftl"
                   to="${escapeXmlAttribute(srcOut)}/${activityClass}.${ktOrJavaExt}" />
    <open file="${escapeXmlAttribute(srcOut)}/${activityClass}.${ktOrJavaExt}" />
</recipe>
复制代码

以上这些文件和png图片都在模板文件夹的根目录下,对于较复杂的模板, root 文件夹下分为 srcres 文件夹,以及清单文件模板 AndroidManifest.xml.ftl 等等,和真实的项目结构类似, src 文件夹中 app_package 则代表包名路径,之后是 activity 等类文件的模板,一般有 .java.ftl.kt.ftl 两种后缀的,分别对应生成 .java 文件和 .kt 文件。 res 文件夹中则可能会有 layout/menu/values 等文件夹,放置布局,菜单,资源值等类型的模板文件。

Activity.ftl

src 文件夹下的 ActivityFragment 等类的模板文件,同理可添加 Adapter 之类的模板。 以最简单的 Activity+kotlin 语言为例:

// 声明包名
package ${escapeKotlinIdentifiers(packageName)}
// 导入一些必要的包,这里的${superClassFqcn}在common_global.xml.ftl中定义,根据是否是appCompatActivity,是否useAndroidX导入了不同的Activity
import ${superClassFqcn}
import android.os.Bundle
// 判断是否导入布局控件
<#if (includeCppSupport!false) && generateLayout>
import kotlinx.android.synthetic.main.${layoutName}.*
</#if>

// 定义activity类名,继承父类
class ${activityClass} : ${superClass}() {

	// 自动生成onCreate方法
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
		// 如果生成了layout文件,调用setContentView方法
<#if generateLayout>
        setContentView(R.layout.${layoutName})
        <#include "../../../../common/jni_code_usage.kt.ftl">
<#elseif includeCppSupport!false>

        // Example of a call to a native method
        android.util.Log.d("${activityClass}", stringFromJNI())
</#if>
    }
<#include "../../../../common/jni_code_snippet.kt.ftl">
}
复制代码

superClassFqcn 的定义( common_global.xml.ftl ):

<#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" />
    <global id="kotlinActionBar" type="string" value="actionBar" />
    <global id="kotlinFragmentManager" type="string" value="fragmentManager" />
<#elseif appCompatActivity>
    <global id="superClass" type="string" value="AppCompatActivity"/>
    <global id="superClassFqcn" type="string" value="${getMaterialComponentName('android.support.v7.app.AppCompatActivity', useAndroidX)}"/>
    <global id="Support" value="Support" />
    <global id="actionBarClassFqcn" type = "string" value="${getMaterialComponentName('android.support.v7.app.ActionBar', useAndroidX)}" />
    <global id="kotlinActionBar" type="string" value="supportActionBar" />
    <global id="kotlinFragmentManager" type="string" value="supportFragmentManager" />
<#else>
    <global id="superClass" type="string" value="ActionBarActivity"/>
    <global id="superClassFqcn" type="string" value="${getMaterialComponentName('android.support.v7.app.ActionBarActivity', useAndroidX)}"/>
    <global id="Support" value="Support" />
    <global id="actionBarClassFqcn" type = "string" value="${getMaterialComponentName('android.support.v7.app.ActionBar', useAndroidX)}" />
    <global id="kotlinActionBar" type="string" value="supportActionBar" />
    <global id="kotlinFragmentManager" type="string" value="supportFragmentManager" />
</#if>
复制代码

layout.xml.ftl

作为模板的布局文件在 root/res/layout 文件夹下,以一个最简单的 simple.xml.ftl 为例:

<?xml version="1.0" encoding="utf-8"?>
<!-- 判断根布局用哪个版本的ConstraintLayout -->
<${getMaterialComponentName('android.support.constraint.ConstraintLayout', useAndroidX)}
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
<#if hasAppBar && appBarLayoutName??>
app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:showIn="@layout/${appBarLayoutName}"
</#if>
<!--如果有appbar,需要设置behavior-->
    tools:context="${packageName}.${activityClass}">
<!-- 添加一个示例的TextView -->
<#if isNewProject!false>
    <TextView
<#if includeCppSupport!false>
        android:id="@+id/sample_text"
</#if>
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</#if>
</${getMaterialComponentName('android.support.constraint.ConstraintLayout', useAndroidX)}>
复制代码

总体来说,这一类模板结构可能比较复杂,但原理都是根据预定义的变量和自定义的变量,加上事先编写好的模板代码,通过不同的条件判断,填充变量名等操作最终生成目标文件代码。 编写模板文件需要了解一些常用的预定义变量和f ree maker 语法等,可以参考上面的官方手册。 使用 ActivityProject 层级的模板需要一定的时间成本,属于磨刀不误砍柴工,一旦完成能够节省很多复制粘贴再修改的工作,但需要平衡好模板化和自定义化的程度,编写符合自己需求同时也具有足够复用价值的模板代码。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

为什么中国没出Facebook

为什么中国没出Facebook

谢文 / 凤凰出版社 / 2011-7-1 / 39.80元

《为什么中国没出Facebook》对互联网的游戏规则、市场、格局、模式及发展趋势等多方面进行了阐述,既勾画出了理想中的互联网生态及其本质,又联系中国实际,探讨了中国互联网行业的未来发展。《为什么中国没出Facebook》提出了在互联网成事应该符合的8条原则,比较了Facebook、MySpace、Twitter三种创新模式,指出了Web2.0平台时代新浪、腾讯、百度、搜狐等互联网巨头的未来方向,也......一起来看看 《为什么中国没出Facebook》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具