专注于 JetBrains IDEA 全家桶,永久激活,教程
持续更新 PyCharm,IDEA,WebStorm,PhpStorm,DataGrip,RubyMine,CLion,AppCode 永久激活教程

自定义Android 项目模板,不需要记忆什么快捷键和Live Templates就能提高Android开发效率

这篇文章介绍自定义Android 项目模板,分为两部分:

1、 修改new Project的默认设置,用于生成新项目的时候,添加自定义的目录、文件、内容。例如:asset文件、anim文件、arrays.xml等;
2、 修改new xxx的默认设置,用于已经存在的项目,生成模板代码,如图所示:

61_1.png

修改new Project的默认设置

用于生成新项目的时候,添加自定义的目录、文件、内容。

进入 Android Studio 安装目录,依次进入 plugins –> android –> lib –> templates –> gradle-projects –> NewAndroidModule,然后用编辑器打开 recipe.xml.ftl文件,recipe.xml.ftl文件就是创建新项目的默认设置文件。

增加默认生成目录

一般我们创建新的项目的时候,默认都会生成如下的文件层次结构:

MyProject/
    src/
        MyActivity.java
    res/
        drawable/
            graphic.png
        layout/
            main.xml
            info.xml
        mipmap/
            icon.png
        values/
            strings.xml

但是一般项目开发只有这些是远远不够的,这时候我们就可以修改设置,默认生成我们所需要的资源文件,所有项目 res/ 目录中支持的资源目录有:

文件 介绍
animator/ 用于定义属性动画的 XML 文件。
anim/ 用于定义渐变动画的 XML 文件。(属性动画也可保存在此目录中,但为了区分这两种类型,属性动画首选 animator/ 目录。)
color/ 用于定义颜色状态列表的 XML 文件。请参阅颜色状态列表资源
drawable/ 存放图片
mipmap/ 存放应用的图标
layout/ 用于定义用户界面布局的 XML 文件。请参阅布局资源。
menu/ 用于定义应用菜单(如选项菜单、上下文菜单或子菜单)的 XML 文件。
raw/ 需以原始形式保存的任意文件。如要使用原始 InputStream 打开这些资源,请使用资源 ID(即 R.raw.filename)调用 Resources.openRawResource()。但是,如需访问原始文件名和文件层次结构,则可以考虑将某些资源保存在 assets/ 目录(而非 res/raw/)下。assets/ 中的文件没有资源 ID,因此您只能使用 AssetManager 读取这些文件。
values/ 包含字符串、整型数和颜色等简单值的 XML 文件。

如图在recipe.xml.ftl中加入如下代码,就可以默认生成

61_2.png

代码如下:

    <mkdir at="${escapeXmlAttribute(projectOut)}/libs" />
    <mkdir at="${escapeXmlAttribute(resOut)}/drawable" />
    <mkdir at="${escapeXmlAttribute(resOut)}/drawable-hdpi" />
    <mkdir at="${escapeXmlAttribute(resOut)}/drawable-xhdpi" />
    <mkdir at="${escapeXmlAttribute(resOut)}/drawable-xxhdpi" />
    <mkdir at="${escapeXmlAttribute(resOut)}/anim" />
    <mkdir at="${escapeXmlAttribute(resOut)}/animator" />
    <mkdir at="${escapeXmlAttribute(resOut)}/color" />
    <mkdir at="${escapeXmlAttribute(resOut)}/menu" />
     <mkdir at="${escapeXmlAttribute(resOut)}/raw" />
    <mkdir at="${escapeXmlAttribute(resOut)}/xml" />
    <mkdir at="${escapeXmlAttribute(resOut)}/font" />
    <mkdir at="${escapeXmlAttribute(projectOut)}/assets" />

mkdir代表创建目录;projectOut代表项目即MyProject目录下;resOut代表res目录下。

默认生成values/目录下的xml文件

values/目录下常用的xml文件如下:

  • arrays.xml:资源数组(类型数组)。
  • colors.xml:颜色值。
  • dimens.xml:尺寸值。
  • strings.xml:字符串值。
  • styles.xml:样式
  • attrs.xml:view属性

进入 Android Studio 安装目录,依次进入 plugins –> android –> lib –> templates –> gradle-projects –> NewAndroidModule–>root–>res–>values目录下,在该目录下,创建arrays.xmldimens.xmlattrs.xml。代码如下:

<?xml version="1.0" encoding="UTF-8"?>
<resources> 

</resources>

然后在recipe.xml.ftl中设置默认创建这些文件,如图所示:

61_3.png

代码如下:

   <instantiate from="root/res/values/arrays.xml"
                   to="${escapeXmlAttribute(resOut)}/values/arrays.xml" />               
    <instantiate from="root/res/values/dimens.xml"
                   to="${escapeXmlAttribute(resOut)}/values/dimens.xml" />
    <instantiate from="root/res/values/attrs.xml"
                   to="${escapeXmlAttribute(resOut)}/values/attrs.xml" />   

instantiate表示将root/res/values/arrays.xml目录下的arrays.xml复制到项目的res目录下。

自定义xml文件

strings.xml

  • 通用
<!--常用的-->
<string name="common_login">登录</string>
<string name="common_register">注册</string>
<string name="common_cancel">取消</string>
<string name="common_sure">确定</string>
<string name="common_share">分享</string>
<string name="common_setting">设置</string>
<string name="common_help">帮助</string>
<string name="common_icon">头像</string>
<string name="common_introduction">简介</string>
<string name="common_edit">编辑</string>
<string name="common_search">搜索</string>
<string name="common_email">邮箱</string>
<string name="common_phone">手机号</string>
<string name="common_password">密码</string>
<string name="common_recommend">推荐</string>
<string name="common_nickname">昵称</string>
<string name="common_user_name">用户名</string>
<string name="common_about_us">关于我们</string>
<string name="common_feedback_titlle">意见反馈</string>
<string name="common_favourite">我的收藏</string>
<string name="common_history">历史记录</string>
<string name="common_out_of_login">退出登录</string>
<string name="common_update">检查更新</string>
<string name="common_forget_password">忘记密码</string>
<string name="common_retrieve_password">找回密码</string>
<string name="common_message">我的消息</string>

  • 登录注册相关
<!--登录注册相关-->
<string name="login_error">登录失败</string>
<string name="login_register_error">注册失败</string>
<string name="login_error_reason">用户名或者密码错误</string>
<string name="login_phone_format_error">手机格式有误</string>
<string name="login_phone_not_empty">手机号不能为空</string>
<string name="login_password_not_empty">密码不能为空</string>
<string name="login_nickname_not_empty">昵称不能为空</string>
<string name="login_user_name_not_empty">用户名不能为空</string>
<string name="login_vertify_code_not_empty">验证码不能为空</string>
<string name="login_verification_code">验证码</string>
<string name="login_phone_not_available">手机号不可用</string>
<string name="login_send_code_error">发送验证码失败</string>
<string name="login_vertify_code_error">验证码有误</string>
<string name="login_send_code_btn_normal_tip">发送验证码</string>

  • 视频播放相关
<!--视频播放相关-->
<string name="video_loading">加载中…</string>
<string name="video_downloaded">离线缓存</string>
<string name="video_quality_medium">清晰</string>
<string name="video_quality_smooth">流畅</string>
<string name="video_quality_super">超清</string>
<string name="video">视频</string>
<string name="video_local">本地视频</string>
<string name="video_short">短视频</string>
<string name="video_care">关注</string>
<string name="video_">视频</string>
<string name="video_fans">粉丝</string>
<string name="video_play">次播放</string>
<string name="video_comment">评论</string>

如图所示,打开strings.xml.ftl文件,并将上述代码复制到该文件中。

61_4.png

styles.xml

  • 将默认的DarkActionBar改为NoActionBar
<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat<#if
            minApiLevel gte 11>.Light</#if><#if
            minApiLevel gte 14>.NoActionBar</#if>"><!--这里将DarkActionBar改为NoActionBar-->
        <!-- Customize your theme here. -->
<#if (buildApi gte 22) >
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
</#if>
    </style>
</resources>

  • 设置自定义的style

我们可以设置自定义的style,在这里我添加有关欢迎页的style,用来解决app打开出现的白屏问题(具体的看Android冷启动白屏问题)以及Dialogstyle。代码如下:

<resources>
...

<!--设置欢迎页的style-->
<style name="SplashStyle" parent="AppTheme">
    <item name="android:windowNoTitle">true</item>
    <item name="android:textAllCaps">false</item>
    <item name="windowActionBar">false</item>
    <item name="android:windowFullscreen">true</item>
    <item name="android:windowBackground">@color/colorAccent</item><!-- 设置欢迎页的背景,这里设置为颜色值 -->
</style>
<!--设置Dialog的style-->
<style name="MyDialogStyle" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="android:windowBackground">@android:color/transparent</item><!--背景透明-->
        <item name="android:windowFrame">@null</item><!--边框-->
        <item name="android:windowNoTitle">true</item><!--无标题-->
        <item name="android:windowIsFloating">true</item><!--是否浮现在activity之上-->
        <item name="android:windowIsTranslucent">true</item><!--半透明-->
        <item name="android:windowContentOverlay">@null</item><!--内容覆盖 -->
        <item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item><!-- 窗口样式Dialog -->
        <item name="android:backgroundDimEnabled">true</item><!--模糊-->
    </style>
</resources>

其他文件,比如arrays.xmldimens.xmlattrs.xml等可以根据自己的需求自己设置,这里不再累述。

添加默认依赖

如图在recipe.xml.ftl文件中添加默认生成的依赖:

61_5.png

常用依赖

<!--/** gson **/-->
<dependency mavenUrl="com.google.code.gson:gson:2.8.5" />
<!--/** okhttp **/-->
<dependency mavenUrl="com.squareup.okhttp3:okhttp:3.14.1" />
<!--/** glide **/-->
<dependency mavenUrl="com.github.bumptech.glide:glide:4.9.0" />
<!--/** rxjava **/-->
<dependency mavenUrl="io.reactivex.rxjava2:rxjava:2.0.1" />
<dependency mavenUrl="io.reactivex.rxjava2:rxandroid:2.0.1" />
<!--/** retrofit**/-->
<dependency mavenUrl="com.squareup.retrofit2:retrofit:2.1.0" />
<dependency mavenUrl="com.squareup.retrofit2:converter-gson:2.0.2" />
<dependency mavenUrl="com.squareup.retrofit2:adapter-rxjava:2.1.0" />

其他依赖可根据自己的开发习惯自行添加。

注意如果直接使用<dependency mavenUrl="com.google.code.gson:gson:2.8.5" />默认会生成implementation 'com.google.code.gson:gson:2.8.5';如果需要使用annotationProcessor,则要添加gradleConfiguration="annotationProcessor"属性,例如<dependency mavenUrl="xxxx" gradleConfiguration="annotationProcessor"/>

修改AndroidManifest.xml的默认生成

AndroidManifest.xml的配置文件为plugins –> android –> lib –> templates –> gradle-projects –> NewAndroidModule–>root中的shared_macros.ftl;

添加默认生成的权限

常用的权限有:

  • <uses-permission android:name="android.permission.INTERNET" /> :允许联网
  • <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> :获取sd卡的读写权限
  • <uses-permission android:name="android.permission.READ_PHONE_STATE" /> :获取手机状态
  • <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> : 获取网络状态信息
  • <uses-permission android:name="android.permission.WRITE_CALENDAR" /> :读写日历信息
  • <uses-permission android:name="android.permission.CAMERA" /> : 使用相机
  • <uses-permission android:name="android.permission.WRITE_CONTACTS" />: 允许编辑通讯录信息
  • <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />:获取精准的 (GPS) 位置
  • <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />:获取 (基于网络的) 大概位置
  • <uses-permission android:name="android.permission.RECORD_AUDIO" /> : 录音
  • <uses-permission android:name="android.permission.SEND_SMS" /> : 发送短信

如图往shared_macros.ftl文件中添加权限:

61_6.png

代码如下:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_CALENDAR" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />`
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.SEND_SMS" />

允许http请求

在Android P中默认不允许http请求,要求用https,但是图片的请求一般需要使用http,这个时候我们就可以通过往AndroidManifest.xml中添加android:usesCleartextTraffic="true"属性就可以使用http,如图所示:

61_7.png

修改new xxx的默认设置

进入 Android Studio 安装目录,依次进入 plugins –> android –> lib –> templates,如图创建了Easy_otherEasy_activities文件,用来存放自定义的生成模板。

61_8.png

生成普通的Java类模板

这里用生成FileUtil这个工具类为例。首先打开other文件夹,找到common文件夹和CustomView文件夹复制到Easy_other中,前者是通用的文件夹不需要更改,而后者是我们需要更改为FileUtil文件夹。

  • 第一步:将CustomView文件夹重命名为FileUtil
  • 第二步:编辑template.xml文件,参数说明见这里,代码如下
<?xml version="1.0"?>
<template
    format="5"
    revision="3"
    name="FileUtil"//模板名
    description="文件操作工具类">//描述

    <category value="Easy" />//定义了模板所属的分类

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

    <parameter
        id="viewClass"
        name="FileUtil"
        type="string"
        constraints="class|unique|nonempty"
        default="FileUtil"
        help="类名" />

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

</template>

  • 第三步:编辑recipe.xml.ftl文件,删除生成布局文件的代码,结果如下:
<?xml version="1.0"?>
<#import "root://activities/common/kotlin_macros.ftl" as kt>
<recipe>
    <@kt.addAllKotlinDependencies />

    <instantiate from="root/src/app_package/CustomView.${ktOrJavaExt}.ftl"
                   to="${escapeXmlAttribute(srcOut)}/${viewClass}.${ktOrJavaExt}" />

    <open file="${escapeXmlAttribute(srcOut)}/${viewClass}.${ktOrJavaExt}" />

</recipe>

  • 第四步:进入root–>src–>app_package,并编辑CustomView.java.ftl(如果使用kotlin就编辑CustomView.kt.ftl),代码如下:
package ${packageName};

import android.util.Log;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.text.DecimalFormat;

/**
 * 文件操作工具类
 */
public class FileUtil {
    /**
     * 在指定的位置创建指定的文件
     *
     * @param filePath 完整的文件路径
     * @param mkdir 是否创建相关的文件夹
     * @throws Exception
     */
    public static void mkFile(String filePath, boolean mkdir) throws Exception {
        File file = new File(filePath);
        file.getParentFile().mkdirs();
        file.createNewFile();
        file = null;
    }

    /**
     * 在指定的位置创建文件夹
     *
     * @param dirPath 文件夹路径
     * @return 若创建成功,则返回True;反之,则返回False
     */
    public static boolean mkDir(String dirPath) {
        return new File(dirPath).mkdirs();
    }

    /**
     * 删除指定的文件
     *
     * @param filePath 文件路径
     *
     * @return 若删除成功,则返回True;反之,则返回False
     *
     */
    public static boolean delFile(String filePath) {
        return new File(filePath).delete();
    }

    /**
     * 删除指定的文件夹
     *
     * @param dirPath 文件夹路径
     * @param delFile 文件夹中是否包含文件
     * @return 若删除成功,则返回True;反之,则返回False
     *
     */
    public static boolean delDir(String dirPath, boolean delFile) {
        if (delFile) {
            File file = new File(dirPath);
            if (file.isFile()) {
                return file.delete();
            } else if (file.isDirectory()) {
                if (file.listFiles().length == 0) {
                    return file.delete();
                } else {
                    int zfiles = file.listFiles().length;
                    File[] delfile = file.listFiles();
                    for (int i = 0; i < zfiles; i++) {
                        if (delfile[i].isDirectory()) {
                            delDir(delfile[i].getAbsolutePath(), true);
                        }
                        delfile[i].delete();
                    }
                    return file.delete();
                }
            } else {
                return false;
            }
        } else {
            return new File(dirPath).delete();
        }
    }

    /**
     * 复制文件/文件夹 若要进行文件夹复制,请勿将目标文件夹置于源文件夹中
     * @param source 源文件(夹)
     * @param target 目标文件(夹)
     * @param isFolder 若进行文件夹复制,则为True;反之为False
     * @throws Exception
     */
    public static void copy(String source, String target, boolean isFolder)
            throws Exception {
        if (isFolder) {
            (new File(target)).mkdirs();
            File a = new File(source);
            String[] file = a.list();
            File temp = null;
            for (int i = 0; i < file.length; i++) {
                if (source.endsWith(File.separator)) {
                    temp = new File(source + file[i]);
                } else {
                    temp = new File(source + File.separator + file[i]);
                }
                if (temp.isFile()) {
                    FileInputStream input = new FileInputStream(temp);
                    FileOutputStream output = new FileOutputStream(target + "/" + (temp.getName()).toString());
                    byte[] b = new byte[1024];
                    int len;
                    while ((len = input.read(b)) != -1) {
                        output.write(b, 0, len);
                    }
                    output.flush();
                    output.close();
                    input.close();
                }
                if (temp.isDirectory()) {
                    copy(source + "/" + file[i], target + "/" + file[i], true);
                }
            }
        } else {
            int byteread = 0;
            File oldfile = new File(source);
            if (oldfile.exists()) {
                InputStream inStream = new FileInputStream(source);
                File file = new File(target);
                file.getParentFile().mkdirs();
                file.createNewFile();
                FileOutputStream fs = new FileOutputStream(file);
                byte[] buffer = new byte[1024];
                while ((byteread = inStream.read(buffer)) != -1) {
                    fs.write(buffer, 0, byteread);
                }
                inStream.close();
                fs.close();
            }
        }
    }
 ...https://juejin.im/user/5a7cec9af265da4e7b449b50
}

最后保存,就可以直接生成。

Activity类模板

这里用CameraActivity为例,具体关于自定义Camera可以看Android平台Camera开发实践指南.

和上面创建FileUtil类似,首先打开activities文件夹,找到common文件夹和EmptyActivity文件夹复制到Easy_activities中,前者是通用的文件夹不需要更改,而后者是我们需要更改为CameraActivity文件夹。

  • 第一步:将EmptyActivity文件更改为CameraActivity文件
  • 第二步:编辑template.xml文件,参数说明见这里

代码如下:

<?xml version="1.0"?>
<template
    format="5"
    revision="5"
    name="CameraActivity"  //模板名
    minApi="9"
    minBuildApi="14"
    description="创建CameraActivity">//描述

    <category value="Easy" /> //定义了模板所属的分类
    <formfactor value="Mobile" />

   ... //只需要更改上面就行
    <!-- 128x128 thumbnails relative to template.xml -->
    <thumbs> //预览图
        <!-- default thumbnail is required -->
        <thumb>template_blank_activity.png</thumb>
    </thumbs>

    <globals file="globals.xml.ftl" /> //指定了 global 文件
    <execute file="recipe.xml.ftl" /> //指定了 recipe 文件
</template>

  • 修改recipe.xml.ftl文件,由于EmptyActivity使用默认的布局,所以我们需要修改该文件,使用我们自定义的布局

代码如下

<?xml version="1.0"?>
<#import "root://activities/common/kotlin_macros.ftl" as kt>
<recipe>
    <#include "../common/recipe_manifest.xml.ftl" />
    <@kt.addAllKotlinDependencies />
<!--需要删除的-->
<!--<#if generateLayout>-->
<!--    <#include "../common/recipe_simple.xml.ftl" />-->
<!--    <open file="${escapeXmlAttribute(resOut)}/layout/${layoutName}.xml" />-->
<!--</#if>-->

    <instantiate from="root/src/app_package/SimpleActivity.${ktOrJavaExt}.ftl"
                   to="${escapeXmlAttribute(srcOut)}/${activityClass}.${ktOrJavaExt}" />
    <open file="${escapeXmlAttribute(srcOut)}/${activityClass}.${ktOrJavaExt}" />
    <!--增加的,这里的layoutName是上面template.xml中设置布局文件的id-->
    <instantiate from="root/res/layout/sample.xml.ftl"
                   to="${escapeXmlAttribute(resOut)}/layout/${layoutName}.xml" />
    <open file="${escapeXmlAttribute(resOut)}/layout/${layoutName}.xml" />     
</recipe>

  • 第三步:在root文件下新建res目录,并在res目录下创建layout目录,在layout目录下创建sample.xml.ftl文件

代码如下:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <SurfaceView
        android:id="@+id/camera_view"
        android:layout_gravity="center"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
    <ImageView
        android:layout_marginTop="20dp"
        android:id="@+id/camera"
        android:layout_gravity="end"
        android:layout_marginEnd="10dp"
        android:src="@drawable/camera"
        android:layout_width="35dp"
        android:layout_height="35dp" />
</FrameLayout>

  • 第四步:编辑root–>src–>app_packge–>SimpleActivity.java.ftl文件

代码(部分)如下

package ${packageName};

import ${superClassFqcn};
import android.os.Bundle;
import android.hardware.Camera;
import android.view.SurfaceView;
import com.easy.generaltool.common.SimpleException;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.ImageFormat;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CaptureFailure;
import android.hardware.camera2.CaptureRequest;
...

public class ${activityClass} extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
<#if generateLayout>
        setContentView(R.layout.${layoutName});
       <#include "../../../../common/jni_code_usage.java.ftl">
<#elseif includeCppSupport!false>

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

//Camera的工具类,适用于android5以下
class Camera1Helper{

   private int numberOfCameras;

   private int faceFrontCameraId;

   private int faceBackCameraId;

   private int faceBackCameraOrientation;

   private int faceFrontCameraOrientation;

   private int state;

   private Camera camera;

   private SurfaceView surfaceView;

   private boolean isTakeVideo = false;

   private Camera1RecorderUtils utils;

    Camera1Helper(int state, SurfaceView surfaceView) {
       this.state = state;
       this.surfaceView = surfaceView;
       utils = new Camera1RecorderUtils();
       init();
   }

   private void init(){
       //有多少个摄像头
       numberOfCameras = Camera.getNumberOfCameras();
       for (int i = 0; i < numberOfCameras; ++i) {
           final Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
           Camera.getCameraInfo(i, cameraInfo);
           //后置摄像头
           if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
               faceBackCameraId = i;
               faceBackCameraOrientation = cameraInfo.orientation;
           }
           //前置摄像头
           else if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
               faceFrontCameraId = i;
               faceFrontCameraOrientation = cameraInfo.orientation;
           }
       }
   }

   public void change(){
       if (isTakeVideo)return;
       if (state == CameraHelper.CAMERA_BACK)
           state = CameraHelper.CAMERA_FRONT;
       else
           state = CameraHelper.CAMERA_BACK;
       camera.stopPreview();
       camera.release();
       openCamera();
   }

   public void openCamera(){
       camera = null;
       if (state == CameraHelper.CAMERA_BACK)
           camera = Camera.open(faceBackCameraId);
       else if (state == CameraHelper.CAMERA_FRONT)
           camera = Camera.open(faceFrontCameraId);
       else{
           throw new SimpleException("can not find what you need camera");
       }
       try {
           camera.setPreviewDisplay(surfaceView.getHolder());
           camera.setDisplayOrientation(90);
           Camera.Parameters mParameters = camera.getParameters();
           mParameters.setPictureSize(720, 480);//设置图片尺寸
           mParameters.setPreviewSize(720, 480);//设置预览尺寸
           camera.setParameters(mParameters);
       } catch (IOException e) {
           e.printStackTrace();
       }
       camera.startPreview();
   }

   public void takePhoto(CameraHelper.OnTakePictureFinishCallback callback) {
       if (camera!=null)
           camera.takePicture(null, null, (data, camera) -> {
               callback.finish(data);
               camera.startPreview();
           });
   }

   public void startVideoRecord(String path, String name) {
       isTakeVideo = true;
       utils.create(surfaceView,Camera1RecorderUtils.WH_720X480,camera);
       utils.startRecord(path,name);
   }

   public void stopVideoRecord() {
       utils.stopRecord();
       isTakeVideo = false;
   }

   public void closeCamera(){
       if (camera==null)return;
       camera.stopPreview();
       camera.release();
       utils.destroy();
   }
}
...
}

最后保存,重启android studio即可通过new --> Easy --> CameraActivity生成指定的代码

template.xml的参数说明

来自大幅提高Android开发效率之Android项目模板化

1、 template 标签,整个 xml 的根节点,其中 name属性为模板名称,description属性为模板的描述。
2、 category标签,定义了模板所属的分类,即图四中的分类列表中的分类,分类名一样的模板会被归纳到同一目录下。
3、 parameter 标签,定义了模板输入弹窗中的输入参数,每个 parameter 为一行。其中:

 *  id 属性为参数唯一标识,我们可以在代码中通过 id来使用该参数。
 *  name 属性为参数名称,显示在输入控件的前面或后面。
 *  type属性为参数类型,根据该属性和constraints属性的值综合比较后参数会被渲染成不同的输入形式,比如 string 类型会显示输入框,而 boolean类型会显示一个选择框。
 *  constraints属性为输入约束,常见的有class,代表类名;layout代表布局名;package 代表包路径; unique则是不能与现有的重复;nonemptye表示不能为空。
 *  suggest 和 default标签,前者是建议名称,后者是默认名称,前者优先级高于后者。
 *  help属性是参数输入提示,当该参数获取焦点后,对应的帮助信息会显示在对话框上。

4、 thumbs标签定义了该目标的缩略图,这也就是template_blank_activity.png文件的作用了。
5、 globals标签指定了 global 文件,用 global 标签定义了一系列的全局参数(这里的全局是指可以在其他模板文件中使用它们)供具体的模板文件使用,id为唯一标识,type为类型,value为参数值。
6、 execute标签,跟字面上的意思一样,执行 recipe.xml.ftl文件的内容,将模板文件生成具体的可用文件。

推荐

如果想看Android Studio Live Templates快捷键常用插件,可以看:

文章永久链接:https://tech.souyunku.com/28190

未经允许不得转载:搜云库技术团队 » 自定义Android 项目模板,不需要记忆什么快捷键和Live Templates就能提高Android开发效率

JetBrains 全家桶,激活、破解、教程

提供 JetBrains 全家桶激活码、注册码、破解补丁下载及详细激活教程,支持 IntelliJ IDEA、PyCharm、WebStorm 等工具的永久激活。无论是破解教程,还是最新激活码,均可免费获得,帮助开发者解决常见激活问题,确保轻松破解并快速使用 JetBrains 软件。获取免费的破解补丁和激活码,快速解决激活难题,全面覆盖 2024/2025 版本!

联系我们联系我们