版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/bbtianshi/article/details/82152032
下面是对应的三个布局
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/btn_openCamera2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="打开Camera2" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:layout_marginTop="15dp"
android:layout_below="@+id/btn_openCamera2"
android:textSize="15sp"
android:text="开启前请确保已经获取了相关权限:拍照,录音,存储这三个权限"/>
</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".Camera2RecordActivity">
<TextureView
android:id="@+id/textureView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.example.yidoucoltdred.myapplication.ProgressView
android:id="@+id/progressView"
android:layout_width="match_parent"
android:visibility="gone"
android:layout_height="3dp" />
<RelativeLayout
android:id="@+id/rl_takePhoto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="45dp"
android:paddingLeft="38dp"
android:paddingRight="38dp">
<ImageView
android:id="@+id/iv_takePhoto"
android:layout_width="76dp"
android:layout_height="76dp"
android:layout_centerInParent="true"
android:background="@drawable/ic_capture_btn" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/iv_takePhoto"
android:layout_centerHorizontal="true"
android:layout_marginTop="25dp"
android:text="单击拍照,长按录像"
android:textColor="@color/white"
android:textSize="12sp" />
<ImageView
android:id="@+id/iv_switchCamera"
android:layout_width="28dp"
android:layout_height="28dp"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:background="@drawable/ic_capture_switch" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/rl_time"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="11dp"
android:layout_marginRight="11dp"
android:layout_marginTop="15dp">
<ImageView
android:id="@+id/iv_close"
android:layout_width="22dp"
android:layout_height="22dp"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:background="@drawable/ic_capture_delete" />
<TextView
android:id="@+id/tv_balanceTime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text=""
android:textColor="@color/white"
android:textSize="15sp" />
<ImageView
android:id="@+id/iv_lightOn"
android:layout_width="27dp"
android:layout_height="27dp"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:background="@drawable/selector_capture_light" />
</RelativeLayout>
</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".Camera2RecordFinishActivity">
<ImageView
android:id="@+id/iv"
android:layout_width="match_parent"
android:layout_height="250dp"
android:scaleType="centerCrop"
android:layout_centerInParent="true"/>
<TextView
android:id="@+id/tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:textColor="@color/black"
android:textSize="15dp"/>
<Button
android:id="@+id/btn"
android:text="上传图片"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:layout_below="@id/btn"
android:id="@+id/btn2"
android:text="上传视频"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</RelativeLayout>
下面是对应的三个activity 第一个mainactivity就一个button点击跳转
public class MainActivity extends AppCompatActivity {
private Button btnOpenCamera2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnOpenCamera2=findViewById(R.id.btn_openCamera2);
//配置Camera2相关参数,
Camera2Config.RECORD_MAX_TIME = 10;
Camera2Config.RECORD_MIN_TIME=2;
Camera2Config.RECORD_PROGRESS_VIEW_COLOR=R.color.colorAccent;
Camera2Config.PREVIEW_MAX_HEIGHT=1300;
Camera2Config.PATH_SAVE_VIDEO= Environment.getExternalStorageDirectory().getAbsolutePath() + "/Camera/";
Camera2Config.PATH_SAVE_PIC= Environment.getExternalStorageDirectory().getAbsolutePath() + "/Camera/CameraV/";
Camera2Config.ENABLE_CAPTURE=true;
Camera2Config.ENABLE_CAPTURE=true;
Camera2Config.ACTIVITY_AFTER_CAPTURE = Camera2RecordFinishActivity.class;
btnOpenCamera2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Camera2RecordActivity.start(MainActivity.this);
// Intent intent = new Intent(MainActivity.this,Camera2RecordActivity.class);
// startActivity(intent);
}
});
}
}
第二个是对应的传回来展示 对应的地址保存
public class Camera2RecordFinishActivity extends AppCompatActivity {
private String picPath;//图片地址
private String videoPath;//视频地址
private ImageView iv;
private TextView tv;
String savedFile;
Button btn,btn2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//全屏模式
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_camera2_record_finish);
iv = findViewById(R.id.iv);
tv = findViewById(R.id.tv);
btn=findViewById(R.id.btn);
btn2=findViewById(R.id.btn2);
if (getIntent() != null) {
//获取传递过来的图片地址
picPath = getIntent().getStringExtra(Camera2Config.INTENT_PATH_SAVE_PIC);
if (TextUtils.isEmpty(picPath)) {
iv.setVisibility(View.GONE);
} else {
iv.setImageBitmap(BitmapFactory.decodeFile(picPath));
// SPUtils.setParam(this,"pic",picPath);
Log.e("haoshi", "onCreate: "+picPath);
}
// 获取传递过来的视频地址
videoPath = getIntent().getStringExtra(Camera2Config.INTENT_PATH_SAVE_VIDEO);
// Toast.makeText(this,"lujing"+videoPath,Toast.LENGTH_LONG);
if (TextUtils.isEmpty(videoPath)) {
tv.setVisibility(View.GONE);
} else {
tv.setText("存放地址:" + videoPath );
// SPUtils.setParam(this,"name",videoPath);
Log.d("s======", "onCreate: "+videoPath);
}
}
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
}
});
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(Camera2RecordFinishActivity.this,"好使", Toast.LENGTH_LONG).show();
// postGoodsPicToServers();
}
});
}
}
第三个对应的是拍照,的逻辑
public class Camera2RecordActivity extends AppCompatActivity implements TextureView.SurfaceTextureListener {
//views
private TextureView mTextureView;
private TextView tvBalanceTime;//录制剩余时间
private ImageView ivTakePhoto;//拍照&录像按钮
private ImageView ivSwitchCamera;//切换前后摄像头
private ImageView ivLightOn;//开关闪光灯
private ImageView ivClose;//关闭该Activity
private ProgressView mProgressView;//录像进度条
//拍照方向
private static final SparseIntArray ORIENTATION = new SparseIntArray();
static {
ORIENTATION.append(Surface.ROTATION_0, 90);
ORIENTATION.append(Surface.ROTATION_90, 0);
ORIENTATION.append(Surface.ROTATION_180, 270);
ORIENTATION.append(Surface.ROTATION_270, 180);
}
//constant
private static final String TAG = "Camera2RecordActivity";
private static final int PERMISSIONS_REQUEST = 1;//拍照完成回调
private static final int CAPTURE_OK = 0;//拍照完成回调
private String mCameraId;//后置摄像头ID
private String mCameraIdFront;//前置摄像头ID
private Size mPreviewSize;//预览的Size
private Size mCaptureSize;//拍照Size
private int width;//TextureView的宽
private int height;//TextureView的高
private boolean isCameraFront = false;//当前是否是前置摄像头
private boolean isLightOn = false;//当前闪光灯是否开启
//Camera2
private CameraDevice mCameraDevice;
private CaptureRequest.Builder mPreviewBuilder;
private CaptureRequest mCaptureRequest;
private CameraCaptureSession mPreviewSession;
private CameraCharacteristics characteristics;
private ImageReader mImageReader;
private int mSensorOrientation;
private String picSavePath;//图片保存路径
private String videoSavePath;//视频保存路径
//handler
private HandlerThread mCameraThread;
private Handler mCameraHandler;
private LongPressRunnable longPressRunnable;//长按后处理的逻辑Runnable
//录像
private static final int MAX_RECORD_TIME = Camera2Config.RECORD_MAX_TIME;//最大录制时长,默认10S
private static final int MIN_RECORD_TIME = Camera2Config.RECORD_MIN_TIME;//最小录制时长,默认2S
private boolean isRecording = false;//是否正在录制视频
private boolean isStop = false;//是否停止过了MediaRecorder
private int currentTime;
private MediaRecorder mMediaRecorder;
//自定义调转
public static void start(Context context) {
Intent intent = new Intent(context, Camera2RecordActivity.class);
context.startActivity(intent);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//全屏模式
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
//透明导航栏
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
setContentView(R.layout.activity_camera2_record);
initViews();
initTextureView();
}
/**
* **************************************初始化相关**********************************************
*/
//初始化TextureView
private void initTextureView() {
mCameraThread = new HandlerThread("CameraThread");
mCameraThread.start();
mCameraHandler = new Handler(mCameraThread.getLooper());
mTextureView.setSurfaceTextureListener(this);
}
//初始化视图控件
private void initViews() {
mTextureView = findViewById(R.id.textureView);
tvBalanceTime = findViewById(R.id.tv_balanceTime);
ivTakePhoto = findViewById(R.id.iv_takePhoto);
ivSwitchCamera = findViewById(R.id.iv_switchCamera);
ivLightOn = findViewById(R.id.iv_lightOn);
ivClose = findViewById(R.id.iv_close);
mProgressView = findViewById(R.id.progressView);
ivSwitchCamera.setOnClickListener(clickListener);
ivLightOn.setOnClickListener(clickListener);
ivClose.setOnClickListener(clickListener);
//触摸事件
onTouchListner();
}
View.OnClickListener clickListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
int i = view.getId();
if (i == R.id.iv_switchCamera) {
//切换摄像头
switchCamera();
} else if (i == R.id.iv_lightOn) {
//开启关闭闪光灯
openLight();
} else if (i == R.id.iv_close) {
//关闭Activity
// finish();
// Intent intent = new Intent(Camera2RecordActivity.this,NewDecetorActivity.class);
// startActivity(intent);
}
}
};
//拍照按钮触摸事件
private void onTouchListner() {
longPressRunnable = new LongPressRunnable();
ivTakePhoto.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
isRecording = false;
mCameraHandler.postDelayed(longPressRunnable, 500);//同时延长500启动长按后处理的逻辑Runnable
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
//根据当前按钮的状态进行相应的处理
handlerUnpressByState();
break;
}
return true;
}
});
mTextureView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent event) {
//两指缩放
changeZoom(event);
return true;
}
});
}
//长按线程
private class LongPressRunnable implements Runnable {
@Override
public void run() {
//判断是否需要录像功能
if (Camera2Config.ENABLE_RECORD) {
prepareMediaRecorder();
startButtonAnima();
isRecording = true; //如果按下后经过500毫秒则会修改当前状态为长按状态,标记为正在录制中
startMediaRecorder();//开始录制
}
}
}
//当手指松开按钮时候处理的逻辑
private void handlerUnpressByState() {
mCameraHandler.removeCallbacks(longPressRunnable);//移除长按逻辑的Runnable
//根据当前状态处理
if (isRecording) {
stopButtonAnima();
isRecording = false;
mCameraHandler.postDelayed(new Runnable() {
@Override
public void run() {
//停止录制,先判断是不是停止过了
if (!isStop) {
stopMediaRecorder();
}
}
}, 200);
} else {
isRecording = false;
//判断是否需要拍照功能
if (Camera2Config.ENABLE_CAPTURE) {
capture();
}
}
}
//开始按下按钮动画
public void startButtonAnima() {
AnimatorSet animatorSet = new AnimatorSet();//组合动画
ObjectAnimator scaleX = ObjectAnimator.ofFloat(ivTakePhoto, "scaleX", 1f, 1.3f);
ObjectAnimator scaleY = ObjectAnimator.ofFloat(ivTakePhoto, "scaleY", 1f, 1.3f);
animatorSet.setDuration(100);
animatorSet.setInterpolator(new LinearInterpolator());
animatorSet.play(scaleX).with(scaleY);//两个动画同时开始
animatorSet.start();
}
//停止按下按钮动画
public void stopButtonAnima() {
AnimatorSet animatorSet = new AnimatorSet();//组合动画
ObjectAnimator scaleX = ObjectAnimator.ofFloat(ivTakePhoto, "scaleX", 1.3f, 1f);
ObjectAnimator scaleY = ObjectAnimator.ofFloat(ivTakePhoto, "scaleY", 1.3f, 1f);
animatorSet.setDuration(100);
animatorSet.setInterpolator(new LinearInterpolator());
animatorSet.play(scaleX).with(scaleY);//两个动画同时开始
animatorSet.start();
}
/**
* ******************************SurfaceTextureListener*****************************************
*/
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) {
//当SurefaceTexture可用的时候,设置相机参数并打开相机
this.width = width;
this.height = height;
setupCamera(width, height);//配置相机参数
openCamera(mCameraId);//打开相机
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int i, int i1) {
configureTransform(width, height);
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
return false;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {
}
/**
* ******************************SetupCamera(配置Camera)*****************************************
*/
private void setupCamera(int width, int height) {
//获取摄像头的管理者CameraManager
CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
try {
//0表示后置摄像头,1表示前置摄像头
mCameraId = manager.getCameraIdList()[0];
mCameraIdFront = manager.getCameraIdList()[1];
//前置摄像头和后置摄像头的参数属性不同,所以这里要做下判断
if (isCameraFront) {
characteristics = manager.getCameraCharacteristics(mCameraIdFront);
} else {
characteristics = manager.getCameraCharacteristics(mCameraId);
}
//获取StreamConfigurationMap,它是管理摄像头支持的所有输出格式和尺寸
StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
mSensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
//选择预览尺寸
mPreviewSize = Camera2Util.getMinPreSize(map.getOutputSizes(SurfaceTexture.class), width, height, Camera2Config.PREVIEW_MAX_HEIGHT);
Log.e(TAG, mPreviewSize.getWidth() + "----" + mPreviewSize.getHeight());
Log.e(TAG, height + "----" + width);
//获取相机支持的最大拍照尺寸
mCaptureSize = Collections.max(Arrays.asList(map.getOutputSizes(ImageFormat.JPEG)), new Comparator<Size>() {
@Override
public int compare(Size lhs, Size rhs) {
return Long.signum(lhs.getWidth() * lhs.getHeight() - rhs.getHeight() * rhs.getWidth());
}
});
configureTransform(width, height);
//此ImageReader用于拍照所需
setupImageReader();
//MediaRecorder用于录像所需
mMediaRecorder = new MediaRecorder();
} catch (Exception e) {
e.printStackTrace();
}
}
//配置ImageReader
private void setupImageReader() {
//2代表ImageReader中最多可以获取两帧图像流
mImageReader = ImageReader.newInstance(mCaptureSize.getWidth(), mCaptureSize.getHeight(),
ImageFormat.JPEG, 2);
mImageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
@Override
public void onImageAvailable(ImageReader reader) {
Image mImage = reader.acquireNextImage();
ByteBuffer buffer = mImage.getPlanes()[0].getBuffer();
byte[] data = new byte[buffer.remaining()];
buffer.get(data);
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
Camera2Util.createSavePath(Camera2Config.PATH_SAVE_PIC);//判断有没有这个文件夹,没有的话需要创建
picSavePath = Camera2Config.PATH_SAVE_PIC + "IMG_" + timeStamp + ".jpg";
FileOutputStream fos = null;
try {
fos = new FileOutputStream(picSavePath);
fos.write(data, 0, data.length);
Message msg = new Message();
msg.what = CAPTURE_OK;
msg.obj = picSavePath;
mCameraHandler.sendMessage(msg);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
mImage.close();
}
}, mCameraHandler);
mCameraHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case CAPTURE_OK:
//这里拍照保存完成,可以进行相关的操作,例如再次压缩等(由于封装,这里我先跳转掉完成页面)
if (Camera2Config.ACTIVITY_AFTER_CAPTURE != null) {
Intent intent = new Intent(Camera2RecordActivity.this, Camera2Config.ACTIVITY_AFTER_CAPTURE);
intent.putExtra(Camera2Config.INTENT_PATH_SAVE_PIC, picSavePath);
startActivity(intent);
}
break;
}
}
};
}
/**
* ******************************openCamera(打开Camera)*****************************************
*/
private void openCamera(String CameraId) {
//获取摄像头的管理者CameraManager
CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
//检查权限
try {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
return;
}
//打开相机,第一个参数指示打开哪个摄像头,第二个参数stateCallback为相机的状态回调接口,第三个参数用来确定Callback在哪个线程执行,为null的话就在当前线程执行
manager.openCamera(CameraId, mStateCallback, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
@Override
public void onOpened(CameraDevice camera) {
mCameraDevice = camera;
startPreview();
if (null != mTextureView) {
configureTransform(mTextureView.getWidth(), mTextureView.getHeight());
}
}
@Override
public void onDisconnected(CameraDevice cameraDevice) {
cameraDevice.close();
mCameraDevice = null;
}
@Override
public void onError(CameraDevice cameraDevice, int error) {
cameraDevice.close();
mCameraDevice = null;
}
};
/**
* ******************************Camera2成功打开,开始预览(startPreview)*************************
*/
public void startPreview() {
if (null == mCameraDevice || !mTextureView.isAvailable() || null == mPreviewSize) {
return;
}
SurfaceTexture mSurfaceTexture = mTextureView.getSurfaceTexture();//获取TextureView的SurfaceTexture,作为预览输出载体
if (mSurfaceTexture == null) {
return;
}
try {
closePreviewSession();
mSurfaceTexture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());//设置TextureView的缓冲区大小
mPreviewBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);//创建CaptureRequestBuilder,TEMPLATE_PREVIEW比表示预览请求
Surface mSurface = new Surface(mSurfaceTexture);//获取Surface显示预览数据
mPreviewBuilder.addTarget(mSurface);//设置Surface作为预览数据的显示界面
//默认预览不开启闪光灯
mPreviewBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
//创建相机捕获会话,第一个参数是捕获数据的输出Surface列表,第二个参数是CameraCaptureSession的状态回调接口,当它创建好后会回调onConfigured方法,第三个参数用来确定Callback在哪个线程执行,为null的话就在当前线程执行
mCameraDevice.createCaptureSession(Arrays.asList(mSurface, mImageReader.getSurface()), new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(CameraCaptureSession session) {
try {
//创建捕获请求
mCaptureRequest = mPreviewBuilder.build();
mPreviewSession = session;
//不停的发送获取图像请求,完成连续预览
mPreviewSession.setRepeatingRequest(mCaptureRequest, null, mCameraHandler);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onConfigureFailed(CameraCaptureSession session) {
}
}, null);
} catch (Exception e) {
e.printStackTrace();
Log.e("dasdadasd", "捕获的异常" + e.toString());
}
}
/**
* ********************************************拍照*********************************************
*/
private void capture() {
if (null == mCameraDevice || !mTextureView.isAvailable() || null == mPreviewSize) {
return;
}
try {
CaptureRequest.Builder mCaptureBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
//获取屏幕方向
int rotation = getWindowManager().getDefaultDisplay().getRotation();
mCaptureBuilder.addTarget(mImageReader.getSurface());
//isCameraFront是自定义的一个boolean值,用来判断是不是前置摄像头,是的话需要旋转180°,不然拍出来的照片会歪了
if (isCameraFront) {
mCaptureBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATION.get(Surface.ROTATION_180));
} else {
mCaptureBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATION.get(rotation));
}
//锁定焦点
mCaptureBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_START);
//判断预览的时候是不是已经开启了闪光灯
if (isLightOn) {
mCaptureBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_TORCH);
} else {
mCaptureBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
}
//判断预览的时候是否两指缩放过,是的话需要保持当前的缩放比例
mCaptureBuilder.set(CaptureRequest.SCALER_CROP_REGION, zoom);
CameraCaptureSession.CaptureCallback CaptureCallback = new CameraCaptureSession.CaptureCallback() {
@Override
public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {
//拍完照unLockFocus
unLockFocus();
}
};
mPreviewSession.stopRepeating();
//咔擦拍照
mPreviewSession.capture(mCaptureBuilder.build(), CaptureCallback, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private void unLockFocus() {
try {
// 构建失能AF的请求
mPreviewBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);
//闪光灯重置为未开启状态
mPreviewBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
//继续开启预览
mPreviewSession.setRepeatingRequest(mCaptureRequest, null, mCameraHandler);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* ********************************************录像*********************************************
*/
private void setUpMediaRecorder() {
try {
Log.e("daasddasd", "setUpMediaRecorder");
mMediaRecorder.reset();
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
// 这里有点投机取巧的方式,不过证明方法也是不错的
// 录制出来10S的视频,大概1.2M,清晰度不错,而且避免了因为手动设置参数导致无法录制的情况
// 手机一般都有这个格式CamcorderProfile.QUALITY_480P,因为单单录制480P的视频还是很大的,所以我们在手动根据预览尺寸配置一下videoBitRate,值越高越大
// QUALITY_QVGA清晰度一般,不过视频很小,一般10S才几百K
// 判断有没有这个手机有没有这个参数
if (CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_480P)) {
CamcorderProfile profile = CamcorderProfile.get(CamcorderProfile.QUALITY_480P);
profile.videoBitRate = mPreviewSize.getWidth() * mPreviewSize.getHeight();
mMediaRecorder.setProfile(profile);
mMediaRecorder.setPreviewDisplay(new Surface(mTextureView.getSurfaceTexture()));
} else if (CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_720P)) {
CamcorderProfile profile = CamcorderProfile.get(CamcorderProfile.QUALITY_720P);
profile.videoBitRate = mPreviewSize.getWidth() * mPreviewSize.getHeight();
mMediaRecorder.setProfile(profile);
mMediaRecorder.setPreviewDisplay(new Surface(mTextureView.getSurfaceTexture()));
} else if (CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_QVGA)) {
mMediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_QVGA));
mMediaRecorder.setPreviewDisplay(new Surface(mTextureView.getSurfaceTexture()));
} else if (CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_CIF)) {
mMediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_CIF));
mMediaRecorder.setPreviewDisplay(new Surface(mTextureView.getSurfaceTexture()));
} else {
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
mMediaRecorder.setVideoEncodingBitRate(10000000);
mMediaRecorder.setVideoFrameRate(30);
mMediaRecorder.setVideoEncodingBitRate(2500000);
mMediaRecorder.setVideoFrameRate(20);
mMediaRecorder.setVideoSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
}
//判断有没有配置过视频地址了
Camera2Util.createSavePath(Camera2Config.PATH_SAVE_VIDEO);//判断有没有这个文件夹,没有的话需要创建
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
videoSavePath = Camera2Config.PATH_SAVE_VIDEO + "VIDEO_" + timeStamp + ".mp4";
mMediaRecorder.setOutputFile(videoSavePath);
//判断是不是前置摄像头,是的话需要旋转对应的角度
if (isCameraFront) {
mMediaRecorder.setOrientationHint(270);
} else {
mMediaRecorder.setOrientationHint(90);
}
mMediaRecorder.prepare();
} catch (Exception e) {
e.printStackTrace();
}
}
//预览录像
private void prepareMediaRecorder() {
if (null == mCameraDevice || !mTextureView.isAvailable() || null == mPreviewSize) {
return;
}
try {
closePreviewSession();
Log.e("aasdasdasd", "prepareMediaRecorder");
setUpMediaRecorder();
SurfaceTexture texture = mTextureView.getSurfaceTexture();
assert texture != null;
texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
mPreviewBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
List<Surface> surfaces = new ArrayList<>();
// Set up Surface for the camera preview
Surface previewSurface = new Surface(texture);
surfaces.add(previewSurface);
mPreviewBuilder.addTarget(previewSurface);
// Set up Surface for the MediaRecorder
Surface recorderSurface = mMediaRecorder.getSurface();
surfaces.add(recorderSurface);
mPreviewBuilder.addTarget(recorderSurface);
//判断预览之前有没有开闪光灯
if (isLightOn) {
mPreviewBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_TORCH);
} else {
mPreviewBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
}
//保持当前的缩放比例
mPreviewBuilder.set(CaptureRequest.SCALER_CROP_REGION, zoom);
mCameraDevice.createCaptureSession(surfaces, new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(CameraCaptureSession session) {
try {
//创建捕获请求
mCaptureRequest = mPreviewBuilder.build();
mPreviewSession = session;
//设置反复捕获数据的请求,这样预览界面就会一直有数据显示
mPreviewSession.setRepeatingRequest(mCaptureRequest, null, mCameraHandler);
} catch (Exception e) {
e.printStackTrace();
Log.e("dasdasdasdas", "捕获的异常2" + e.toString());
}
}
@Override
public void onConfigureFailed(CameraCaptureSession session) {
Toast.makeText(Camera2RecordActivity.this, "onConfigureFailed", Toast.LENGTH_SHORT).show();
}
}, null);
} catch (Exception e) {
e.printStackTrace();
}
}
//开始录像
private void startMediaRecorder() {
Log.e("daasddasd", "startMediaRecorder");
// Start recording
try {
mMediaRecorder.start();
//开始计时,判断是否已经超过录制时间了
mCameraHandler.postDelayed(recordRunnable, 0);
isStop = false;
} catch (Exception e) {
e.printStackTrace();
}
}
Runnable recordRunnable = new Runnable() {
@Override
public void run() {
currentTime++;
//开始显示进度条
mProgressView.setVisibility(View.VISIBLE);
mProgressView.setIsStart(true);
//显示时间
tvBalanceTime.setVisibility(View.VISIBLE);
tvBalanceTime.setText(MAX_RECORD_TIME - currentTime + "s");
//如果超过最大录制时长则自动结束
if (currentTime > MAX_RECORD_TIME) {
stopMediaRecorder();
} else {
mCameraHandler.postDelayed(this, 1000);
}
}
};
//停止录像
private void stopMediaRecorder() {
if (TextUtils.isEmpty(videoSavePath)) {
return;
}
try {
//结束ProgressView
mProgressView.setIsStart(false);
mCameraHandler.removeCallbacks(recordRunnable);
mMediaRecorder.stop();
mMediaRecorder.reset();
isStop = true;
//判断录制时常是不是小于指定秒数
if (currentTime <= MIN_RECORD_TIME) {
Toast.makeText(this, "录制时间过短", Toast.LENGTH_LONG).show();
} else {
//正常录制结束,跳转到完成页,这里你也可以自己处理
if (Camera2Config.ACTIVITY_AFTER_CAPTURE != null) {
Intent intent = new Intent(Camera2RecordActivity.this, Camera2Config.ACTIVITY_AFTER_CAPTURE);
intent.putExtra(Camera2Config.INTENT_PATH_SAVE_VIDEO, videoSavePath);
startActivity(intent);
}
}
//录制完成后重置录制界面
showResetCameraLayout();
} catch (Exception e) {
//这里抛出的异常是由于MediaRecorder开关时间过于短暂导致,直接按照录制时间短处理
Toast.makeText(this, "录制时间过短", Toast.LENGTH_LONG).show();
showResetCameraLayout();
}
currentTime = 0;
}
public void showResetCameraLayout() {
resetCamera();
mProgressView.setVisibility(View.INVISIBLE);
tvBalanceTime.setVisibility(View.GONE);
//重置ProgressView
mProgressView.reset();
}
/**
* **********************************************切换摄像头**************************************
*/
public void switchCamera() {
if (mCameraDevice != null) {
mCameraDevice.close();
mCameraDevice = null;
}
if (isCameraFront) {
isCameraFront = false;
setupCamera(width, height);
openCamera(mCameraId);
} else {
isCameraFront = true;
setupCamera(width, height);
openCamera(mCameraIdFront);
}
}
/**
* ***************************************打开和关闭闪光灯****************************************
*/
public void openLight() {
if (isLightOn) {
ivLightOn.setSelected(false);
isLightOn = false;
mPreviewBuilder.set(CaptureRequest.FLASH_MODE,
CaptureRequest.FLASH_MODE_OFF);
} else {
ivLightOn.setSelected(true);
isLightOn = true;
mPreviewBuilder.set(CaptureRequest.FLASH_MODE,
CaptureRequest.FLASH_MODE_TORCH);
}
try {
if (mPreviewSession != null)
mPreviewSession.setRepeatingRequest(mPreviewBuilder.build(), null, mCameraHandler);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* *********************************放大或者缩小**********************************
*/
//手指按下的点为(x1, y1)手指离开屏幕的点为(x2, y2)
float finger_spacing;
int zoom_level = 0;
Rect zoom;
public void changeZoom(MotionEvent event) {
try {
//活动区域宽度和作物区域宽度之比和活动区域高度和作物区域高度之比的最大比率
float maxZoom = (characteristics.get(CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM)) * 10;
Rect m = characteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
int action = event.getAction();
float current_finger_spacing;
//判断当前屏幕的手指数
if (event.getPointerCount() > 1) {
//计算两个触摸点的距离
current_finger_spacing = getFingerSpacing(event);
if (finger_spacing != 0) {
if (current_finger_spacing > finger_spacing && maxZoom > zoom_level) {
zoom_level++;
} else if (current_finger_spacing < finger_spacing && zoom_level > 1) {
zoom_level--;
}
int minW = (int) (m.width() / maxZoom);
int minH = (int) (m.height() / maxZoom);
int difW = m.width() - minW;
int difH = m.height() - minH;
int cropW = difW / 100 * (int) zoom_level;
int cropH = difH / 100 * (int) zoom_level;
cropW -= cropW & 3;
cropH -= cropH & 3;
zoom = new Rect(cropW, cropH, m.width() - cropW, m.height() - cropH);
mPreviewBuilder.set(CaptureRequest.SCALER_CROP_REGION, zoom);
}
finger_spacing = current_finger_spacing;
} else {
if (action == MotionEvent.ACTION_UP) {
//single touch logic,可做点击聚焦操作
}
}
try {
mPreviewSession.setRepeatingRequest(mPreviewBuilder.build(), new CameraCaptureSession.CaptureCallback() {
@Override
public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) {
super.onCaptureCompleted(session, request, result);
}
},
null);
} catch (Exception e) {
e.printStackTrace();
}
} catch (Exception e) {
throw new RuntimeException("can not access camera.", e);
}
}
//计算两个触摸点的距离
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);
}
/**
* **************************************清除操作************************************************
*/
public void onFinishCapture() {
try {
if (mPreviewSession != null) {
mPreviewSession.close();
mPreviewSession = null;
}
if (mCameraDevice != null) {
mCameraDevice.close();
mCameraDevice = null;
}
if (mImageReader != null) {
mImageReader.close();
mImageReader = null;
}
if (mMediaRecorder != null) {
mMediaRecorder.release();
mMediaRecorder = null;
}
if (mCameraHandler != null) {
mCameraHandler.removeCallbacksAndMessages(null);
}
} catch (Exception e) {
e.printStackTrace();
Log.e("adsdadadad", e.toString() + "onFinish2()");
}
}
//清除预览Session
private void closePreviewSession() {
if (mPreviewSession != null) {
mPreviewSession.close();
mPreviewSession = null;
}
}
//重新配置打开相机
public void resetCamera() {
if (TextUtils.isEmpty(mCameraId)) {
return;
}
if (mCameraDevice != null) {
mCameraDevice.close();
}
setupCamera(width, height);
openCamera(mCameraId);
}
/**
* 屏幕方向发生改变时调用转换数据方法
*
* @param viewWidth mTextureView 的宽度
* @param viewHeight mTextureView 的高度
*/
private void configureTransform(int viewWidth, int viewHeight) {
if (null == mTextureView || null == mPreviewSize) {
return;
}
int rotation = getWindowManager().getDefaultDisplay().getRotation();
Matrix matrix = new Matrix();
RectF viewRect = new RectF(0, 0, viewWidth, viewHeight);
RectF bufferRect = new RectF(0, 0, mPreviewSize.getHeight(), mPreviewSize.getWidth());
float centerX = viewRect.centerX();
float centerY = viewRect.centerY();
if (Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation) {
bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY());
matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL);
float scale = Math.max(
(float) viewHeight / mPreviewSize.getHeight(),
(float) viewWidth / mPreviewSize.getWidth());
matrix.postScale(scale, scale, centerX, centerY);
matrix.postRotate(90 * (rotation - 2), centerX, centerY);
}
mTextureView.setTransform(matrix);
}
/**
* ******************************Activity生命周期*****************************************
*/
@Override
protected void onResume() {
super.onResume();
//从FinishActivity退回来的时候默认重置为初始状态,因为有些机型从不可见到可见不会执行onSurfaceTextureAvailable,像有些一加手机
//所以也可以在这里在进行setupCamera()和openCamera()这两个方法
//每次开启预览缩放重置为正常状态
if (zoom != null) {
zoom.setEmpty();
zoom_level = 0;
}
//每次开启预览默认闪光灯没开启
isLightOn = false;
ivLightOn.setSelected(false);
//每次开启预览默认是后置摄像头
isCameraFront = false;
}
@Override
protected void onPause() {
onFinishCapture();//释放资源
super.onPause();
}
@Override
protected void onStop() {
super.onStop();
}
@Override
protected void onDestroy() {
super.onDestroy();
}
}
下面就是对应的工具类
public class Camera2Config {
public static int RECORD_MAX_TIME = 10;//录制的总时长秒数,单位秒,默认10秒
public static int RECORD_MIN_TIME = 2;//最小录制时长,单位秒,默认2秒
public static int RECORD_PROGRESS_VIEW_COLOR = R.color.colorPrimary;//进度条颜色,默认蓝色
public static int PREVIEW_MAX_HEIGHT = 1000;//最大高度预览尺寸,默认大于1000的第一个
public static String PATH_SAVE_VIDEO= Camera2Util.getCamera2Path();//小视频存放地址,不设置的话默认在根目录的Camera文件夹
public static String PATH_SAVE_PIC= Camera2Util.getCamera2Path();//图片保存地址,不设置的话默认在根目录的Camera文件夹
public static Class ACTIVITY_AFTER_CAPTURE;//拍照完成后需要跳转的Activity,一般这个activity做处理照片或者视频用
public static String INTENT_PATH_SAVE_VIDEO = "INTENT_PATH_SAVE_VIDEO"; //Intent跳转可用
public static String INTENT_PATH_SAVE_PIC = "INTENT_PATH_SAVE_PIC";//Intent跳转可用
public static boolean ENABLE_RECORD=true;//是否需要录像功能
public static boolean ENABLE_CAPTURE=true;//是否需要拍照功能
}
第二个工具类
public class Camera2Util {
//选择合适的视频size,并且不能大于1080p
private Size chooseVideoSize(Size[] choices) {
for (Size size : choices) {
if (size.getWidth() == size.getHeight() * 4 / 3 && size.getWidth() <= 1080) {
return size;
}
}
return choices[choices.length - 1];
}
//选择sizeMap中大于并且最接近width和height的size
private Size getOptimalSize(Size[] sizeMap, int width, int height) {
List<Size> sizeList = new ArrayList<>();
for (Size option : sizeMap) {
if (width > height) {
if (option.getWidth() > width && option.getHeight() > height) {
sizeList.add(option);
}
} else {
if (option.getWidth() > height && option.getHeight() > width) {
sizeList.add(option);
}
}
}
if (sizeList.size() > 0) {
return Collections.min(sizeList, new Comparator<Size>() {
@Override
public int compare(Size lhs, Size rhs) {
return Long.signum(lhs.getWidth() * lhs.getHeight() - rhs.getWidth() * rhs.getHeight());
}
});
}
return sizeMap[0];
}
// 通过对比得到与宽高比最接近的尺寸(如果有相同尺寸,优先选择,activity我们已经固定了方向,所以这里无需在做判断
protected static Size getCloselyPreSize(Size[] sizeMap, int surfaceWidth, int surfaceHeight) {
int ReqTmpWidth;
int ReqTmpHeight;
ReqTmpWidth = surfaceHeight;
ReqTmpHeight = surfaceWidth;
//先查找preview中是否存在与surfaceview相同宽高的尺寸
for (Size size : sizeMap) {
if ((size.getWidth() == ReqTmpWidth) && (size.getHeight() == ReqTmpHeight)) {
return size;
}
}
// 得到与传入的宽高比最接近的size
float reqRatio = ((float) ReqTmpWidth) / ReqTmpHeight;
float curRatio, deltaRatio;
float deltaRatioMin = Float.MAX_VALUE;
Size retSize = null;
for (Size size : sizeMap) {
curRatio = ((float) size.getWidth()) / size.getHeight();
deltaRatio = Math.abs(reqRatio - curRatio);
if (deltaRatio < deltaRatioMin) {
deltaRatioMin = deltaRatio;
retSize = size;
}
}
return retSize;
}
/**
* 核心方法,这里是通过从sizeMap中获取和Textureview宽高比例相同的map,然后在获取接近自己想获取到的尺寸
* 之所以这么做是因为我们要确保预览尺寸不要太大,这样才不会太卡
*
* @param sizeMap
* @param surfaceWidth
* @param surfaceHeight
* @param maxHeight
* @return
*/
public static Size getMinPreSize(Size[] sizeMap, int surfaceWidth, int surfaceHeight, int maxHeight) {
// 得到与传入的宽高比最接近的size
float reqRatio = ((float) surfaceWidth) / surfaceHeight;
float curRatio;
List<Size> sizeList = new ArrayList<>();
Size retSize = null;
for (Size size : sizeMap) {
curRatio = ((float) size.getHeight()) / size.getWidth();
if (reqRatio == curRatio) {
sizeList.add(size);
}
}
if (sizeList != null && sizeList.size() != 0) {
for (int i = sizeList.size() - 1; i >= 0; i--) {
//取Size宽度大于1000的第一个数,这里我们获取大于maxHeight的第一个数,理论上我们是想获取size.getWidth宽度为1080或者1280那些,因为这样的预览尺寸已经足够了
if (sizeList.get(i).getWidth() >= maxHeight) {
retSize = sizeList.get(i);
break;
}
}
//可能没有宽度大于maxHeight的size,则取相同比例中最小的那个size
if (retSize == null) {
retSize = sizeList.get(sizeList.size() - 1);
}
} else {
retSize = getCloselyPreSize(sizeMap, surfaceWidth, surfaceHeight);
}
return retSize;
}
/**
* 使用Camera2录制和所拍的照片都会在这里
*/
public static String getCamera2Path() {
String picturePath = Environment.getExternalStorageDirectory().getAbsolutePath();
File file = new File(picturePath);
if (!file.exists()) {
file.mkdirs();
}
return picturePath;
}
/**
* 判断传入的地址是否已经有这个文件夹,没有的话需要创建
*/
public static void createSavePath(String path){
File file = new File(path);
if (!file.exists()) {
file.mkdirs();
}
}
}
第三个 对应的顶部的走动条
public class ProgressView extends View {
//constant
private int millisecond = 1000;//每一秒
private float maxProgressSize = Camera2Config.RECORD_MAX_TIME * millisecond;//总进度是10s
private float eachProgressWidth = 0;//每一格的宽度
private Context mContext;
private WindowManager mWindowManager;
private Paint progressPaint;
public ProgressView(Context context) {
this(context, null);
}
public ProgressView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ProgressView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.mContext = context;
init();
}
private void init() {
//设置每一刻度的宽度
DisplayMetrics dm = new DisplayMetrics();
mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
mWindowManager.getDefaultDisplay().getMetrics(dm);
eachProgressWidth = dm.widthPixels / (maxProgressSize * 1.0f);
//进度条的背景颜色
setBackgroundColor(getResources().getColor(R.color.transparent));
//进度条的前景颜色,画笔
progressPaint = new Paint();
progressPaint.setStyle(Paint.Style.FILL);
progressPaint.setColor(getResources().getColor(Camera2Config.RECORD_PROGRESS_VIEW_COLOR));
}
private long initTime = -1;//上一次刷新完成后的时间
private boolean isStart = false;
private float countWidth = 0;//进度条进度的进程,每次调用invalidate()都刷新一次
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (!isStart) {
canvas.drawRect(0, 0, countWidth, getMeasuredHeight(), progressPaint);
return;
}
if (initTime == -1) {
initTime = System.currentTimeMillis();
canvas.drawRect(0, 0, countWidth, getMeasuredHeight(), progressPaint);
invalidate();
return;
}
//这次刷新的时间,用于与上一次刷新完成的时间作差得出进度条需要增加的进度
long thisTime = System.currentTimeMillis();
countWidth += eachProgressWidth * (thisTime - initTime) * 1.0f;
if (countWidth > getMeasuredWidth()) {
countWidth = getMeasuredWidth();
}
canvas.drawRect(0, 0, countWidth, getMeasuredHeight(), progressPaint);
//如果都了最大长度,就不再调用invalidate();了
if (countWidth < getMeasuredWidth() && isStart) {
initTime = System.currentTimeMillis();
invalidate();
} else {
countWidth = 0;
initTime = -1;
isStart = false;
}
}
//开始或暂停进度条进度刷新
public void setIsStart(boolean isStart) {
if (isStart == this.isStart)
return;
this.isStart = isStart;
if (isStart) {
initTime = -1;
invalidate();
}
}
//重置进度条
public void reset() {
countWidth = 0;
initTime = -1;
isStart = false;
invalidate();
}
//设置每一个像素的宽度
public void setEachProgressWidth(int width) {
eachProgressWidth = width / (maxProgressSize * 1.0f);
}
}
对应的drawable
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/ic_capture_light_on" android:state_selected="false"></item>
<item android:drawable="@drawable/ic_capture_light_off" android:state_selected="true"></item>
</selector>
对应的颜色
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#FF4081</color>
<color name="black">#000000</color>
<color name="white">#FFFFFF</color>
<color name="transparent">#00000000</color>
</resources>
对应的三个图片。就是x 一个⚡️ 看手机的灯 ,还有一个相机的logo点击前后摄像头 还有一个x点击退出
拍照 录像 前后摄像头切换 ,手机灯
591528075联系方式。大神勿喷