Android 自定义拍照音效 问题

本文详细介绍了一个集成拍照、相框选择及简单手势操作功能的应用开发过程。该应用利用Android的Camera API实现拍照,并通过自定义视图组件实现了相框的动态切换。此外,还介绍了如何通过手势识别器实现相框的滑动切换。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

package com.platomix.babyshow.activity;



import com.example.demo_imagecreate.R;
import com.platomix.babyshow.util.BitmapUtil;
import com.platomix.babyshow.util.Loger;
import com.platomix.babyshow.util.SoundPlayer;
import com.platomix.babyshow.widget.ToggleButton;
import com.platomix.babyshow.widget.ToggleButton.OnSwitchStatusListener;

import android.os.Bundle;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.hardware.Camera;
import android.hardware.Camera.AutoFocusCallback;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.PictureCallback;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.SurfaceHolder.Callback;
import android.view.View.OnClickListener;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.Toast;

public class TakePhotoActivity extends Activity implements OnClickListener{
	private static final String TAG = "TakePhotoActivity";
	private Context context;
	private static int[] photoFrames = {R.drawable.photo_frame1,R.drawable.photo_frame2};
	private SurfaceView previewPhoto;        //照片
	private Camera camera;
	private ImageView photoFrame;   //相框
	private  ToggleButton takephoto_switch;
	private ImageButton btn_camera_photo;  
	private ImageView btn_frame;  
	private ImageView btn_thumbnail;
	private ImageView arrow_right;   //下一个
	private ImageView arrow_left;    //上一个
	private ImageView btn_back;

	private boolean haveFrame ;          //是否有相框  true:有
	private int currentPhotoFrameIndex;  //当前相框的资源id的数组下标
	private int photoFramesCount;
	private boolean isTakePhoto ;//是否是拍照:true:拍照   false:录像

	//1.声明一个手势识别器
	private GestureDetector mGestureDetector;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.takephoto_activity);
		context = this.getApplicationContext();
		SoundPlayer.init(context);
		haveFrame = false;
		isTakePhoto = true;
		currentPhotoFrameIndex = 0;
		photoFramesCount = photoFrames.length;
		takephoto_switch = (ToggleButton) findViewById(R.id.takephoto_switch);
		takephoto_switch.setSwitchStyle(R.drawable.bkg_take_photo_switch, R.drawable.icon_photo, R.drawable.icon_camera);
		takephoto_switch.setTop(true);

		//添加开关状态改变监听器
		takephoto_switch.setOnSwitchStatusListener(new OnSwitchStatusListener() {
			@Override
			public void onSwitch(boolean isTop) {
				if(isTop){
					//拍照
					isTakePhoto = true;
					btn_camera_photo.setBackgroundResource(R.drawable.btn_photo);
				} else {
					//录像
					isTakePhoto = false;
					btn_camera_photo.setBackgroundResource(R.drawable.btn_camera);
				}
			}
		});
		previewPhoto = (SurfaceView) findViewById(R.id.previewPhoto);
		previewPhoto.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
		previewPhoto.getHolder().addCallback(new MyCallback());
		//camera = Camera.open();
		photoFrame = (ImageView) findViewById(R.id.photoFrame);

		btn_camera_photo = (ImageButton) findViewById(R.id.btn_camera_photo);
		btn_camera_photo.setClickable(true);
		btn_camera_photo.setOnClickListener(this);
		btn_frame = (ImageView) findViewById(R.id.btn_frame);
		btn_frame.setOnClickListener(this);
		btn_thumbnail = (ImageView) findViewById(R.id.btn_thumbnail);
		btn_thumbnail.setOnClickListener(this);
		arrow_right = (ImageView) findViewById(R.id.arrow_right);
		arrow_right.setOnClickListener(this);
		arrow_left = (ImageView) findViewById(R.id.arrow_left);
		arrow_left.setOnClickListener(this);
		btn_back = (ImageView) findViewById(R.id.btn_back);
		btn_back.setOnClickListener(this);

		//		Bitmap  bitmap1 = BitmapFactory.decodeResource(this.getResources(), R.drawable.arrow_right);
		//		Bitmap  bitmap2 = BitmapFactory.decodeResource(this.getResources(), R.drawable.photo_frame1);
		//		bitmapTemp = BitmapUtil.createBitmap(bitmap1,bitmap2);
		//		//		//photo.setImageBitmap(bitmapTemp);
		//		//ornament = new MoveWithFingerView(this, R.drawable.ic_launcher);
		//		//main_RL.addView(ornament);
		setPhotoFrame(haveFrame);

		//2.初始化手势识别器
		//Basic Default Base Simple
		mGestureDetector = new GestureDetector(this, new GestureDetector.SimpleOnGestureListener(){


			/**划屏对应的方法.
			 * e1 手指第一次触摸屏幕
			 * e2 手指离开屏幕瞬间
			 * velocityX 水平方向移动的速度 px/s
			 * velocityY 竖直方向移动的速度
			 */
			@Override
			public boolean onFling(MotionEvent e1, MotionEvent e2,float velocityX, float velocityY) {
				if(haveFrame){//使用相框
					if(Math.abs(velocityX)<100){
						Loger.d(TAG,"移动的太慢,动作不合法");
						return true;
					}
					if((e2.getRawX()-e1.getRawX()) >200){
						Loger.d(TAG,"上一张,同:arrow_left");
						photoFrame.setBackgroundResource(photoFrames[1]);
						if(currentPhotoFrameIndex == 0){
							currentPhotoFrameIndex = photoFramesCount;
						}
						photoFrame.setBackgroundResource(photoFrames[(--currentPhotoFrameIndex)%photoFramesCount]);
						
						return true;
					}
					if((e1.getRawX()-e2.getRawX()) >200){
						Loger.d(TAG,"下一张,同:arrow_right");
						photoFrame.setBackgroundResource(photoFrames[(++currentPhotoFrameIndex)%photoFramesCount]);
						return true;
					}
				}
				return super.onFling(e1, e2, velocityX, velocityY);
			}
		});
	}

	/********相机**********/
	private class MyCallback implements Callback {
		//打开摄像头,开始预览
		public void surfaceCreated(SurfaceHolder holder) {
			Loger.d(TAG, "surfaceCreated");
			try {
				camera = Camera.open();  //打开摄像头
				Loger.d(TAG, "camera="+camera);
				Parameters params = camera.getParameters();	// 获取默认参数
				System.out.println(params.flatten());	// 打印
				params.setPictureSize(800, 480);		// 拍照尺寸
				params.setPreviewSize(800, 480);        // 预览尺寸
				params.setFlashMode("on");              // 闪光灯打开
				params.setJpegQuality(50);              // 照片质量,100是最高质量
				camera.setParameters(params);			// 把修改后的参数设置到摄像头

				camera.setPreviewDisplay(previewPhoto.getHolder());// 设置预览显示位置,在 previewSV
				camera.startPreview();		// 开始预览
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		//停止预览,释放摄像头
		public void surfaceDestroyed(SurfaceHolder holder) {
			Loger.d(TAG, "surfaceDestroyed"); //activity 返回时候,surfaceView自动销毁
			if (camera != null) {
				camera.stopPreview();		// 停止预览
				camera.release();			// 释放资源
				camera = null;				// 垃圾回收
			}
		}
		public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
		}
	}

	private class MyAutoFocusCallback implements AutoFocusCallback {
		public void onAutoFocus(boolean success, Camera camera) {
			/*
			 * 4个回调对象
			 * 1: 当按下快门时执行其中方法, 通常用来播放一个提示音
			 * 2: 当获取到原始数据时会执行其中方法
			 * 3: 当生成预览图片时调用(有的设备不支持)
			 * 4: 当压缩成JPG格式之后调用, 通常在这个方法中获取数据
			 */
			camera.takePicture(null, null, null, new MyPictureCallback());	// 对焦结束后拍照
		}
	}
	private class MyPictureCallback implements PictureCallback {
		public void onPictureTaken(byte[] data, Camera camera) {		// 获取到数据后, 写到文件
			String path = "/mnt/sdcard/DCIM";
			String thumbnailFileName = "thumbnail_"+System.currentTimeMillis() + ".png";
			String photoFileName = System.currentTimeMillis() + ".png";
			if(haveFrame){ //有相框
				Bitmap  bitmapPhoto = BitmapFactory.decodeByteArray(data, 0, data.length);
				Bitmap  bitmapPhotoFrame = BitmapFactory.decodeResource(getResources(), photoFrames[currentPhotoFrameIndex]);
				Bitmap  bitmapResult = BitmapUtil.createBitmap(context, bitmapPhoto, photoFrames[currentPhotoFrameIndex]);
				//缩略图
				BitmapUtil.savePhotoThumbnailToFile(path,thumbnailFileName,0.5, bitmapResult);
				//照片
				BitmapUtil.saveBitmapToFile(path,photoFileName, bitmapResult);
				camera.startPreview();
			}else{
				Bitmap  bitmapPhoto = BitmapFactory.decodeByteArray(data, 0, data.length);
				BitmapUtil.savePhotoThumbnailToFile(path,thumbnailFileName,0.5, bitmapPhoto);
				BitmapUtil.saveBitmapToFile(path, photoFileName, bitmapPhoto);
				camera.startPreview();
			}
			//照片截图
			Bitmap photoScreenshot = BitmapFactory.decodeFile(path +"/"+ thumbnailFileName);
			if(photoScreenshot != null){
				Loger.d(TAG, path +"/"+ thumbnailFileName);
				btn_thumbnail.setImageBitmap(photoScreenshot);
			}
		}
	}
	@Override
	public void onClick(View v) {
		switch (v.getId()) {
		case R.id.btn_camera_photo:
			if(isTakePhoto){
				//拍照
				Loger.d(TAG, "对焦,拍照");
//				SoundPlayer.init(this);
				SoundPlayer.playSound(1);
				camera.autoFocus(new MyAutoFocusCallback()); // 自动对焦,拍照
			}else{
				//录像
				Loger.d(TAG, "切换到录像");
				Intent intent = new Intent();
				intent.setClass(this, VideoRecodActivity.class);
				startActivity(intent);
			}
			break;
		case R.id.btn_frame:
			Loger.d(TAG,"btn_frame");
			haveFrame = !haveFrame;
			setPhotoFrame(haveFrame);
			break;
		case R.id.btn_thumbnail:
			 Loger.d(TAG, "btn_thumbnail");
			break;
		case R.id.arrow_right: 
			Loger.d(TAG, "arrow_right");
			photoFrame.setBackgroundResource(photoFrames[(++currentPhotoFrameIndex)%photoFramesCount]);
			break;
		case R.id.arrow_left:
			Loger.d(TAG, "arrow_left");
			photoFrame.setBackgroundResource(photoFrames[1]);
			if(currentPhotoFrameIndex == 0){
				currentPhotoFrameIndex = photoFramesCount;
			}
			photoFrame.setBackgroundResource(photoFrames[(--currentPhotoFrameIndex)%photoFramesCount]);
			break;
		case R.id.btn_back:
			System.out.println("btn_back");
			break;
		default:
			break;
		}
	}

	//	@Override
	//	public boolean onKeyDown(int keyCode, KeyEvent event) {
	//		if (keyCode == KeyEvent.KEYCODE_BACK) {
	//			bitmapLast = createBitmap(bitmapTemp,bitmapOrnament);
	//			photo.setImageBitmap(bitmapLast);
	//			String path = "";//"/mnt/sdcard/Android";
	//			String fileName = "p10.png";
	//			//System.out.println("result="+BitmapUtil.saveBitmapToFile(path,fileName,bitmapLast));
	//			System.out.println("result="+BitmapUtil.savePhotoThumbnailToFile(path, fileName, null));
	//			return true;
	//		}
	//		 return super.onKeyDown(keyCode, event);
	//	}

	/**
	 * 设置相框是否显示
	 * @param haveFrame  true:显示   应该吧btn_frame图片切换
	 */
	private void setPhotoFrame(boolean haveFrame){
		if(haveFrame){ //有相框
			arrow_left.setVisibility(View.VISIBLE);
			arrow_right.setVisibility(View.VISIBLE);
			photoFrame.setBackgroundResource(photoFrames[0]);
		}else{
			arrow_left.setVisibility(View.GONE);
			arrow_right.setVisibility(View.GONE);
			photoFrame.setBackgroundResource(0);
		}
	}
	//3.activity被触摸的时候调用的方法 , 需要在这个里面让手势识别器 生效
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		//让手势识别器 生效
		mGestureDetector.onTouchEvent(event);
		return super.onTouchEvent(event);
	}
}

下面这个值转载的:是播放声音的工具类,声音的资源文件放到 res/raw 目录下,MP3,wav 都行

package com.platomix.babyshow.util;


import java.util.HashMap;
import java.util.Map;
import java.util.Random;



import com.example.demo_imagecreate.R;

import android.content.Context;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.SoundPool;
/**
 * 声音控制类
 * @author wyf
 */
public class SoundPlayer {
	private static MediaPlayer music;
	private static SoundPool soundPool;
	private static boolean musicSt = true; //音乐开关
	private static boolean soundSt = true; //音效开关
	private static Context context;
	private static final int[] musicId = {R.raw.cs1};
	private static Map<Integer,Integer> soundMap; //音效资源id与加载过后的音源id的映射关系表

	/**
	 * 初始化方法
	 * @param c
	 */
	public static void init(Context c){
		context = c;
		initMusic();
		initSound();
	}

	//初始化音效播放器
	private static void initSound(){
		soundPool = new SoundPool(10,AudioManager.STREAM_MUSIC,0);
		soundMap = new HashMap<Integer,Integer>();
		soundMap.put(1, soundPool.load(context, R.raw.cs1, 1));
		soundMap.put(2, soundPool.load(context, R.raw.cs2, 1));
	}

	//初始化音乐播放器
	private static void initMusic(){
		int r = new Random().nextInt(musicId.length);
		music = MediaPlayer.create(context,musicId[r]);
		music.setLooping(true);
	}

	/**
	 * 播放音效
	 * @param resId 音效资源id
	 */
	public static void playSound(int resId){
		if(soundSt == false){
			return;
		}
		Integer soundId = soundMap.get(resId);
		if(soundId != null){
			soundPool.play(soundId, 1, 1, 1, 0, 1);
		}
	}

	/**
	 * 暂停音乐
	 */
	public static void pauseMusic(){
		if(music.isPlaying()){
			music.pause();
		}
	}

	/**
	 * 播放音乐
	 */
	public static void startMusic(){
		if(musicSt){
				music.start();
		}
	}

	/**
	 * 切换一首音乐并播放
	 */
	public static void changeAndPlayMusic(){
		if(music != null){
			music.release();
		}
		initMusic();
		startMusic();
	}

	/**
	 * 获得音乐开关状态
	 * @return
	 */
	public static boolean isMusicSt() {
		return musicSt;
	}

	/**
	 * 设置音乐开关
	 * @param musicSt
	 */
	public static void setMusicSt(boolean musicSt) {
		SoundPlayer.musicSt = musicSt;
		if(musicSt)
			music.start();
		else
			music.stop();
	}

	/**
	 * 获得音效开关状态
	 * @return
	 */
	public static boolean isSoundSt() {
		return soundSt;
	}

	/**
	 * 设置音效开关
	 * @param soundSt
	 */
	public static void setSoundSt(boolean soundSt) {
		SoundPlayer.soundSt = soundSt;
	}

	/**
	 * 发出‘邦’的声音
	 */
	public static void boom()
	{
		playSound(1);
	}
}


有个问题,先 mark 一下:SoundPlayer.init(context); 放在 activity 的onCreate 中,音效可以正常播放;

但是 SoundPlayer.init(context); 放到按钮的监听 onClick 方法中就没声音了。但是拍照可以继续

目前猜测:SoundPlayer.init(context) 是在另一个子线程中加载文件,所有才会这样子


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值