Android仿最新微信相机功能

最近在开发即时通讯这个模块的时候使用到了自定义的相机,需求与微信一样,要求相机能长按和轻点,当时在网上找自定义相机的资源,很少,所以,我在这里把我的一些开发经验贴出来,供大家学习。

大致完成的功能如下:

  • 长按拍摄视频,轻点拍照
  • 前后摄像头的切换
  • 闪光的的开启,关闭,自动
  • 图片的压缩
  • 自动聚焦,手动聚焦

效果图如下:

相关代码如下:

package com.ses.im.app.chat.newcamera;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.PointF;
import android.graphics.SurfaceTexture;
import android.hardware.Camera;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.view.Surface;
import android.view.TextureView;
import android.view.View;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.ses.im.app.chat.R;

import java.io.File;
import java.util.concurrent.TimeUnit;

import rx.Observable;
import rx.Subscriber;
import rx.Subscription;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;

/**
 *
 * 拍摄界面
 */
public class CameraActivity extends AppCompatActivity implements View.OnClickListener {
 /**
 * 获取相册
 */
 public static final int REQUEST_PHOTO = 1;
 /**
 * 获取视频
 */
 public static final int REQUEST_VIDEO = 2;
 /**
 * 最小录制时间
 */
 private static final int MIN_RECORD_TIME = 1 * 1000;
 /**
 * 最长录制时间
 */
 private static final int MAX_RECORD_TIME = 15 * 1000;
 /**
 * 刷新进度的间隔时间
 */
 private static final int PLUSH_PROGRESS = 100;

 private Context mContext;
 /**
 * TextureView
 */
 private TextureView mTextureView;
 /**
 * 带手势识别
 */
 private CameraView mCameraView;
 /**
 * 录制按钮
 */
 private CameraProgressBar mProgressbar;
 /**
 * 顶部像机设置
 */
 private RelativeLayout rl_camera;
 /**
 * 关闭,选择,前后置
 */
 private ImageView iv_close, iv_facing;
 private RelativeLayout iv_choice;
 private RelativeLayout cancel;
 /**
 * 闪光
 */
 private TextView tv_flash;
 /**
 * camera manager
 */
 private CameraManager cameraManager;
 /**
 * player manager
 */
 private MediaPlayerManager playerManager;
 /**
 * true代表视频录制,否则拍照
 */
 private boolean isSupportRecord;
 /**
 * 视频录制地址
 */
 private String recorderPath;
 /**
 * 图片地址
 */
 private String photoPath;
 /**
 * 录制视频的时间,毫秒
 */
 private int recordSecond;
 /**
 * 获取照片订阅, 进度订阅
 */
 private Subscription takePhotoSubscription, progressSubscription;
 /**
 * 是否正在录制
 */
 private boolean isRecording;

 /**
 * 是否为点了拍摄状态(没有拍照预览的状态)
 */
 private boolean isPhotoTakingState;

 public static void lanuchForPhoto(Activity context) {
 Intent intent = new Intent(context, CameraActivity.class);
 context.startActivityForResult(intent, REQUEST_PHOTO);
 }

 @Override
 protected void onCreate(@Nullable Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 mContext = this;
 setContentView(R.layout.activity_camera);
 initView();
 initDatas();
 }

 private void initView() {
 mTextureView = (TextureView) findViewById(R.id.mTextureView);
 mCameraView = (CameraView) findViewById(R.id.mCameraView);
 mProgressbar = (CameraProgressBar) findViewById(R.id.mProgressbar);
 rl_camera = (RelativeLayout) findViewById(R.id.rl_camera);
 iv_close = (ImageView) findViewById(R.id.iv_close);
 iv_close.setOnClickListener(this);
 iv_choice = (RelativeLayout) findViewById(R.id.iv_choice);
 iv_choice.setOnClickListener(this);
 iv_close.setOnClickListener(this);
 iv_facing = (ImageView) findViewById(R.id.iv_facing);
 iv_facing.setOnClickListener(this);
 iv_close.setOnClickListener(this);
 tv_flash = (TextView) findViewById(R.id.tv_flash);
 tv_flash.setOnClickListener(this);
 cancel= (RelativeLayout) findViewById(R.id.cancel);
 cancel.setOnClickListener(this);
 }

 protected void initDatas() {
 cameraManager = CameraManager.getInstance(getApplication());
 playerManager = MediaPlayerManager.getInstance(getApplication());
 cameraManager.setCameraType(isSupportRecord ? 1 : 0);

 tv_flash.setVisibility(cameraManager.isSupportFlashCamera() ? View.VISIBLE : View.GONE);
 setCameraFlashState();
 iv_facing.setVisibility(cameraManager.isSupportFrontCamera() ? View.VISIBLE : View.GONE);
 rl_camera.setVisibility(cameraManager.isSupportFlashCamera()
  || cameraManager.isSupportFrontCamera() ? View.VISIBLE : View.GONE);

 final int max = MAX_RECORD_TIME / PLUSH_PROGRESS;
 mProgressbar.setMaxProgress(max);

 /**
  * 拍照,拍摄按钮监听
  */
 mProgressbar.setOnProgressTouchListener(new CameraProgressBar.OnProgressTouchListener() {
  @Override
  public void onClick(CameraProgressBar progressBar) {
  cameraManager.takePhoto(callback);
  isSupportRecord = false;
  }

  @Override
  public void onLongClick(CameraProgressBar progressBar) {
  isSupportRecord = true;
  cameraManager.setCameraType(1);
  rl_camera.setVisibility(View.GONE);
  recorderPath = FileUtils.getUploadVideoFile(mContext);
  cameraManager.startMediaRecord1(recorderPath);
  isRecording = true;
  progressSubscription = Observable.interval(100, TimeUnit.MILLISECONDS, AndroidSchedulers.mainThread()).take(max).subscribe(new Subscriber<Long>() {
   @Override
   public void onCompleted() {
   stopRecorder(true);
   }

   @Override
   public void onError(Throwable e) {

   }

   @Override
   public void onNext(Long aLong) {
   mProgressbar.setProgress(mProgressbar.getProgress() + 1);
   }
  });
  }

  @Override
  public void onZoom(boolean zoom) {
  cameraManager.handleZoom(zoom);
  }

  @Override
  public void onLongClickUp(CameraProgressBar progressBar) {
//  isSupportRecord = false;
  cameraManager.setCameraType(0);
  stopRecorder(true);
  if (progressSubscription != null) {
   progressSubscription.unsubscribe();
  }
  }

  @Override
  public void onPointerDown(float rawX, float rawY) {
  if (mTextureView != null) {
   mCameraView.setFoucsPoint(new PointF(rawX, rawY));
  }
  }
 });

 /**
  *点击预览图聚焦
  */
 mCameraView.setOnViewTouchListener(new CameraView.OnViewTouchListener() {
  @Override
  public void handleFocus(float x, float y) {
  cameraManager.handleFocusMetering(x, y);
  }

  @Override
  public void handleZoom(boolean zoom) {
  cameraManager.handleZoom(zoom);
  }
 });
 }

 /**
 * 设置闪光状态
 */
 private void setCameraFlashState() {
 int flashState = cameraManager.getCameraFlash();
 switch (flashState) {
  case 0: //自动
  tv_flash.setSelected(true);
  tv_flash.setText("自动");
  break;
  case 1://open
  tv_flash.setSelected(true);
  tv_flash.setText("开启");
  break;
  case 2: //close
  tv_flash.setSelected(false);
  tv_flash.setText("关闭");
  break;
 }
 }

 /**
 * 是否显示录制按钮
 * @param isShow
 */
 private void setTakeButtonShow(boolean isShow) {
 if (isShow) {
  mProgressbar.setVisibility(View.VISIBLE);
  rl_camera.setVisibility(cameraManager.isSupportFlashCamera()
   || cameraManager.isSupportFrontCamera() ? View.VISIBLE : View.GONE);
 } else {
  mProgressbar.setVisibility(View.GONE);
  rl_camera.setVisibility(View.GONE);
 }
 }

 /**
 * 停止拍摄
 */
 private void stopRecorder(boolean play) {
 isRecording = false;
 cameraManager.stopMediaRecord();
 recordSecond = mProgressbar.getProgress() * PLUSH_PROGRESS;//录制多少毫秒
 mProgressbar.reset();
 if (recordSecond < MIN_RECORD_TIME) {//小于最小录制时间作废
  if (recorderPath != null) {
  FileUtils.delteFiles(new File(recorderPath));
  recorderPath = null;
  recordSecond = 0;
  }
  setTakeButtonShow(true);
 } else if (play && mTextureView != null && mTextureView.isAvailable()){
  setTakeButtonShow(false);
  mProgressbar.setVisibility(View.GONE);
  iv_choice.setVisibility(View.VISIBLE);
  cancel.setVisibility(View.VISIBLE);
  iv_close.setVisibility(View.GONE);
  cameraManager.closeCamera();
  playerManager.playMedia(new Surface(mTextureView.getSurfaceTexture()), recorderPath);
 }
 }

 @Override
 protected void onResume() {
 super.onResume();
 if (mTextureView.isAvailable()) {
  if (recorderPath != null) {//优先播放视频
  iv_choice.setVisibility(View.VISIBLE);
  setTakeButtonShow(false);
  playerManager.playMedia(new Surface(mTextureView.getSurfaceTexture()), recorderPath);
  } else {
  iv_choice.setVisibility(View.GONE);
  setTakeButtonShow(true);
  cameraManager.openCamera(mTextureView.getSurfaceTexture(),
   mTextureView.getWidth(), mTextureView.getHeight());
  }
 } else {
  mTextureView.setSurfaceTextureListener(listener);
 }
 }

 @Override
 protected void onPause() {
 if (progressSubscription != null) {
  progressSubscription.unsubscribe();
 }
 if (takePhotoSubscription != null) {
  takePhotoSubscription.unsubscribe();
 }
 if (isRecording) {
  stopRecorder(false);
 }
 cameraManager.closeCamera();
 playerManager.stopMedia();
 super.onPause();
 }

 @Override
 protected void onDestroy() {
 mCameraView.removeOnZoomListener();
 super.onDestroy();
 }

 @Override
 public void onClick(View v) {
 int i = v.getId();
 if (i == R.id.iv_close) {
//  if (recorderPath != null) {//有拍摄好的正在播放,重新拍摄
//  FileUtils.delteFiles(new File(recorderPath));
//  recorderPath = null;
//  recordSecond = 0;
//  playerManager.stopMedia();
//  setTakeButtonShow(true);
//  iv_choice.setVisibility(View.GONE);
//  cameraManager.openCamera(mTextureView.getSurfaceTexture(), mTextureView.getWidth(), mTextureView.getHeight());
//  } else if (isPhotoTakingState) {
//  isPhotoTakingState = false;
//  iv_choice.setVisibility(View.GONE);
//  setTakeButtonShow(true);
//  cameraManager.restartPreview();
//  } else {
  finish();
//  }

 } else if (i == R.id.iv_choice) {//拿到图片或视频路径
  Intent intent=new Intent();
  if(isSupportRecord){
  intent.putExtra("videopath", recorderPath);
  setResult(3, intent);
  finish();
  }else{
  intent.putExtra("videopath", photoPath);
  setResult(3, intent);
  finish();
  }

 } else if (i == R.id.tv_flash) {
  cameraManager.changeCameraFlash(mTextureView.getSurfaceTexture(),
   mTextureView.getWidth(), mTextureView.getHeight());
  setCameraFlashState();

 } else if (i == R.id.iv_facing) {
  cameraManager.changeCameraFacing(mTextureView.getSurfaceTexture(),
   mTextureView.getWidth(), mTextureView.getHeight());

 }else if(i == R.id.cancel){
  if (recorderPath != null) {//有拍摄好的正在播放,重新拍摄
  FileUtils.delteFiles(new File(recorderPath));
  recorderPath = null;
  recordSecond = 0;
  playerManager.stopMedia();
  setTakeButtonShow(true);
  iv_choice.setVisibility(View.GONE);
  cancel.setVisibility(View.GONE);
  iv_close.setVisibility(View.VISIBLE);

  cameraManager.openCamera(mTextureView.getSurfaceTexture(), mTextureView.getWidth(), mTextureView.getHeight());
  } else if (isPhotoTakingState) {
  isPhotoTakingState = false;
  iv_choice.setVisibility(View.GONE);
  cancel.setVisibility(View.GONE);
  iv_close.setVisibility(View.VISIBLE);
  setTakeButtonShow(true);
  cameraManager.restartPreview();
  }
 }
 }

 /**
 * camera回调监听
 */
 private TextureView.SurfaceTextureListener listener = new TextureView.SurfaceTextureListener() {
 @Override
 public void onSurfaceTextureAvailable(SurfaceTexture texture, int width, int height) {
  if (recorderPath != null) {
  iv_choice.setVisibility(View.VISIBLE);
  setTakeButtonShow(false);
  playerManager.playMedia(new Surface(texture), recorderPath);
  } else {
  setTakeButtonShow(true);
  iv_choice.setVisibility(View.GONE);
  cameraManager.openCamera(texture, width, height);
  }
 }

 @Override
 public void onSurfaceTextureSizeChanged(SurfaceTexture texture, int width, int height) {
 }

 @Override
 public boolean onSurfaceTextureDestroyed(SurfaceTexture texture) {
  return true;
 }

 @Override
 public void onSurfaceTextureUpdated(SurfaceTexture texture) {
 }
 };

 private Camera.PictureCallback callback = new Camera.PictureCallback() {
 @Override
 public void onPictureTaken(final byte[] data, Camera camera) {
  setTakeButtonShow(false);
  takePhotoSubscription = Observable.create(new Observable.OnSubscribe<Boolean>() {
  @Override
  public void call(Subscriber<? super Boolean> subscriber) {
   if (!subscriber.isUnsubscribed()) {
   photoPath = FileUtils.getUploadPhotoFile(mContext);
   isPhotoTakingState = FileUtils.savePhoto(photoPath, data, cameraManager.isCameraFrontFacing());
   subscriber.onNext(isPhotoTakingState);
   }
  }
  }).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Subscriber<Boolean>() {
  @Override
  public void onCompleted() {

  }

  @Override
  public void onError(Throwable e) {

  }

  @Override
  public void onNext(Boolean aBoolean) {
   if (aBoolean != null && aBoolean) {
   iv_choice.setVisibility(View.VISIBLE);
   cancel.setVisibility(View.VISIBLE);
   iv_close.setVisibility(View.GONE);
   } else {
   setTakeButtonShow(true);
   }
  }
  });
 }
 };

}

相机管理类:

package com.ses.im.app.chat.newcamera;

import android.app.Application;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.SurfaceTexture;
import android.hardware.Camera;
import android.media.CamcorderProfile;
import android.media.MediaRecorder;
import android.util.Log;
import android.widget.Toast;

import com.ses.im.app.chat.util.AppConfig;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/**
 *
 * 相机管理类
 */

public final class CameraManager {

 private Application context;
 /**
 * camera
 */
 private Camera mCamera;
 private Camera.Parameters mParameters;
 /**
 * 视频录制
 */
 private MediaRecorder mMediaRecorder;
 /**
 * 相机闪光状态
 */
 private int cameraFlash;
 /**
 * 前后置状态
 */
 private int cameraFacing = Camera.CameraInfo.CAMERA_FACING_BACK;
 /**
 * 是否支持前置摄像,是否支持闪光
 */
 private boolean isSupportFrontCamera, isSupportFlashCamera;
 /**
 * 录制视频的相关参数
 */
 private CamcorderProfile mProfile;
 /**
 * 0为拍照, 1为录像
 */
 private int cameraType;

 private CameraManager(Application context) {
 this.context = context;
 isSupportFrontCamera = CameraUtils.isSupportFrontCamera();
 isSupportFlashCamera = CameraUtils.isSupportFlashCamera(context);
 if (isSupportFrontCamera) {
  cameraFacing = CameraUtils.getCameraFacing(context, Camera.CameraInfo.CAMERA_FACING_BACK);
 }
 if (isSupportFlashCamera) {
  cameraFlash = CameraUtils.getCameraFlash(context);
 }
 }

 private static CameraManager INSTANCE;

 public static CameraManager getInstance(Application context) {
 if (INSTANCE == null) {
  synchronized (CameraManager.class) {
  if (INSTANCE == null) {
   INSTANCE = new CameraManager(context);
  }
  }
 }
 return INSTANCE;
 }

 /**
 * 打开camera
 */
 public void openCamera(SurfaceTexture surfaceTexture, int width, int height) {
 if (mCamera == null) {
  mCamera = Camera.open(cameraFacing);//打开当前选中的摄像头
  mProfile = CamcorderProfile.get(cameraFacing, CamcorderProfile.QUALITY_HIGH);
  try {
  mCamera.setDisplayOrientation(90);//默认竖直拍照
  mCamera.setPreviewTexture(surfaceTexture);
  initCameraParameters(cameraFacing, width, height);
  mCamera.startPreview();
  } catch (Exception e) {
  LogUtils.i(e);
  if (mCamera != null) {
   mCamera.release();
   mCamera = null;
  }
  }
 }
 }

 /**
 * 开启预览,前提是camera初始化了
 */
 public void restartPreview() {
 if (mCamera == null) return;
 try {
  Camera.Parameters parameters = mCamera.getParameters();
  int zoom = parameters.getZoom();
  if (zoom > 0) {
  parameters.setZoom(0);
  mCamera.setParameters(parameters);
  }
  mCamera.startPreview();
 } catch (Exception e) {
  LogUtils.i(e);
  if (mCamera != null) {
  mCamera.release();
  mCamera = null;
  }
 }
 }

 private void initCameraParameters(int cameraId, int width, int height) {
 Camera.Parameters parameters = mCamera.getParameters();
 if (cameraId == Camera.CameraInfo.CAMERA_FACING_BACK) {
  List<String> focusModes = parameters.getSupportedFocusModes();
  if (focusModes != null) {
  if (cameraType == 0) {
   if (focusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
   parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
   }
  } else {
   if (focusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) {
   parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
   }
  }
  }
 }
 parameters.setRotation(90);//设置旋转代码,
 switch (cameraFlash) {
  case 0:
  parameters.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);
  break;
  case 1:
  parameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
  break;
  case 2:
  parameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
  break;
 }
 List<Camera.Size> pictureSizes = parameters.getSupportedPictureSizes();
 List<Camera.Size> previewSizes = parameters.getSupportedPreviewSizes();
 if (!isEmpty(pictureSizes) && !isEmpty(previewSizes)) {
  /**
  for (Camera.Size size : pictureSizes) {
  LogUtils.i("pictureSize " + size.width + " " + size.height);
  }
  for (Camera.Size size : pictureSizes) {
  LogUtils.i("previewSize " + size.width + " " + size.height);
  }*/
  Camera.Size optimalPicSize = getOptimalCameraSize(pictureSizes, width, height);
  Camera.Size optimalPreSize = getOptimalCameraSize(previewSizes, width, height);
//  Camera.Size optimalPicSize = getOptimalSize(pictureSizes, width, height);
//  Camera.Size optimalPreSize = getOptimalSize(previewSizes, width, height);
  LogUtils.i("TextureSize "+width+" "+height+" optimalSize pic " + optimalPicSize.width + " " + optimalPicSize.height + " pre " + optimalPreSize.width + " " + optimalPreSize.height);
  parameters.setPictureSize(optimalPicSize.width, optimalPicSize.height);
  parameters.setPreviewSize(optimalPreSize.width, optimalPreSize.height);
  mProfile.videoFrameWidth = optimalPreSize.width;
  mProfile.videoFrameHeight = optimalPreSize.height;
  mProfile.videoBitRate = 5000000;//此参数主要决定视频拍出大小
 }
 mCamera.setParameters(parameters);
 }

 /**
 * 释放摄像头
 */
 public void closeCamera() {
 this.cameraType = 0;
 if (mCamera != null) {
  try {
  mCamera.stopPreview();
  mCamera.release();
  mCamera = null;
  } catch (Exception e) {
  LogUtils.i(e);
  if (mCamera != null) {
   mCamera.release();
   mCamera = null;
  }
  }
 }
 }

 /**
 * 集合不为空
 *
 * @param list
 * @param <E>
 * @return
 */
 private <E> boolean isEmpty(List<E> list) {
 return list == null || list.isEmpty();
 }

 /**
 *
 * @param sizes 相机support参数
 * @param w
 * @param h
 * @return 最佳Camera size
 */
 private Camera.Size getOptimalCameraSize(List<Camera.Size> sizes, int w, int h){
 sortCameraSize(sizes);
 int position = binarySearch(sizes, w*h);
 return sizes.get(position);
 }

 /**
 *
 * @param sizes
 * @param targetNum 要比较的数
 * @return
 */
 private int binarySearch(List<Camera.Size> sizes,int targetNum){
 int targetIndex;
 int left = 0,right;
 int length = sizes.size();
 for (right = length-1;left != right;){
  int midIndex = (right + left)/2;
  int mid = right - left;
  Camera.Size size = sizes.get(midIndex);
  int midValue = size.width * size.height;
  if (targetNum == midValue){
  return midIndex;
  }
  if (targetNum > midValue){
  left = midIndex;
  }else {
  right = midIndex;
  }

  if (mid <= 1){
  break;
  }
 }
 Camera.Size rightSize = sizes.get(right);
 Camera.Size leftSize = sizes.get(left);
 int rightNum = rightSize.width * rightSize.height;
 int leftNum = leftSize.width * leftSize.height;
 targetIndex = Math.abs((rightNum - leftNum)/2) > Math.abs(rightNum - targetNum) ? right : left;
 return targetIndex;
 }

 /**
 * 排序
 * @param previewSizes
 */
 private void sortCameraSize(List<Camera.Size> previewSizes){
 Collections.sort(previewSizes, new Comparator<Camera.Size>() {
  @Override
  public int compare(Camera.Size size1, Camera.Size size2) {
  int compareHeight = size1.height - size2.height;
  if (compareHeight == 0){
   return (size1.width == size2.width ? 0 :(size1.width > size2.width ? 1:-1));
  }
  return compareHeight;
  }
 });
 }

 /**
 * 获取最佳预览相机Size参数
 *
 * @return
 */
 private Camera.Size getOptimalSize(List<Camera.Size> sizes, int w, int h) {
 Camera.Size optimalSize = null;
 float targetRadio = h / (float) w;
 float optimalDif = Float.MAX_VALUE; //最匹配的比例
 int optimalMaxDif = Integer.MAX_VALUE;//最优的最大值差距
 for (Camera.Size size : sizes) {
  float newOptimal = size.width / (float) size.height;
  float newDiff = Math.abs(newOptimal - targetRadio);
  if (newDiff < optimalDif) { //更好的尺寸
  optimalDif = newDiff;
  optimalSize = size;
  optimalMaxDif = Math.abs(h - size.width);
  } else if (newDiff == optimalDif) {//更好的尺寸
  int newOptimalMaxDif = Math.abs(h - size.width);
  if (newOptimalMaxDif < optimalMaxDif) {
   optimalDif = newDiff;
   optimalSize = size;
   optimalMaxDif = newOptimalMaxDif;
  }
  }
 }
 return optimalSize;
 }

 /**
 * 缩放
 * @param isZoomIn
 */
 public void handleZoom(boolean isZoomIn) {
 if (mCamera == null) return;
 Camera.Parameters params = mCamera.getParameters();
 if (params == null) return;
 if (params.isZoomSupported()) {
  int maxZoom = params.getMaxZoom();
  int zoom = params.getZoom();
  if (isZoomIn && zoom < maxZoom) {
  zoom++;
  } else if (zoom > 0) {
  zoom--;
  }
  params.setZoom(zoom);
  mCamera.setParameters(params);
 } else {
  LogUtils.i("zoom not supported");
 }
 }

 /**
 * 更换前后置摄像
 */
 public void changeCameraFacing(SurfaceTexture surfaceTexture, int width, int height) {
 if(isSupportFrontCamera) {
  Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
  int cameraCount = Camera.getNumberOfCameras();//得到摄像头的个数
  for(int i = 0; i < cameraCount; i++) {
  Camera.getCameraInfo(i, cameraInfo);//得到每一个摄像头的信息
  if(cameraFacing == Camera.CameraInfo.CAMERA_FACING_FRONT) { //现在是后置,变更为前置
   if(cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {//代表摄像头的方位为前置
   closeCamera();
   cameraFacing = Camera.CameraInfo.CAMERA_FACING_BACK;
   CameraUtils.setCameraFacing(context, cameraFacing);
   openCamera(surfaceTexture, width, height);
   break;
   }
  } else {//现在是前置, 变更为后置
   if(cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {//代表摄像头的方位
   closeCamera();
   cameraFacing = Camera.CameraInfo.CAMERA_FACING_FRONT;
   CameraUtils.setCameraFacing(context, cameraFacing);
   openCamera(surfaceTexture, width, height);
   break;
   }
  }
  }
 } else { //不支持摄像机
  Toast.makeText(context, "您的手机不支持前置摄像", Toast.LENGTH_SHORT).show();
 }
 }

 /**
 * 改变闪光状态
 */
 public void changeCameraFlash(SurfaceTexture surfaceTexture, int width, int height) {
 if (!isSupportFlashCamera) {
  Toast.makeText(context, "您的手机不支闪光", Toast.LENGTH_SHORT).show();
  return;
 }
 if(mCamera != null) {
  Camera.Parameters parameters = mCamera.getParameters();
  if(parameters != null) {
  int newState = cameraFlash;
  switch (cameraFlash) {
   case 0: //自动
   parameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
   newState = 1;
   break;
   case 1://open
   parameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
   newState = 2;
   break;
   case 2: //close
   parameters.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);
   newState = 0;
   break;
  }
  cameraFlash = newState;
  CameraUtils.setCameraFlash(context, newState);
  mCamera.setParameters(parameters);
  }
 }
 }

 /**
 * 拍照
 */
 public void takePhoto(Camera.PictureCallback callback) {
 if (mCamera != null) {
  try {
  mCamera.takePicture(null, null, callback);
  } catch(Exception e) {
  Toast.makeText(context, "拍摄失败", Toast.LENGTH_SHORT).show();
  }
 }
 }

 /**
 * 开始录制视频
 */
// public void startMediaRecord(String savePath) {
// if (mCamera == null || mProfile == null) return;
// mCamera.unlock();
// if (mMediaRecorder == null) {
//  mMediaRecorder = new MediaRecorder();
// }
// if (isCameraFrontFacing()) {
//  mMediaRecorder.setOrientationHint(270);
//  Log.i("wujie","front");
// }else
// {
//  Log.i("wujie","back");
//  mMediaRecorder.setOrientationHint(90);
// }
// mMediaRecorder.reset();
// mMediaRecorder.setCamera(mCamera);
// mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
// mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
// mMediaRecorder.setProfile(mProfile);
// mMediaRecorder.setOutputFile(savePath);
// try {
//  mMediaRecorder.prepare();
//  mMediaRecorder.start();
// } catch (Exception e) {
//  e.printStackTrace();
//
// }
// }
 /**
 * 开始录制视频
 */
 public void startMediaRecord1(String savePath) {
 if (mCamera == null) {
  return;
 }
 if (mMediaRecorder == null) {
  mMediaRecorder = new MediaRecorder();
 } else {
  mMediaRecorder.reset();
 }

 if (isCameraFrontFacing()) {
  mMediaRecorder.setOrientationHint(270);
  Log.i("wujie","front");
 }else
 {
  Log.i("wujie","back");
  mMediaRecorder.setOrientationHint(90);
 }
 mParameters = mCamera.getParameters();
 mCamera.unlock();
 mMediaRecorder.setCamera(mCamera);
 mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
 mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
 // 设置录像参数
 mMediaRecorder.setProfile(CamcorderProfile.get(AppConfig.VIDEOSIZE));
 try {
  mMediaRecorder.setOutputFile(savePath);
  mMediaRecorder.prepare();
  mMediaRecorder.start();
 } catch (Exception e) {

 }

 }

 /**
 * 停止录制
 */
 public void stopMediaRecord() {
 this.cameraType = 0;
 stopRecorder();
 releaseMediaRecorder();
 }

 private void releaseMediaRecorder() {
 if (mMediaRecorder != null) {
  try {
  mMediaRecorder.reset();
  mMediaRecorder.release();
  mMediaRecorder = null;
  mCamera.lock();
  } catch (Exception e) {
  e.printStackTrace();
  LogUtils.i(e);
  }
 }
 }

 private void stopRecorder() {
 if (mMediaRecorder != null) {
  try {
  mMediaRecorder.stop();
  } catch (Exception e) {
  e.printStackTrace();
  LogUtils.i(e);
  }

 }
 }

 public boolean isSupportFrontCamera() {
 return isSupportFrontCamera;
 }

 public boolean isSupportFlashCamera() {
 return isSupportFlashCamera;
 }

 public boolean isCameraFrontFacing() {
 return cameraFacing == Camera.CameraInfo.CAMERA_FACING_FRONT;
 }

 /**
 * 设置对焦类型
 * @param cameraType
 */
 public void setCameraType(int cameraType) {
 this.cameraType = cameraType;
 if (mCamera != null) {//拍摄视频时
  if (cameraFacing == Camera.CameraInfo.CAMERA_FACING_BACK) {
  Camera.Parameters parameters = mCamera.getParameters();
  List<String> focusModes = parameters.getSupportedFocusModes();
  if (focusModes != null) {
   if (cameraType == 0) {
   if (focusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
    parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
   }
   } else {
   if (focusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) {
    parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
   }
   }
  }
  }
 }
 }

 public int getCameraFlash() {
 return cameraFlash;
 }

 /**
 * 对焦
 * @param x
 * @param y
 */
 public void handleFocusMetering(float x, float y) {
 if(mCamera!=null){
  Camera.Parameters params = mCamera.getParameters();
  Camera.Size previewSize = params.getPreviewSize();
  Rect focusRect = calculateTapArea(x, y, 1f, previewSize);
  Rect meteringRect = calculateTapArea(x, y, 1.5f, previewSize);
  mCamera.cancelAutoFocus();

  if (params.getMaxNumFocusAreas() > 0) {
  List<Camera.Area> focusAreas = new ArrayList<>();
  focusAreas.add(new Camera.Area(focusRect, 1000));
  params.setFocusAreas(focusAreas);
  } else {
  LogUtils.i("focus areas not supported");
  }
  if (params.getMaxNumMeteringAreas() > 0) {
  List<Camera.Area> meteringAreas = new ArrayList<>();
  meteringAreas.add(new Camera.Area(meteringRect, 1000));
  params.setMeteringAreas(meteringAreas);
  } else {
  LogUtils.i("metering areas not supported");
  }
  final String currentFocusMode = params.getFocusMode();
  params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
  mCamera.setParameters(params);

  mCamera.autoFocus(new Camera.AutoFocusCallback() {
  @Override
  public void onAutoFocus(boolean success, Camera camera) {
   Camera.Parameters params = camera.getParameters();
   params.setFocusMode(currentFocusMode);
   camera.setParameters(params);
  }
  });
 }

 }

 private Rect calculateTapArea(float x, float y, float coefficient, Camera.Size previewSize) {
 float focusAreaSize = 300;
 int areaSize = Float.valueOf(focusAreaSize * coefficient).intValue();
 int centerX = (int) (x / previewSize.width - 1000);
 int centerY = (int) (y / previewSize.height - 1000);
 int left = clamp(centerX - areaSize / 2, -1000, 1000);
 int top = clamp(centerY - areaSize / 2, -1000, 1000);
 RectF rectF = new RectF(left, top, left + areaSize, top + areaSize);
 return new Rect(Math.round(rectF.left), Math.round(rectF.top), Math.round(rectF.right), Math.round(rectF.bottom));
 }

 private int clamp(int x, int min, int max) {
 if (x > max) {
  return max;
 }
 if (x < min) {
  return min;
 }
 return x;
 }

}

自定义拍摄,拍照按钮:

package com.ses.im.app.chat.newcamera;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.os.Bundle;
import android.os.Parcelable;
import android.support.v4.view.GestureDetectorCompat;
import android.support.v4.view.MotionEventCompat;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;

import com.ses.im.app.chat.R;

/**
 * 自定义拍照,拍摄按钮
 */

public class CameraProgressBar extends View {
 /**
 * 默认缩小值
 */
 public static final float DEF_SCALE = 0.75F;
 /**
 * 默认缩小值
 */
 private float scale = DEF_SCALE;

 /**
 * 内圆颜色
 */
 private int innerColor = Color.GRAY;
 /**
 * 背景颜色
 */
 private int backgroundColor = Color.WHITE;
 /**
 * 外圆颜色
 */
 private int outerColor = Color.parseColor("#e9e9e9");
 /**
 * 进度颜色
 */
 private int progressColor = Color.parseColor("#0ebffa");
 /**
 * 进度宽
 */
 private int progressWidth = 15;
 /**
 * 内圆宽度
 */
 private int innerRadio = 10;
 /**
 * 进度
 */
 private int progress;
 /**
 * 最大进度
 */
 private int maxProgress = 100;
 /**
 * paint
 */
 private Paint backgroundPaint, progressPaint, innerPaint;
 /**
 * 圆的中心坐标点, 进度百分比
 */
 private float sweepAngle;
 /**
 * 手识识别
 */
 private GestureDetectorCompat mDetector;
 /**
 * 是否为长按录制
 */
 private boolean isLongClick;
 /**
 * 是否产生滑动
 */
 private boolean isBeingDrag;
 /**
 * 滑动单位
 */
 private int mTouchSlop;
 /**
 * 记录上一次Y轴坐标点
 */
 private float mLastY;
 /**
 * 是否长按放大
 */
 private boolean isLongScale;

 public CameraProgressBar(Context context) {
 super(context);
 init(context, null);
 }

 public CameraProgressBar(Context context, AttributeSet attrs) {
 super(context, attrs);
 init(context, attrs);
 }

 public CameraProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
 super(context, attrs, defStyleAttr);
 init(context, attrs);
 }

 private void init(Context context, AttributeSet attrs) {
 mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
 if (attrs != null) {
  TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CameraProgressBar);
  innerColor = a.getColor(R.styleable.CameraProgressBar_innerColor, innerColor);
  outerColor = a.getColor(R.styleable.CameraProgressBar_outerColor, outerColor);
  progressColor = a.getColor(R.styleable.CameraProgressBar_progressColor, progressColor);
  innerRadio = a.getDimensionPixelOffset(R.styleable.CameraProgressBar_innerRadio, innerRadio);
  progressWidth = a.getDimensionPixelOffset(R.styleable.CameraProgressBar_progressWidth, progressWidth);
  progress = a.getInt(R.styleable.CameraProgressBar_progresscamera, progress);
  scale = a.getFloat(R.styleable.CameraProgressBar_scale, scale);
  isLongScale = a.getBoolean(R.styleable.CameraProgressBar_isLongScale, isLongScale);
  maxProgress = a.getInt(R.styleable.CameraProgressBar_maxProgress, maxProgress);
  a.recycle();
 }
 backgroundPaint = new Paint();
 backgroundPaint.setAntiAlias(true);
 backgroundPaint.setColor(backgroundColor);

 progressPaint = new Paint();
 progressPaint.setAntiAlias(true);
 progressPaint.setStrokeWidth(progressWidth);
 progressPaint.setStyle(Paint.Style.STROKE);

 innerPaint = new Paint();
 innerPaint.setAntiAlias(true);
 innerPaint.setStrokeWidth(innerRadio);
 innerPaint.setStyle(Paint.Style.STROKE);

 sweepAngle = ((float) progress / maxProgress) * 360;

 mDetector = new GestureDetectorCompat(context, new GestureDetector.SimpleOnGestureListener() {
  @Override
  public boolean onSingleTapConfirmed(MotionEvent e) {
  isLongClick = false;
  if (CameraProgressBar.this.listener != null) {
   CameraProgressBar.this.listener.onClick(CameraProgressBar.this);
  }
  return super.onSingleTapConfirmed(e);
  }

  @Override
  public void onLongPress(MotionEvent e) {
  isLongClick = true;
  postInvalidate();
  mLastY = e.getY();
  if (CameraProgressBar.this.listener != null) {
   CameraProgressBar.this.listener.onLongClick(CameraProgressBar.this);
  }
  }
 });
 mDetector.setIsLongpressEnabled(true);
 }

 @Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
 super.onMeasure(widthMeasureSpec, heightMeasureSpec);
 int width = MeasureSpec.getSize(widthMeasureSpec);
 int height = MeasureSpec.getSize(heightMeasureSpec);
 if (width > height) {
  setMeasuredDimension(height, height);
 } else {
  setMeasuredDimension(width, width);
 }
 }

 @Override
 protected void onDraw(Canvas canvas) {
 super.onDraw(canvas);
 int width = getWidth();
 float circle = width / 2.0f;

 if (/*isLongScale && */!isLongClick) {
  canvas.scale(scale, scale, circle, circle);
 }

 //画内圆
 float backgroundRadio = circle - progressWidth - innerRadio;
 canvas.drawCircle(circle, circle, backgroundRadio, backgroundPaint);

 //画内外环
 float halfInnerWidth = innerRadio / 2.0f + progressWidth;
 RectF innerRectF = new RectF(halfInnerWidth, halfInnerWidth, width - halfInnerWidth, width - halfInnerWidth);
 canvas.drawArc(innerRectF, -90, 360, true, innerPaint);

 progressPaint.setColor(outerColor);
 float halfOuterWidth = progressWidth / 2.0f;
 RectF outerRectF = new RectF(halfOuterWidth, halfOuterWidth, getWidth() - halfOuterWidth, getWidth() - halfOuterWidth);
 canvas.drawArc(outerRectF, -90, 360, true, progressPaint);

 progressPaint.setColor(progressColor);
 canvas.drawArc(outerRectF, -90, sweepAngle, false, progressPaint);
 }

 @Override
 public boolean onTouchEvent(MotionEvent event) {
 if (!isLongScale) {
  return super.onTouchEvent(event);
 }
 this.mDetector.onTouchEvent(event);
 switch(MotionEventCompat.getActionMasked(event)) {
  case MotionEvent.ACTION_DOWN:
  isLongClick = false;
  isBeingDrag = false;
  break;
  case MotionEvent.ACTION_MOVE:
  if (isLongClick) {
   float y = event.getY();
   if (isBeingDrag) {
   boolean isUpScroll = y < mLastY;
   mLastY = y;
   if (this.listener != null) {
    this.listener.onZoom(isUpScroll);
   }
   } else {
   isBeingDrag = Math.abs(y - mLastY) > mTouchSlop;
   }
  }
  break;
  case MotionEvent.ACTION_UP:
  case MotionEvent.ACTION_CANCEL:
  isBeingDrag = false;
  if (isLongClick) {
   isLongClick = false;
   postInvalidate();
   if (this.listener != null) {
   this.listener.onLongClickUp(this);
   }
  }
  break;
  case MotionEvent.ACTION_POINTER_DOWN:
  if (isLongClick) {
   if (this.listener != null) {
   this.listener.onPointerDown(event.getRawX(), event.getRawY());
   }
  }
  break;
 }
 return true;
 }

 @Override
 protected Parcelable onSaveInstanceState() {
 Bundle bundle = new Bundle();
 Parcelable superData = super.onSaveInstanceState();
 bundle.putParcelable("superData", superData);
 bundle.putInt("progress", progress);
 bundle.putInt("maxProgress", maxProgress);
 return bundle;
 }

 @Override
 protected void onRestoreInstanceState(Parcelable state) {
 Bundle bundle = (Bundle) state;
 Parcelable superData = bundle.getParcelable("superData");
 progress = bundle.getInt("progress");
 maxProgress = bundle.getInt("maxProgress");
 super.onRestoreInstanceState(superData);
 }

 /**
 * 设置进度
 * @param progress
 */
 public void setProgress(int progress) {
 if (progress <= 0) progress = 0;
 if (progress >= maxProgress) progress = maxProgress;
 if (progress == this.progress) return;
 this.progress = progress;
 this.sweepAngle = ((float) progress / maxProgress) * 360;
 postInvalidate();
 }

 /**
 * 还原到初始状态
 */
 public void reset() {
 isLongClick = false;
 this.progress = 0;
 this.sweepAngle = 0;
 postInvalidate();
 }

 public int getProgress() {
 return progress;
 }

 public void setLongScale(boolean longScale) {
 isLongScale = longScale;
 }

 public void setMaxProgress(int maxProgress) {
 this.maxProgress = maxProgress;
 }

 private OnProgressTouchListener listener;

 public void setOnProgressTouchListener(OnProgressTouchListener listener) {
 this.listener = listener;
 }

 /**
 * 进度触摸监听
 */
 public interface OnProgressTouchListener {
 /**
  * 单击
  * @param progressBar
  */
 void onClick(CameraProgressBar progressBar);

 /**
  * 长按
  * @param progressBar
  */
 void onLongClick(CameraProgressBar progressBar);

 /**
  * 移动
  * @param zoom true放大
  */
 void onZoom(boolean zoom);

 /**
  * 长按抬起
  * @param progressBar
  */
 void onLongClickUp(CameraProgressBar progressBar);

 /**
  * 触摸对焦
  * @param rawX
  * @param rawY
  */

 void onPointerDown(float rawX, float rawY);
 }

}

预览试图页:

package com.ses.im.app.chat.newcamera;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.support.v4.view.MotionEventCompat;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewParent;

import java.util.concurrent.TimeUnit;

import rx.Observable;
import rx.Subscriber;
import rx.Subscription;

/**
 * 相机预览页
 */

public class CameraView extends View {
 /**
 * 动画时长
 */
 private static final int ANIM_MILS = 600;
 /**
 * 动画每多久刷新一次
 */
 private static final int ANIM_UPDATE = 30;
 /**
 * focus paint
 */
 private Paint paint, clearPaint;

 private int paintColor = Color.GREEN;
 /**
 * 进度订阅
 */
 private Subscription subscription;
 /**
 * focus rectf
 */
 private RectF rectF = new RectF();
 /**
 * focus size
 */
 private int focusSize = 120;

 private int lineSize = focusSize / 4;
 /**
 * 上一次两指距离
 */
 private float oldDist = 1f;
 /**
 * 画笔宽
 */
 private float paintWidth = 6.0f;
 /**
 * s
 */
 private float scale;

 public CameraView(Context context) {
 super(context);
 init();
 }

 public CameraView(Context context, AttributeSet attrs) {
 super(context, attrs);
 init();
 }

 public CameraView(Context context, AttributeSet attrs, int defStyleAttr) {
 super(context, attrs, defStyleAttr);
 init();
 }

 private void init() {
 paint = new Paint();
 paint.setColor(paintColor);
 paint.setStyle(Paint.Style.STROKE);
 paint.setStrokeWidth(paintWidth);

 clearPaint = new Paint();
 clearPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
 }

 @Override
 public boolean onTouchEvent(MotionEvent event) {
 int action = MotionEventCompat.getActionMasked(event);
 if (event.getPointerCount() == 1 && action == MotionEvent.ACTION_DOWN) {
  float x = event.getX();
  float y = event.getY();
  setFoucsPoint(x, y);
  if (listener != null) {
  listener.handleFocus(x, y);
  }
 } else if (event.getPointerCount() >= 2){
  switch (event.getAction() & MotionEvent.ACTION_MASK) {
  case MotionEvent.ACTION_POINTER_DOWN:
   oldDist = getFingerSpacing(event);
   break;
  case MotionEvent.ACTION_MOVE:
   float newDist = getFingerSpacing(event);
   if (newDist > oldDist) {
   if (this.listener != null) {
    this.listener.handleZoom(true);
   }
   } else if (newDist < oldDist) {
   if (this.listener != null) {
    this.listener.handleZoom(false);
   }
   }
   oldDist = newDist;
   break;
  }
 }
 return true;
 }

 /**
 * 计算两点触控距离
 * @param event
 * @return
 */
 private float getFingerSpacing(MotionEvent event) {
 float x = event.getX(0) - event.getX(1);
 float y = event.getY(0) - event.getY(1);
 return (float) Math.sqrt(x * x + y * y);
 }

 /**
 * 设置坐标点(坐标为rawX, rawY)
 */
 public void setFoucsPoint(PointF pointF) {
 PointF transPointF = transPointF(pointF, this);
 setFoucsPoint(transPointF.x, transPointF.y);
 }

 /**
 * 设置当前触摸点
 * @param x
 * @param y
 */
 private void setFoucsPoint(float x, float y) {
 if (subscription != null) {
  subscription.unsubscribe();
 }
 rectF.set(x - focusSize, y - focusSize, x + focusSize, y + focusSize);
 final int count = ANIM_MILS / ANIM_UPDATE;
 subscription = Observable.interval(ANIM_UPDATE, TimeUnit.MILLISECONDS).take(count).subscribe(new Subscriber<Long>() {
  @Override
  public void onCompleted() {
  scale = 0;
  postInvalidate();
  }

  @Override
  public void onError(Throwable e) {
  scale = 0;
  postInvalidate();
  }

  @Override
  public void onNext(Long aLong) {
  float current = aLong== null ? 0 : aLong.longValue();
  scale = 1 - current / count;
  if (scale <= 0.5f) {
   scale = 0.5f;
  }
  postInvalidate();
  }
 });
 }

 @Override
 protected void onDraw(Canvas canvas) {
 super.onDraw(canvas);
 if (scale != 0) {
  float centerX = rectF.centerX();
  float centerY = rectF.centerY();
  canvas.scale(scale, scale, centerX, centerY);
  canvas.drawRect(rectF, paint);
  canvas.drawLine(rectF.left, centerY, rectF.left + lineSize, centerY, paint);
  canvas.drawLine(rectF.right, centerY, rectF.right - lineSize, centerY, paint);
  canvas.drawLine(centerX, rectF.top, centerX, rectF.top + lineSize, paint);
  canvas.drawLine(centerX, rectF.bottom, centerX, rectF.bottom - lineSize, paint);
 }
 }

 @Override
 protected void onDetachedFromWindow() {
 super.onDetachedFromWindow();
 if (subscription != null) {
  subscription.unsubscribe();
 }
 }

 /**
 * 根据raw坐标转换成屏幕中所在的坐标
 * @param pointF
 * @return
 */
 private PointF transPointF(PointF pointF, View view) {
 pointF.x -= view.getX();
 pointF.y -= view.getY();
 ViewParent parent = view.getParent();
 if (parent instanceof View) {
  return transPointF(pointF, (View) parent);
 } else {
  return pointF;
 }
 }

 private OnViewTouchListener listener;

 public void setOnViewTouchListener(OnViewTouchListener listener) {
 this.listener = listener;
 }

 public void removeOnZoomListener() {
 this.listener = null;
 }

 public interface OnViewTouchListener {
 /**
  * 对焦
  * @param x
  * @param y
  */
 void handleFocus(float x, float y);

 /**
  * 缩放
  * @param zoom true放大反之
  */
 void handleZoom(boolean zoom);

 }

}

视频管理类:

package com.ses.im.app.chat.newcamera;

import android.app.Application;
import android.media.MediaPlayer;
import android.view.Surface;

/**
* Created by you on 2016/10/24.
* 由于拍摄跟播放都关联TextureView,停止播放时要释放mediaplayer
*/

public class MediaPlayerManager {

private Application app;

private MediaPlayer mPlayer;

private MediaPlayerManager(Application app) {
 this.app = app;
}

private static MediaPlayerManager INSTANCE;

public static MediaPlayerManager getInstance(Application app) {
 if (INSTANCE == null) {
 synchronized (CameraManager.class) {
  if (INSTANCE == null) {
  INSTANCE = new MediaPlayerManager(app);
  }
 }
 }
 return INSTANCE;
}

/**
 * 播放Media
 */
public void playMedia(Surface surface, String mediaPath) {
 try {
 if (mPlayer == null) {
  mPlayer = new MediaPlayer();
  mPlayer.setDataSource(mediaPath);
 } else {
  if (mPlayer.isPlaying()) {
  mPlayer.stop();
  }
  mPlayer.reset();
  mPlayer.setDataSource(mediaPath);
 }
 mPlayer.setSurface(surface);
 mPlayer.setLooping(true);
 mPlayer.prepareAsync();
 mPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
  @Override
  public void onPrepared(MediaPlayer mp) {
  mp.start();
  }
 });
 } catch (Exception e) {
 LogUtils.i(e);
 }
}

/**
 * 停止播放Media
 */
public void stopMedia() {
 try {
 if (mPlayer != null) {
  if (mPlayer.isPlaying()) {
  mPlayer.stop();
  }
  mPlayer.release();
  mPlayer = null;
 }
 } catch (Exception e) {
 LogUtils.i(e);
 }
}

}

由于本人上传的demo被csdn弄丢了,想要做微信相机的可以参考陈嘉桐的demo

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

(0)

相关推荐

  • Android 照相机的实例应用

    Android 照相机的实例应用 关键技术: SurfaceHolder.Callback public class MyCameraDemo extends Activity { private SurfaceView surface = null ; private Button but = null ; private SurfaceHolder holder = null ; private Camera cam = null ; private boolean previewRunni

  • Android 用 camera2 API 自定义相机

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

  • android 7自定义相机预览及拍照功能

    本文实例为大家分享了Android实现摄像头切换,拍照及保存到相册,预览等功能,解决android7拍照之后不能连续预览的问题.参数设置相关问题以及前后摄像头语言颠倒等问题. import android.Manifest; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; imp

  • Android如何调用系统相机拍照

    本文实例为大家分享了Android调用系统相机拍照的具体代码,供大家参考,具体内容如下 /** * 调用系统相机 */ private void takePhoto() { Uri uri = null; if (which_image == FRONT_IMAGE) { frontFile = new File(getSDPath() +"/test/front_" + getDate() + ".jpg"); uri = Uri.fromFile(frontFi

  • Android自定义照相机的实例

    Android自定义照相机实现 近期小巫在学校有一个创新项目,也不是最近,是一个拖了很久的项目,之前一直没有去搞,最近因为要中期检查,搞得我跟小组成员一阵忙活,其实开发一款照相机软件并不太难,下面就是通过自定义的方式来实现手机照相的功能. 创建一个项目:FingerTakePicture 首先来搞一下界面: <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools=&qu

  • Android相机启动加速详解

    在Android上实现一个简单能用的相机其实挺容易.谷歌随便搜一搜就有很多能用的Sample.当然就像谷歌能搜到的其他代码一样,这些Sample虽然能用但离好用还很远. 这篇文章就只说说从用户点击启动按钮到用户能看到实时预览的这一小段时间内,我们所做的优化. Android手机上良莠不齐的硬件,导致相机启动时间有长有短,很难预期.用户在使用app过程中,过长的等待会产生焦虑.我们要做的就是让用户尽量感知不到相机启动的耗时. 按照网上能搜到的一般相机Sample的说法,从启动相机到实时预览,我们需

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

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

  • Android调用系统照相机拍照与摄像的方法

    前言 在很多场景中,都需要用到摄像头去拍摄照片或视频,在照片或视频的基础之上进行处理.但是Android系统源码是开源的,很多设备厂商均可使用,并且定制比较混乱.一般而言,在需要用到摄像头拍照或摄像的时候,均会直接调用系统现有的相机应用,去进行拍照或摄像,我们只取它拍摄的结果进行处理,这样避免了不同设备的摄像头的一些细节问题.本篇博客将介绍在Android应用中,如何调用系统现有的相机应用去拍摄照片与短片,并对其进行处理,最后均会以一个简单的Demo来演示效果. 1.系统现有相机应用的调用 对于

  • Android开源库自定义相机模块

    简介 相机模块库,自定义相机,通过简单的调用即可实现拍照.图片裁剪.录像及录像抓拍功能: 实现图片压缩,减少图片体积:自定义相机可避免使用系统相机导致的照片或视频体积过大问题: 内置相机及sd卡权限获取的处理: github链接如下,帮忙star支持下~ github链接 实现功能: - 拍照 - 图片裁剪 - 录像 - 录像抓拍 在项目中导入该库 在工程的 build.gradle中加入: allprojects { repositories { ... maven { url "https:

  • Android仿最新微信相机功能

    最近在开发即时通讯这个模块的时候使用到了自定义的相机,需求与微信一样,要求相机能长按和轻点,当时在网上找自定义相机的资源,很少,所以,我在这里把我的一些开发经验贴出来,供大家学习. 大致完成的功能如下: 长按拍摄视频,轻点拍照 前后摄像头的切换 闪光的的开启,关闭,自动 图片的压缩 自动聚焦,手动聚焦 效果图如下: 相关代码如下: package com.ses.im.app.chat.newcamera; import android.app.Activity; import android.

  • Android仿支付宝微信支付密码界面弹窗封装dialog

    一,功能效果 二,实现过程 1,先写xml文件:dialog_keyboard.xml 注意事项 (1),密码部分用的是一个线性布局中6个TextView,并设置android:inputType="numberPassword",外框是用的一个有stroke属性的shape, (2),1-9数字是用的recycleview ,每个item的底部和右边有1dp的黑线,填充后形成分割线. (3),recycleview 要设置属性  android:overScrollMode=&quo

  • Android 仿微博的点赞功能的实现原理(持续点赞再取消)

    产品需求,实现类似微博的持续点赞再取消功能,因为自己也偶尔刷微博,对这功能有一定的使用上的了解, 至于微博点赞的具体实现我并不知道,微博点赞在断网的情况下依然能点赞,不会提示网络异常,等有网络之后 重新刷新,实际是没有点赞的,那就针对这现象去实现吧. 避免并发,减少CPU压力,我个人会想到 HandlerThread ,不懂可以自行科普,这里只说我实现的点赞功能原理. private Timer mTimer;//定时器 private TimerTask mTask; mMap = new H

  • Android仿新版微信浮窗效果

    阅读公众号或其他文章,经常需要暂时退出文章. 在新版微信中,可以把浏览的文章缩小为浮窗.点击浮窗继续阅读.对于经常在微信里阅读的人来说,这简直就是人类之光. 微信效果如下 微信效果 对于这功能我进行了仿写. 效果如下 仿写效果 微信的大佬一定用了了不起的技术,我这里只是实现效果. 简单写了一个库,一句代码即可实现效果 github.com/SherlockQi/- //在AppDelegate中将类名传入即可 [HKFloatManager addFloatVcs:@[@"HKSecondVie

  • Android仿QQ微信未读消息小红点BadgeHelper

    Android 小红点 未读消息功能 BadgeHelper 因为最近的项目需求,翻遍github上的未读消息红点开源库, 发现大部分 不能适配不同情况的布局, 所以我写了一个能兼容全部的 ! 网上的写法是 继承TextView然后生成一个小红点drawable,设置到背景中去, 然后把目标view外层加一层FrameLayout,然后把小红点添加进去 但这样做的问题来了, 小红点与目标View 会叠起来!, 挡住文字,!!! 看得我瞎了~~~ 而且 他们提供的setOffsetX setpad

  • Android仿知乎悬浮功能按钮FloatingActionButton效果

    前段时间在看属性动画,恰巧这个按钮的效果可以用属性动画实现,所以就来实践实践.效果基本出来了,大家可以自己去完善. 首先看一下效果图: 我们看到点击FloatingActionButton后会展开一些item,然后会有一个蒙板效果,这都是这个View的功能.那么这整个View肯定是个ViewGroup,我们一部分一部分来看. 首先是这个最小的Tag: 这个Tag带文字,可以是一个TextView,但为了美观,我们使用CardView,CardView是一个FrameLayout,我们要让它具有显

  • Android仿音乐播放器功能

    本文实例为大家分享了Android仿音乐播放器功能的具体代码,供大家参考,具体内容如下 读取本地音乐文件 源代码: import android.media.MediaPlayer; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.ImageButton; import android.widget.

  • Android仿打开微信红包动画效果实现代码

    首先看下效果: 实现原理: 准备3张不同角度的图片,通过AnimationDrawable帧动画进行播放即可 代码实现: 1.编写动画xml文件: <?xml version="1.0" encoding="utf-8"?> <animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false&

  • Android仿QQ微信侧滑删除效果

    仿QQ侧滑删除效果图 1.自定义listview public class DragDelListView extends ListView { private boolean moveable=false; private boolean closed=true; private float mDownX,mDownY; private int mTouchPosition,oldPosition=-1; private DragDelItem mTouchView,oldView; priv

  • Android仿百度图片查看功能

    我们知道,进入百度图片后,输入一个关键字后,首先看到的是很多缩略图,当我们点击某张缩略图时,我们就可以进入到大图显示页面,在大图显示页面,中包含了一个图片画廊,同时当前大图为刚刚我们点击的那张图片.现在我们看看在Android中如何实现类似的效果: 首先,我们需要有一个控件来显示缩略图,这里没有什么比GridView更加合适了. 配置文件如下: <?xml version="1.0" encoding="utf-8"?> <LinearLayout

随机推荐