Android自定义照相机倒计时拍照

自定义拍照会用到SurfaceView控件显示照片的预览区域,以下是布局文件:

两个TextView是用来显示提示信息和倒计时的秒数的

相关教程:Android开发从相机或相册获取图片裁剪

Android启动相机拍照并返回图片

<RelativeLayout 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="#266194"
 android:orientation="vertical"
 tools:context=".TestActivity" >
 <SurfaceView
 android:id="@+id/surfaceView"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:layout_centerInParent="true" />
 <LinearLayout
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_centerInParent="true"
 android:orientation="vertical" >
 <TextView
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:text="请调整位置到此区域"
 android:textColor="#ff0000"
 android:textSize="32sp" />
 <TextView
 android:id="@+id/tv_time"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:paddingTop="10dp"
 android:gravity="center_horizontal"
 android:textColor="#266194"
 android:textSize="32sp" />
 </LinearLayout>
</RelativeLayout> 

接下来是mainActivity中的具体实现以及详细注释:

package com.dhsr.pujiejia.ui;
import java.io.File;
import java.io.FileOutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.hardware.Camera.CameraInfo;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.Window;
import android.view.WindowManager;
import android.widget.TextView;
import com.example.pujiejiaapp.R;
@SuppressLint({ "NewApi", "SdCardPath" })
public class CameraActivity extends Activity implements Runnable {
 // 预览图片范围
 private SurfaceView surfaceView;
 private TextView tv_time;
 // 倒计时拍摄
 private int cameratime = 4;
 private Camera camera;
 private boolean preview = false;
 // 文件名字
 private String filename;
 // 文件名字的带的时间戳
 private String timeString;
 // 格式化时间
 private SimpleDateFormat dateFormat;
 // 日期对象
 private Date date;
 // 控制线程
 boolean stopThread = false;
 private File file;
 String photo;
 private Handler mHandler = new Handler() {
 public void handleMessage(android.os.Message msg) {
 int what = msg.what;
 switch (what) {
 case 222:
 tv_time.setText("" + cameratime);
 if ("0".equals(tv_time.getText().toString())) {
  tv_time.setText("拍摄成功!");
  takePhoto();
 }
 break;
 }
 };
 };
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 // TODO Auto-generated method stub
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_test);
 CameraActivity.this.setFinishOnTouchOutside(false);
 // 初始化数据
 findView();
 surfaceView.getHolder().addCallback(new SufaceListener());
 /* 下面设置Surface不维护自己的缓冲区,而是等待屏幕的渲染引擎将内容推送到用户面前 */
 surfaceView.getHolder()
 .setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
 surfaceView.getHolder().setFixedSize(200, 200); // 设置分辨率
 }
 @Override
 protected void onStart() {
 // TODO Auto-generated method stub
 super.onStart();
 // 开启线程
 new Thread(this).start();
 }
 private final class SufaceListener implements SurfaceHolder.Callback {
 /**
 * surface改变
 */
 @Override
 public void surfaceChanged(SurfaceHolder holder, int format, int width,
 int height) {
 }
 /**
 * surface创建
 */
 @Override
 public void surfaceCreated(SurfaceHolder holder) {
 try {
 for (int i = 0; i < Camera.getNumberOfCameras(); i++) {
  CameraInfo info = new CameraInfo();
  Camera.getCameraInfo(i, info);
  // 调用系统的前置摄像头
  if (info.facing == CameraInfo.CAMERA_FACING_FRONT) {
  camera = Camera.open(i);
  }
 }
 Camera.Parameters parameters = camera.getParameters();
 /* 每秒从摄像头捕获5帧画面, */
 parameters.setPreviewFrameRate(5);
 /* 设置照片的输出格式:jpg */
 parameters.setPictureFormat(PixelFormat.JPEG);
 /* 照片质量 */
 parameters.set("jpeg-quality", 85);
 WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
 camera.setParameters(parameters);
 camera.setPreviewDisplay(surfaceView.getHolder());// 通过SurfaceView显示取景画面
 camera.startPreview();
 preview = true;
 } catch (Exception e) {
 }
 }
 /**
 * surface销毁
 */
 @Override
 public void surfaceDestroyed(SurfaceHolder holder) {
 if (camera != null) {
 if (preview)
  camera.stopPreview();
 camera.release();
 camera = null;
 }
 }
 }
 /**
 * 拍摄照片
 */
 private void takePhoto() {
 // 执行拍照效果
 camera.takePicture(null, null, new Camera.PictureCallback() {
 @Override
 public void onPictureTaken(byte[] data, Camera camera) {
 try {
  Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0,
  data.length);
  timeString = formatDate();
  //保存到data/data目录自定义文件夹下
  filename = "/data/data/com.example.pujiejiaapp/images/"
  + timeString + ".jpg";
  File file = new File(filename);
  boolean createNewFile = file.createNewFile()
  System.out.println("创建文件夹成功没有" + createNewFile);
  System.out.println(file);
  FileOutputStream outStream = new FileOutputStream(file);
  bitmap.compress(Bitmap.CompressFormat.JPEG, 60, outStream);
  outStream.flush();
  outStream.close();
  // 重新浏览
  camera.stopPreview();
  camera.startPreview();
  preview = true;
 } catch (Exception e) {
  e.printStackTrace();
 } finally {
 }
 }
 });
 }
 @Override
 public void run() {
 while (!stopThread) {
 try {
 //按秒数倒计时
 Thread.sleep(1000);
 } catch (InterruptedException e) {
 // TODO Auto-generated catch block
 e.printStackTrace();
 }
 cameratime--;
 mHandler.sendEmptyMessage(222);
 if (cameratime <= 0) {
 break;
 }
 }
 }
 // 初始化数据
 private void findView() {
 surfaceView = (SurfaceView) this.findViewById(R.id.surfaceView);
 tv_time = (TextView) findViewById(R.id.tv_time);
 }
 // 格式化系统的时间
 public String formatDate() {
 date = new Date(System.currentTimeMillis());
 // 日期格式
 dateFormat = new SimpleDateFormat("'IMG'_yyyyMMddHHmmss");
 return dateFormat.format(date);
 }
 @Override
 protected void onDestroy() {
 // TODO Auto-generated method stub
 // 线程已关闭
 super.onDestroy();
 stopThread = true;
 }
} 

核心代码详解:

1.创建SurfaceView时,surfaceCreated()方法中

for (int i = 0; i < Camera.getNumberOfCameras(); i++) {
  CameraInfo info = new CameraInfo();
  Camera.getCameraInfo(i, info);
  // 调用系统的前置摄像头
  if (info.facing == CameraInfo.CAMERA_FACING_FRONT) {
  camera = Camera.open(i);
  }
 }

此部分代码为打开相机时默认打开前置摄像头CameraInfo.CAMERA_FACING_BACK为默认打开后置摄像头,CameraInfo.CAMERA_FACING_FRONT前置摄像头

2.照片拍摄takePhoto()方法中:

Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0,
  data.length);
  timeString = formatDate();
  filename = "/data/data/com.example.pujiejiaapp/images/"
  + timeString + ".jpg";
  photo = timeString + ".jpg";
  File file = new File(filename);
  boolean createNewFile = file.createNewFile();
  FileOutputStream outStream = new FileOutputStream(file);
  bitmap.compress(Bitmap.CompressFormat.JPEG, 60, outStream);

此部分代码为将拍摄到的图片保存为以bitmap格式保存在指定的目录下

3.开子线程用于倒计时拍摄

public void run() {
 while (!stopThread) {
 try {
 Thread.sleep(1000);
 } catch (InterruptedException e) {
 // TODO Auto-generated catch block
 e.printStackTrace();
 }
 cameratime--;
 mHandler.sendEmptyMessage(222);
 if (cameratime <= 0) {
 break;
 }
 }
 }

希望大家理解核心代码的详细注释,欢迎提供意见,希望能给大家带来帮助,谢谢!

(0)

相关推荐

  • Android自定义照相机详解

    几乎每个APP都会用的相机功能,下面小编把内容整理分享到我们平台,供大家参考,感兴趣的朋友一起学习吧! 启动相机的两种方式 1.直接启动系统相机 <code class="hljs avrasm"> Intent intent = new Intent(); intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE); startActivity(intent);</code> 或者指定返回图片的名称mCurrentPho

  • Android 用 camera2 API 自定义相机

    前言 笔者因为项目需要自定义相机,所以了解了一下 Android 关于 camera 这块的 API.Android SDK 21(LOLLIPOP) 开始已经弃用了之前的 Camera 类,提供了 camera2 相关 API,目前网上关于 camera2 API 介绍的资料比较少,笔者搜集网上资料,结合自己的实践,在这里做一个总结. 流程 因为 camera2 提供的接口比较多,虽然很灵活,但是也增加了使用的复杂度.首先来大致了解一下调用 camera2 的流程,方便我们理清思路. 要显示相

  • Android自定义相机实现自动对焦和手动对焦

    Android自定义相机实现自动对焦和手动对焦: 不调用系统相机,因为不同的机器打开相机呈现的界面不统一也不能满足需求. 所以为了让程序在不同的机器上呈现出统一的界面,并且可以根据需求进行布局,做了此demo. 程序实现代码如下: import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.la

  • Android自定义组件获取本地图片和相机拍照图片

    iOS中有封装好的选择图片后长按出现动画删除效果,效果如下 而Android找了很久都没有找到有这样效果的第三方组件,最后懒得找了还是自己实现这效果吧 选择图片后还可对图片进行剪裁 当然,代码中还有很多不完善的地方,我接下来会继续完善这个组件的 已经上传到开源社区,欢迎大家来Star啊~ Demo源码:传送门 设计中的碰到的一些问题和解决思路 1.如何让加号图片显示在GridView最后面 首先在调用GridAdapter构造方法时就加载加号图片 /** * 图片适配器 * @param con

  • Android 自定义相机及分析源码

    Android 自定义相机及分析源码 使用Android 系统相机的方法: 要想让应用有相机的action,咱们就必须在清单文件中做一些声明,好让系统知道,如下 <intent-filter> <action android:name="android.intent.action.IMAGE_CAPTURE" /> <category android:name="android.intent.category.DEFAULT" />

  • Android实用控件自定义逼真相机光圈View

    最近手机界开始流行双摄像头,大光圈功能也应用而生.所谓大光圈功能就是能够对照片进行后期重新对焦,其实现的原理主要是对拍照期间获取的深度图片与对焦无穷远的图像通过算法来实现重新对焦的效果. 在某双摄手机的大光圈操作界面有个光圈的操作图标,能够模拟光圈调节时的真实效果,感觉还不错,于是想着实现该效果.现在把我的实现方法贡献给大家,万一你们公司也要做双摄手机呢?( ̄┰ ̄*) 首先,百度一下光圈图片,观察观察,就可以发现其关键在于计算不同的光圈值时各个光圈叶片的位置.为了计算简便,我以六个直边叶片的光圈

  • Android中关于自定义相机预览界面拉伸问题

    关于自定义相机预览界面拉伸问题 1.导致主要变形的原因是Camera预览界面旋转的角度和摄像头挂载的角度不同导致的 2.我们的Activity设置的方向是竖屏,这是手机的自然方向 所以宽比高短 3.角度:所谓屏幕和摄像头的角度,指的是相对于自然方向旋转过的角度,根据旋转角度即可获知当前的方向 4.假如说:手机是竖屏的情况下, 自然角度为0,但是Camera逆时针旋转90度,那咱们设置顺时针旋转90度,就正常 .手机是横屏的情况下Camera返回为0度 ,如果设置顺时针旋转90度,就回旋转 怎么设

  • Android自定义照相机Camera出现黑屏的解决方法

    本文实例讲述了Android自定义照相机Camera出现黑屏的解决方法.分享给大家供大家参考,具体如下: 对于一些手机,像HTC,当自定义Camera时,调用Camera.Parameters的 parameters.setPreviewSize(width, height)方法时,如果width和height为奇数情况下,则会出现黑屏现象,解决办法可参考SDK提供的ApiDemos中关于Camera的 例子: List<Size> sizes = parameters.getSupporte

  • Android自定义相机界面的实现代码

    我们先实现拍照按钮的圆形效果哈,Android开发中,当然可以找美工人员设计图片,然后直接拿进来,不过我们可以自己写代码实现这个效果哈,最常用的的是用layout-list实现图片的叠加,我们这个layout命名为btn_take_photo.xml,这是一个自定义的drawable文件,所以按照规范,我们要将它放在drawable文件夹里. 注意:drawable文件夹一般是来放自定义的drawable文件的,可以将它看成自己写的背景样式等等哦 解释代码: layer-list里面放3个ite

  • Android自定义相机实现定时拍照功能

    这篇博客为大家介绍Android自定义相机,并且实现倒计时拍照功能. 首先自定义拍照会用到SurfaceView控件显示照片的预览区域,以下是布局文件: activity_main.xml <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="m

随机推荐