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

发布时间 - 2026-01-10 22:42:42    点击率:

这篇博客为大家介绍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);

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

效果图如下:

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


# Android相机定时拍照  # Android定时拍照  # Android相机拍照  # Android自定义相机聚焦和显示框  # Android自定义相机Camera实现手动对焦的方法示例  # android 7自定义相机预览及拍照功能  # Android开源库自定义相机模块  # Android 自定义相机及分析源码  # Android 用 camera2 API 自定义相机  # Android中关于自定义相机预览界面拉伸问题  # Android自定义相机实现自动对焦和手动对焦  # Android自定义相机界面的实现代码  # Android自定义相机、预览区域裁剪  # 自定义  # 都是  # 这篇  # 需要注意  # 大家多多  # 倒计时  # 自动对焦  # 有两点  # 博客  # util  # AppCompatActivity  # app  # support  # Log  # widget  # io  # File  # view  # SurfaceHolder 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: 网站制作壁纸教程视频,电脑壁纸网站?  Win11怎么更改系统语言为中文_Windows11安装语言包并设为显示语言  如何在宝塔面板中修改默认建站目录?  Laravel怎么自定义错误页面_Laravel修改404和500页面模板  Laravel怎么做数据加密_Laravel内置Crypt门面的加密与解密功能  如何快速搭建高效WAP手机网站吸引移动用户?  Laravel如何实现本地化和多语言支持?(i18n教程)  使用spring连接及操作mongodb3.0实例  如何获取免费开源的自助建站系统源码?  西安专业网站制作公司有哪些,陕西省建行官方网站?  Laravel怎么在Blade中安全地输出原始HTML内容  非常酷的网站设计制作软件,酷培ai教育官方网站?  🚀拖拽式CMS建站能否实现高效与个性化并存?  高配服务器限时抢购:企业级配置与回收服务一站式优惠方案  如何在VPS电脑上快速搭建网站?  打开php文件提示内存不足_怎么调整php内存限制【解决方案】  php在windows下怎么调试_phpwindows环境调试操作说明【操作】  Laravel怎么实现搜索功能_Laravel使用Eloquent实现模糊查询与多条件搜索【实例】  七夕网站制作视频,七夕大促活动怎么报名?  如何用花生壳三步快速搭建专属网站?  东莞市网站制作公司有哪些,东莞找工作用什么网站好?  UC浏览器如何切换小说阅读源_UC浏览器阅读源切换【方法】  JS弹性运动实现方法分析  小米17系列还有一款新机?主打6.9英寸大直屏和旗舰级影像  如何快速重置建站主机并恢复默认配置?  Laravel Octane如何提升性能_使用Laravel Octane加速你的应用  如何解决hover在ie6中的兼容性问题  php静态变量怎么调试_php静态变量作用域调试技巧【解答】  Android利用动画实现背景逐渐变暗  Laravel怎么使用Intervention Image库处理图片上传和缩放  jQuery中的100个技巧汇总  详解jQuery中基本的动画方法  如何在HTML表单中获取用户输入并用JavaScript动态控制复利计算循环  PHP怎么接收前端传的文件路径_处理文件路径参数接收方法【汇总】  Laravel怎么清理缓存_Laravel optimize clear命令详解  laravel怎么通过契约(Contracts)编程_laravel契约(Contracts)编程方法  长沙做网站要多少钱,长沙国安网络怎么样?  bootstrap日历插件datetimepicker使用方法  如何在腾讯云服务器上快速搭建个人网站?  如何在 Python 中将列表项按字母顺序编号(a.、b.、c. …)  javascript中对象的定义、使用以及对象和原型链操作小结  html5怎么画眼睛_HT5用Canvas或SVG画眼球瞳孔加JS控制动态【绘制】  Python并发异常传播_错误处理解析【教程】  简历在线制作网站免费版,如何创建个人简历?  Laravel如何处理CORS跨域请求?(配置示例)  Android自定义控件实现温度旋转按钮效果  如何快速搭建个人网站并优化SEO?  Laravel怎么处理异常_Laravel自定义异常处理与错误页面教程  深圳防火门网站制作公司,深圳中天明防火门怎么编码?  大连企业网站制作公司,大连2025企业社保缴费网上缴费流程?