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

这篇博客为大家介绍Android自定义相机,并且实现倒计时拍照功能。
首先自定义拍照会用到SurfaceView控件显示照片的预览区域,以下是布局文件:
activity_main.xml

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="match_parent" > 

  <SurfaceView
    android:id="@+id/surface_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent" /> 

  <RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" > 

    <ImageView
      android:id="@+id/start"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_centerHorizontal="true"
      android:layout_alignParentBottom="true"
      android:layout_marginBottom="10dp"
      android:src="@drawable/capture"/> 

    <TextView
      android:id="@+id/count_down"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:layout_gravity="center"
      android:gravity="center"
      android:textSize="80sp"/>
  </RelativeLayout>
</FrameLayout>

MainActivity.java

package com.jackie.timercamera; 

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.hardware.Camera;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView; 

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException; 

public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback,
    View.OnClickListener, Camera.PictureCallback {
  private SurfaceView mSurfaceView;
  private ImageView mIvStart;
  private TextView mTvCountDown; 

  private SurfaceHolder mHolder; 

  private Camera mCamera; 

  private Handler mHandler = new Handler(); 

  private int mCurrentTimer = 10; 

  private boolean mIsSurfaceCreated = false;
  private boolean mIsTimerRunning = false; 

  private static final int CAMERA_ID = 0; //后置摄像头
//  private static final int CAMERA_ID = 1; //前置摄像头
  private static final String TAG = MainActivity.class.getSimpleName(); 

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main); 

    initView();
    initEvent();
  } 

  @Override
  protected void onPause() {
    super.onPause(); 

    stopPreview();
  } 

  private void initView() {
    mSurfaceView = (SurfaceView) findViewById(R.id.surface_view);
    mIvStart = (ImageView) findViewById(R.id.start);
    mTvCountDown = (TextView) findViewById(R.id.count_down);
  } 

  private void initEvent() {
    mHolder = mSurfaceView.getHolder();
    mHolder.addCallback(this); 

    mIvStart.setOnClickListener(this);
  } 

  @Override
  public void surfaceCreated(SurfaceHolder holder) {
    mIsSurfaceCreated = true;
  } 

  @Override
  public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    startPreview();
  } 

  @Override
  public void surfaceDestroyed(SurfaceHolder holder) {
    mIsSurfaceCreated = false;
  } 

  private void startPreview() {
    if (mCamera != null || !mIsSurfaceCreated) {
      Log.d(TAG, "startPreview will return");
      return;
    } 

    mCamera = Camera.open(CAMERA_ID); 

    Camera.Parameters parameters = mCamera.getParameters();
    int width = getResources().getDisplayMetrics().widthPixels;
    int height = getResources().getDisplayMetrics().heightPixels;
    Camera.Size size = getBestPreviewSize(width, height, parameters);
    if (size != null) {
      //设置预览分辨率
      parameters.setPreviewSize(size.width, size.height);
      //设置保存图片的大小
      parameters.setPictureSize(size.width, size.height);
    } 

    //自动对焦
    parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
    parameters.setPreviewFrameRate(20); 

    //设置相机预览方向
    mCamera.setDisplayOrientation(90); 

    mCamera.setParameters(parameters); 

    try {
      mCamera.setPreviewDisplay(mHolder);
    } catch (Exception e) {
      Log.d(TAG, e.getMessage());
    } 

    mCamera.startPreview();
  } 

  private void stopPreview() {
    //释放Camera对象
    if (mCamera != null) {
      try {
        mCamera.setPreviewDisplay(null);
        mCamera.stopPreview();
        mCamera.release();
        mCamera = null;
      } catch (Exception e) {
        Log.e(TAG, e.getMessage());
      }
    }
  } 

  private Camera.Size getBestPreviewSize(int width, int height,
                      Camera.Parameters parameters) {
    Camera.Size result = null; 

    for (Camera.Size size : parameters.getSupportedPreviewSizes()) {
      if (size.width <= width && size.height <= height) {
        if (result == null) {
          result = size;
        } else {
          int resultArea = result.width * result.height;
          int newArea = size.width * size.height; 

          if (newArea > resultArea) {
            result = size;
          }
        }
      }
    } 

    return result;
  } 

  @Override
  public void onClick(View v) {
    switch (v.getId()) {
      case R.id.start:
        if (!mIsTimerRunning) {
          mIsTimerRunning = true;
          mHandler.post(timerRunnable);
        }
        break;
    }
  } 

  private Runnable timerRunnable = new Runnable() {
    @Override
    public void run() {
      if (mCurrentTimer > 0) {
        mTvCountDown.setText(mCurrentTimer + ""); 

        mCurrentTimer--;
        mHandler.postDelayed(timerRunnable, 1000);
      } else {
        mTvCountDown.setText(""); 

        mCamera.takePicture(null, null, null, MainActivity.this);
        playSound(); 

        mIsTimerRunning = false;
        mCurrentTimer = 10;
      }
    }
  }; 

  @Override
  public void onPictureTaken(byte[] data, Camera camera) {
    try {
      FileOutputStream fos = new FileOutputStream(new File
          (Environment.getExternalStorageDirectory() + File.separator +
              System.currentTimeMillis() + ".png")); 

      //旋转角度,保证保存的图片方向是对的
      Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
      Matrix matrix = new Matrix();
      matrix.setRotate(90);
      bitmap = Bitmap.createBitmap(bitmap, 0, 0,
          bitmap.getWidth(), bitmap.getHeight(), matrix, true);
      bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
      fos.flush();
      fos.close();
    } catch (FileNotFoundException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    } 

    mCamera.startPreview();
  } 

  /**
   *  播放系统拍照声音
   */
  public void playSound() {
    MediaPlayer mediaPlayer = null;
    AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
    int volume = audioManager.getStreamVolume( AudioManager.STREAM_NOTIFICATION); 

    if (volume != 0) {
      if (mediaPlayer == null)
        mediaPlayer = MediaPlayer.create(this,
            Uri.parse("file:///system/media/audio/ui/camera_click.ogg"));
      if (mediaPlayer != null) {
        mediaPlayer.start();
      }
    }
  }
}

有两点需要注意:对于Camera来说,默认是横屏的,所以预览的时候和图片保存的时候都是横屏的,需要调整角度。

设置相机预览方法:

//设置相机预览方向
mCamera.setDisplayOrientation(90);

保存图片的时候调整角度:

效果图如下:

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

(0)

相关推荐

  • Android 用 camera2 API 自定义相机

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

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

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

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

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

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

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

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

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

  • Android自定义照相机详解

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

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

    自定义拍照会用到SurfaceView控件显示照片的预览区域,以下是布局文件: 两个TextView是用来显示提示信息和倒计时的秒数的 相关教程:Android开发从相机或相册获取图片裁剪 Android启动相机拍照并返回图片 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools&qu

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

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

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

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

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

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

随机推荐