热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

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

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

这篇博客为大家介绍Android自定义相机,并且实现倒计时拍照功能。

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

activity_main.xml

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 &#61; 1; //前置摄像头private static final String TAG &#61; MainActivity.class.getSimpleName();&#64;Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initView();initEvent();}&#64;Overrideprotected void onPause() {super.onPause();stopPreview();}private void initView() {mSurfaceView &#61; (SurfaceView) findViewById(R.id.surface_view);mIvStart &#61; (ImageView) findViewById(R.id.start);mTvCountDown &#61; (TextView) findViewById(R.id.count_down);}private void initEvent() {mHolder &#61; mSurfaceView.getHolder();mHolder.addCallback(this);mIvStart.setOnClickListener(this);}&#64;Overridepublic void surfaceCreated(SurfaceHolder holder) {mIsSurfaceCreated &#61; true;}&#64;Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {startPreview();}&#64;Overridepublic void surfaceDestroyed(SurfaceHolder holder) {mIsSurfaceCreated &#61; false;}private void startPreview() {if (mCamera !&#61; null || !mIsSurfaceCreated) {Log.d(TAG, "startPreview will return");return;}mCamera &#61; Camera.open(CAMERA_ID);Camera.Parameters parameters &#61; mCamera.getParameters();int width &#61; getResources().getDisplayMetrics().widthPixels;int height &#61; getResources().getDisplayMetrics().heightPixels;Camera.Size size &#61; getBestPreviewSize(width, height, parameters);if (size !&#61; 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 !&#61; null) {try {mCamera.setPreviewDisplay(null);mCamera.stopPreview();mCamera.release();mCamera &#61; null;} catch (Exception e) {Log.e(TAG, e.getMessage());}}}private Camera.Size getBestPreviewSize(int width, int height,Camera.Parameters parameters) {Camera.Size result &#61; null;for (Camera.Size size : parameters.getSupportedPreviewSizes()) {if (size.width <&#61; width && size.height <&#61; height) {if (result &#61;&#61; null) {result &#61; size;} else {int resultArea &#61; result.width * result.height;int newArea &#61; size.width * size.height;if (newArea > resultArea) {result &#61; size;}}}}return result;}&#64;Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.start:if (!mIsTimerRunning) {mIsTimerRunning &#61; true;mHandler.post(timerRunnable);}break;}}private Runnable timerRunnable &#61; new Runnable() {&#64;Overridepublic void run() {if (mCurrentTimer > 0) {mTvCountDown.setText(mCurrentTimer &#43; "");mCurrentTimer--;mHandler.postDelayed(timerRunnable, 1000);} else {mTvCountDown.setText("");mCamera.takePicture(null, null, null, MainActivity.this);playSound();mIsTimerRunning &#61; false;mCurrentTimer &#61; 10;}}};&#64;Overridepublic void onPictureTaken(byte[] data, Camera camera) {try {FileOutputStream fos &#61; new FileOutputStream(new File(Environment.getExternalStorageDirectory() &#43; File.separator &#43;System.currentTimeMillis() &#43; ".png"));//旋转角度&#xff0c;保证保存的图片方向是对的Bitmap bitmap &#61; BitmapFactory.decodeByteArray(data, 0, data.length);Matrix matrix &#61; new Matrix();matrix.setRotate(90);bitmap &#61; 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 &#61; null;AudioManager audioManager &#61; (AudioManager) getSystemService(Context.AUDIO_SERVICE);int volume &#61; audioManager.getStreamVolume( AudioManager.STREAM_NOTIFICATION);if (volume !&#61; 0) {if (mediaPlayer &#61;&#61; null)mediaPlayer &#61; MediaPlayer.create(this, Uri.parse("file:///system/media/audio/ui/camera_click.ogg"));if (mediaPlayer !&#61; null) {mediaPlayer.start();}}}
}

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

设置相机预览方法&#xff1a;

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

保存图片的时候调整角度&#xff1a;


效果图如下&#xff1a;






推荐阅读
  • 本文探讨了资源访问的学习路径与方法,旨在帮助学习者更高效地获取和利用各类资源。通过分析不同资源的特点和应用场景,提出了多种实用的学习策略和技术手段,为学习者提供了系统的指导和建议。 ... [详细]
  • 掌握Android UI设计:利用ZoomControls实现图片缩放功能
    本文介绍了如何在Android应用中通过使用ZoomControls组件来实现图片的缩放功能。ZoomControls提供了一种简单且直观的方式,让用户可以通过点击放大和缩小按钮来调整图片的显示大小。文章详细讲解了ZoomControls的基本用法、布局设置以及与ImageView的结合使用方法,适合初学者快速掌握Android UI设计中的这一重要功能。 ... [详细]
  • 技术分享:深入解析GestureDetector手势识别机制
    技术分享:深入解析GestureDetector手势识别机制 ... [详细]
  • Android 图像色彩处理技术详解
    本文详细探讨了 Android 平台上的图像色彩处理技术,重点介绍了如何通过模仿美图秀秀的交互方式,利用 SeekBar 实现对图片颜色的精细调整。文章展示了具体的布局设计和代码实现,帮助开发者更好地理解和应用图像处理技术。 ... [详细]
  • 本文探讨了在Android应用中实现动态滚动文本显示控件的优化方法。通过详细分析焦点管理机制,特别是通过设置返回值为`true`来确保焦点不会被其他控件抢占,从而提升滚动文本的流畅性和用户体验。具体实现中,对`MarqueeText.java`进行了代码层面的优化,增强了控件的稳定性和兼容性。 ... [详细]
  • 单片微机原理P3:80C51外部拓展系统
      外部拓展其实是个相对来说很好玩的章节,可以真正开始用单片机写程序了,比较重要的是外部存储器拓展,81C55拓展,矩阵键盘,动态显示,DAC和ADC。0.IO接口电路概念与存 ... [详细]
  • 在对WordPress Duplicator插件0.4.4版本的安全评估中,发现其存在跨站脚本(XSS)攻击漏洞。此漏洞可能被利用进行恶意操作,建议用户及时更新至最新版本以确保系统安全。测试方法仅限于安全研究和教学目的,使用时需自行承担风险。漏洞编号:HTB23162。 ... [详细]
  • 本文介绍了一种自定义的Android圆形进度条视图,支持在进度条上显示数字,并在圆心位置展示文字内容。通过自定义绘图和组件组合的方式实现,详细展示了自定义View的开发流程和关键技术点。示例代码和效果展示将在文章末尾提供。 ... [详细]
  • Presto:高效即席查询引擎的深度解析与应用
    本文深入解析了Presto这一高效的即席查询引擎,详细探讨了其架构设计及其优缺点。Presto通过内存到内存的数据处理方式,显著提升了查询性能,相比传统的MapReduce查询,不仅减少了数据传输的延迟,还提高了查询的准确性和效率。然而,Presto在大规模数据处理和容错机制方面仍存在一定的局限性。本文还介绍了Presto在实际应用中的多种场景,展示了其在大数据分析领域的强大潜力。 ... [详细]
  • 在处理遗留数据库的映射时,反向工程是一个重要的初始步骤。由于实体模式已经在数据库系统中存在,Hibernate 提供了自动化工具来简化这一过程,帮助开发人员快速生成持久化类和映射文件。通过反向工程,可以显著提高开发效率并减少手动配置的错误。此外,该工具还支持对现有数据库结构进行分析,自动生成符合 Hibernate 规范的配置文件,从而加速项目的启动和开发周期。 ... [详细]
  • Spring框架中的面向切面编程(AOP)技术详解
    面向切面编程(AOP)是Spring框架中的关键技术之一,它通过将横切关注点从业务逻辑中分离出来,实现了代码的模块化和重用。AOP的核心思想是将程序运行过程中需要多次处理的功能(如日志记录、事务管理等)封装成独立的模块,即切面,并在特定的连接点(如方法调用)动态地应用这些切面。这种方式不仅提高了代码的可维护性和可读性,还简化了业务逻辑的实现。Spring AOP利用代理机制,在不修改原有代码的基础上,实现了对目标对象的增强。 ... [详细]
  • 如何在Java中高效构建WebService
    本文介绍了如何利用XFire框架在Java中高效构建WebService。XFire是一个轻量级、高性能的Java SOAP框架,能够简化WebService的开发流程。通过结合MyEclipse集成开发环境,开发者可以更便捷地进行项目配置和代码编写,从而提高开发效率。此外,文章还详细探讨了XFire的关键特性和最佳实践,为读者提供了实用的参考。 ... [详细]
  • 为了优化直播应用底部聊天框的弹出机制,确保在不同设备上的布局稳定性和兼容性,特别是在配备虚拟按键的设备上,我们对用户交互流程进行了调整。首次打开应用时,需先点击首个输入框以准确获取键盘高度,避免直接点击第二个输入框导致的整体布局挤压问题。此优化通过调整 `activity_main.xml` 布局文件实现,确保了更好的用户体验和界面适配。 ... [详细]
  • 在Spring框架中,基于Schema的异常通知与环绕通知的实现方法具有重要的实践价值。首先,对于异常通知,需要创建一个实现ThrowsAdvice接口的通知类。尽管ThrowsAdvice接口本身不包含任何方法,但开发者需自定义方法来处理异常情况。此外,环绕通知则通过实现MethodInterceptor接口来实现,允许在方法调用前后执行特定逻辑,从而增强功能或进行必要的控制。这两种通知机制的结合使用,能够有效提升应用程序的健壮性和灵活性。 ... [详细]
  • 深入解析 Android Drawable:第六阶段进阶指南 ... [详细]
author-avatar
手机用户2502858281
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有