下面是对应的三个布局

<?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"><Buttonandroid:id="@+id/btn_openCamera2"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerInParent="true"android:text="打开Camera2" /><TextViewandroid: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"><TextureViewandroid:id="@+id/textureView"android:layout_width="match_parent"android:layout_height="match_parent" /><com.example.yidoucoltdred.myapplication.ProgressViewandroid:id="@+id/progressView"android:layout_width="match_parent"android:visibility="gone"android:layout_height="3dp" /><RelativeLayoutandroid: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"><ImageViewandroid:id="@+id/iv_takePhoto"android:layout_width="76dp"android:layout_height="76dp"android:layout_centerInParent="true"android:background="@drawable/ic_capture_btn" /><TextViewandroid: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" /><ImageViewandroid: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><RelativeLayoutandroid: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"><ImageViewandroid: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" /><TextViewandroid: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" /><ImageViewandroid: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"><ImageViewandroid:id="@+id/iv"android:layout_width="match_parent"android:layout_height="250dp"android:scaleType="centerCrop"android:layout_centerInParent="true"/><TextViewandroid:id="@+id/tv"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerInParent="true"android:textColor="@color/black"android:textSize="15dp"/><Buttonandroid:id="@+id/btn"android:text="上传图片"android:layout_width="match_parent"android:layout_height="wrap_content" /><Buttonandroid: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;@Overrideprotected 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() {@Overridepublic 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;@Overrideprotected 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() {@Overridepublic void onClick(View v) {}});btn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Toast.makeText(Camera2RecordFinishActivity.this,"好使", Toast.LENGTH_LONG).show();
//                postGoodsPicToServers();}});}}

第三个对应的是拍照,的逻辑

public class Camera2RecordActivity extends AppCompatActivity implements TextureView.SurfaceTextureListener {//viewsprivate TextureView mTextureView;private TextView tvBalanceTime;//录制剩余时间private ImageView ivTakePhoto;//拍照&录像按钮private ImageView ivSwitchCamera;//切换前后摄像头private ImageView ivLightOn;//开关闪光灯private ImageView ivClose;//关闭该Activityprivate 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);}//constantprivate static final String TAG = "Camera2RecordActivity";private static final int PERMISSIONS_REQUEST = 1;//拍照完成回调private static final int CAPTURE_OK = 0;//拍照完成回调private String mCameraId;//后置摄像头IDprivate String mCameraIdFront;//前置摄像头IDprivate Size mPreviewSize;//预览的Sizeprivate Size mCaptureSize;//拍照Sizeprivate int width;//TextureView的宽private int height;//TextureView的高private boolean isCameraFront = false;//当前是否是前置摄像头private boolean isLightOn = false;//当前闪光灯是否开启//Camera2private 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;//视频保存路径//handlerprivate HandlerThread mCameraThread;private Handler mCameraHandler;private LongPressRunnable longPressRunnable;//长按后处理的逻辑Runnable//录像private static final int MAX_RECORD_TIME = Camera2Config.RECORD_MAX_TIME;//最大录制时长,默认10Sprivate static final int MIN_RECORD_TIME = Camera2Config.RECORD_MIN_TIME;//最小录制时长,默认2Sprivate boolean isRecording = false;//是否正在录制视频private boolean isStop = false;//是否停止过了MediaRecorderprivate int currentTime;private MediaRecorder mMediaRecorder;
//自定义调转public static void start(Context context) {Intent intent = new Intent(context, Camera2RecordActivity.class);context.startActivity(intent);}@Overrideprotected 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();}/*** **************************************初始化相关***********************************************///初始化TextureViewprivate 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() {@Overridepublic 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() {@Overridepublic boolean onTouch(View view, MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN:isRecording = false;mCameraHandler.postDelayed(longPressRunnable, 500);//同时延长500启动长按后处理的逻辑Runnablebreak;case MotionEvent.ACTION_MOVE:break;case MotionEvent.ACTION_UP:case MotionEvent.ACTION_CANCEL://根据当前按钮的状态进行相应的处理handlerUnpressByState();break;}return true;}});mTextureView.setOnTouchListener(new View.OnTouchListener() {@Overridepublic boolean onTouch(View view, MotionEvent event) {//两指缩放changeZoom(event);return true;}});}//长按线程private class LongPressRunnable implements Runnable {@Overridepublic 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() {@Overridepublic 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******************************************/@Overridepublic void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) {//当SurefaceTexture可用的时候,设置相机参数并打开相机this.width = width;this.height = height;setupCamera(width, height);//配置相机参数openCamera(mCameraId);//打开相机}@Overridepublic void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int i, int i1) {configureTransform(width, height);}@Overridepublic boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {return false;}@Overridepublic void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {}/*** ******************************SetupCamera(配置Camera)******************************************/private void setupCamera(int width, int height) {//获取摄像头的管理者CameraManagerCameraManager 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>() {@Overridepublic 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();}}//配置ImageReaderprivate void setupImageReader() {//2代表ImageReader中最多可以获取两帧图像流mImageReader = ImageReader.newInstance(mCaptureSize.getWidth(), mCaptureSize.getHeight(),ImageFormat.JPEG, 2);mImageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {@Overridepublic 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() {@Overridepublic 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) {//获取摄像头的管理者CameraManagerCameraManager 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() {@Overridepublic void onOpened(CameraDevice camera) {mCameraDevice = camera;startPreview();if (null != mTextureView) {configureTransform(mTextureView.getWidth(), mTextureView.getHeight());}}@Overridepublic void onDisconnected(CameraDevice cameraDevice) {cameraDevice.close();mCameraDevice = null;}@Overridepublic 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() {@Overridepublic void onConfigured(CameraCaptureSession session) {try {//创建捕获请求mCaptureRequest = mPreviewBuilder.build();mPreviewSession = session;//不停的发送获取图像请求,完成连续预览mPreviewSession.setRepeatingRequest(mCaptureRequest, null, mCameraHandler);} catch (Exception e) {e.printStackTrace();}}@Overridepublic 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() {@Overridepublic void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {//拍完照unLockFocusunLockFocus();}};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 previewSurface previewSurface = new Surface(texture);surfaces.add(previewSurface);mPreviewBuilder.addTarget(previewSurface);// Set up Surface for the MediaRecorderSurface 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() {@Overridepublic 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());}}@Overridepublic 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 recordingtry {mMediaRecorder.start();//开始计时,判断是否已经超过录制时间了mCameraHandler.postDelayed(recordRunnable, 0);isStop = false;} catch (Exception e) {e.printStackTrace();}}Runnable recordRunnable = new Runnable() {@Overridepublic 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 {//结束ProgressViewmProgressView.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);//重置ProgressViewmProgressView.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() {@Overridepublic 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()");}}//清除预览Sessionprivate 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生命周期******************************************/@Overrideprotected void onResume() {super.onResume();//从FinishActivity退回来的时候默认重置为初始状态,因为有些机型从不可见到可见不会执行onSurfaceTextureAvailable,像有些一加手机//所以也可以在这里在进行setupCamera()和openCamera()这两个方法//每次开启预览缩放重置为正常状态if (zoom != null) {zoom.setEmpty();zoom_level = 0;}//每次开启预览默认闪光灯没开启isLightOn = false;ivLightOn.setSelected(false);//每次开启预览默认是后置摄像头isCameraFront = false;}@Overrideprotected void onPause() {onFinishCapture();//释放资源super.onPause();}@Overrideprotected void onStop() {super.onStop();}@Overrideprotected 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,并且不能大于1080pprivate 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的sizeprivate 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>() {@Overridepublic 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;}}// 得到与传入的宽高比最接近的sizefloat 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) {// 得到与传入的宽高比最接近的sizefloat 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,则取相同比例中最小的那个sizeif (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 {//constantprivate int millisecond = 1000;//每一秒private float maxProgressSize = Camera2Config.RECORD_MAX_TIME * millisecond;//总进度是10sprivate 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()都刷新一次@Overrideprotected 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联系方式。大神勿喷

Android 点击拍照,长按录像保存本地 结合camer2实现 前后摄像头切换,手机闪关灯,相关推荐

  1. android点击拍照长按录制小视频

    实现了点击拍照,长按录制小视频功能.录制时间以及进度环都可以自定义;功能直接看图 部分代码: 下载地址:下载完整demo请戳我

  2. 微信小程序实现点击拍照长按录像功能

    微信小程序实现点击拍照长按录像功能 代码里面注释写的都很详细,直接上代码.官方的组件属性中有触摸开始和触摸结束属性.本功能依靠这些属性实现. .wxml代码: <!-- 相机 pages/cam ...

  3. Android通过代码生成长图并保存本地

    hello大家好,我是斯普润,很久没有更新博客了.因为最近一直在赶项目,不停加班.难得有时间闲下来写写博客.最近也在抽时间学习flutter,作为一枚程序猿当然不能停止学习的脚步啦~ 说远了,今天分享 ...

  4. 《微信小程序案例6》点击图片上传,从本地相册选择或打开摄像头拍摄上传照片

    点击一下相机图片实现上传本都相册图片或者打开摄像头拍照上传 使用微信小程序API里面的wx.chooseImage 实现点击并上传图片后把上传的图片放入上面的虚线框里面. 方法: 在wx.choose ...

  5. iOS 相机 点击拍照,长按录像

    一.ios点击拍照长按录像,效果图如下: 二.使用方法 1.必要权限申请 Privacy - Camera Usage Description Privacy - Microphone Usage D ...

  6. AS打开照相机拍照保存本地、显示页面

    打开相机 1.权限 6.0之后修改动态获取权限 打开照相机的权限 <uses-permission android:name="android.permission.CAMERA&qu ...

  7. JCameraView 仿微信拍照Android控件(点击拍照,长按录小视频)

    使用方法 Gradle依赖: compile 'cjt.library.wheel:camera :1.1.9' 引用源码 :  clone源码后 引入lib -> camera 尝试运行 : ...

  8. android 录制视频过程中拍照,GitHub - 616852636/CameraView: 仿微信拍照Android控件(点击拍照,长按录小视频)...

    JCameraView 控件介绍 这是一个模仿微信拍照的Android开源控件,主要的功能有如下: 点击拍照. 前后摄像头的切换. 长按录视频(视频长度为10秒内). 长按录视频的时候,手指上滑可以放 ...

  9. Android APP Camera2应用(04)录像保存视频流程

    说明:camera子系统 系列文章针对Android10.0系统,主要针对 camera API2 + HAL3 框架进行解读. 1 录像&保存视频流程简要解读 @1 当预览创建之后,点击录像 ...

最新文章

  1. Centos7 fstab盘符挂载硬盘导致重启系统失败解决办法
  2. ios之开发屏幕适配和系统版本适配(转载)
  3. php背景,php图片背景填充实例
  4. 如何调用java的包_jsp如何调用java包
  5. 3.8女神节:我又送福利 书和化妆品 男女通吃
  6. java怎么使两个界面联系_怎么样用java编写界面实现两个数的加法运算
  7. c++学习笔记(7) 面向对象思想
  8. nginx源码分析:打开监听套接字的流程
  9. Picturebox实现图片的缩放
  10. 自费出书多少钱?如何出书
  11. PR字幕不显示的问题(已解决)
  12. NOIP模拟赛 czy的后宫5
  13. larvel html转pdf文件,如何在Laravel中使用TCPDF从HTML生成PDF
  14. Peeking into the Future: Predicting Future Person Activities and Locations in Videos 翻译
  15. 试题 算法提高 陶陶摘苹果
  16. CTF中php相关考点
  17. excel数据透视表总结
  18. java毕业设计流浪猫狗救助网站源码+lw文档+mybatis+系统+mysql数据库+调试
  19. 《软件测试---你必须掌握的100个问题》
  20. 蓝桥杯javaB三羊献瑞

热门文章

  1. 如何清理roaming_C 盘突然爆满,怎么清理?
  2. android 热搜词 布局,Android FlowLayout流式布局打造热门标签(高仿抖音热搜)
  3. 电脑音箱怎么会出现电流声?
  4. 优秀的DJ软件:PCDJ DEX 3 for Mac
  5. php 怎么显示符号,HTML5特殊符号怎么显示
  6. Windows Vista,生而伟大
  7. java不用系统函数String转int
  8. js如何设置radio选中
  9. Failed to save ‘stopContract.vue‘: Insufficient permissions. Select ‘Retry as Sudo‘ to retry as supe
  10. 书论15 萧衍《草书状》