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


相关推荐: Laravel如何使用查询构建器?(Query Builder高级用法)  linux写shell需要注意的问题(必看)  个人摄影网站制作流程,摄影爱好者都去什么网站?  ,网页ppt怎么弄成自己的ppt?  悟空识字如何进行跟读录音_悟空识字开启麦克风权限与录音  EditPlus中的正则表达式 实战(1)  制作旅游网站html,怎样注册旅游网站?  如何在橙子建站中快速调整背景颜色?  如何用ChatGPT准备面试 模拟面试问答与职场话术练习教程  Laravel的路由模型绑定怎么用_Laravel Route Model Binding简化控制器逻辑  Laravel怎么发送邮件_Laravel Mail类SMTP配置教程  如何快速生成高效建站系统源代码?  如何在Windows环境下新建FTP站点并设置权限?  网站建设保证美观性,需要考虑的几点问题!  b2c电商网站制作流程,b2c水平综合的电商平台?  Win11怎么恢复误删照片_Win11数据恢复工具使用【推荐】  javascript中数组(Array)对象和字符串(String)对象的常用方法总结  Android仿QQ列表左滑删除操作  如何在阿里云ECS服务器部署织梦CMS网站?  Laravel如何配置和使用缓存?(Redis代码示例)  Laravel如何使用Contracts(契约)进行编程_Laravel契约接口与依赖反转  Laravel Asset编译怎么配置_Laravel Vite前端构建工具使用  如何用5美元大硬盘VPS安全高效搭建个人网站?  HTML透明颜色代码怎么让下拉菜单透明_下拉菜单透明背景指南【技巧】  如何正确选择百度移动适配建站域名?  Laravel Seeder怎么填充数据_Laravel数据库填充器的使用方法与技巧  如何快速重置建站主机并恢复默认配置?  Laravel如何处理异常和错误?(Handler示例)  Laravel如何生成PDF或Excel文件_Laravel文档导出工具与使用教程  千库网官网入口推荐 千库网设计创意平台入口  开心动漫网站制作软件下载,十分开心动画为何停播?  Win11怎么修改DNS服务器 Win11设置DNS加速网络【指南】  手机怎么制作网站教程步骤,手机怎么做自己的网页链接?  如何自定义建站之星模板颜色并下载新样式?  google浏览器怎么清理缓存_谷歌浏览器清除缓存加速详细步骤  微信推文制作网站有哪些,怎么做微信推文,急?  如何用AI一键生成爆款短视频文案?小红书AI文案写作指令【教程】  网页设计与网站制作内容,怎样注册网站?  JS实现鼠标移上去显示图片或微信二维码  python中快速进行多个字符替换的方法小结  Thinkphp 中 distinct 的用法解析  标准网站视频模板制作软件,现在有哪个网站的视频编辑素材最齐全的,背景音乐、音效等?  文字头像制作网站推荐软件,醒图能自动配文字吗?  Laravel如何使用Passport实现OAuth2?(完整配置步骤)  智能起名网站制作软件有哪些,制作logo的软件?  如何在阿里云香港服务器快速搭建网站?  Laravel队列由Redis驱动怎么配置_Laravel Redis队列使用教程  悟空识字怎么关闭自动续费_悟空识字取消会员自动扣费步骤  黑客入侵网站服务器的常见手法有哪些?  南京网站制作费用,南京远驱官方网站?