写在前面的话:每一个实例的代码都会附上相应的代码片或者图片,保证代码完整展示在博客中。最重要的是保证例程的完整性!!!方便自己也方便他人~欢迎大家交流讨论~本文为博主原创文章,未经博主允许。
在相机预览时增加取景蒙板/浮层的思路是自定义View,用framelayout把自定义view放在surfaceview上面,在oncreat方法中计算坐标位置,调用自定义view中的set…方法设置坐标,根据坐标绘图。
接下来把上篇的自定义相机和增加蒙板那篇的代码结合起来,为相机增加取景蒙板/浮层,上代码!
新建一个Android项目values文件夹strings.xml layout文件夹activity_first.xmlcustom.xmlresult.xml manifestsAndroidManifest.xml Java文件夹FirstActivityCustomcameraTranslucencyViewResultActivity 小结
新建一个Android项目
取名为Cameratwo,具体文件的命名如下
values文件夹
strings.xml
<resources><string name="app_name">Cameratwo</string><string name="button_name">开始拍照</string></resources>
layout文件夹
activity_first.xml
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="/apk/res/android"xmlns:tools="/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context=".FirstActivity"><Button android:id="@+id/button"android:layout_width="match_parent"android:layout_height="wrap_content"android:onClick="customCamera"android:text="@string/button_name" /><ImageView android:id="@+id/iv"android:layout_width="match_parent"android:layout_height="match_parent" /></LinearLayout>
custom.xml
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="/apk/res/android" android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><FrameLayout android:layout_width="match_parent"android:layout_height="match_parent"android:layout_alignParentTop="true"><SurfaceView android:id="@+id/preview"android:layout_width="match_parent"android:layout_height="match_parent"android:visibility="visible" /><com.example.administrator.cameratwo.TranslucencyView android:id="@+id/transView"android:layout_width="match_parent"android:layout_height="match_parent" /></FrameLayout><ImageButton android:id="@+id/button3"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentBottom="true"android:layout_centerHorizontal="true"android:background="@drawable/button3"android:onClick="capture" /></RelativeLayout>
result.xml
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="/apk/res/android" android:layout_width="match_parent"android:layout_height="match_parent"><ImageView android:id="@+id/pic"android:layout_width="match_parent"android:layout_height="match_parent" /></LinearLayout>
manifests
AndroidManifest.xml
在该文件中增加以下两项
<uses-permission android:name="android.permission.CAMERA"/><uses-feature android:name="android.hardware.Camera"/><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<activity android:name=".Customcamera"/><activity android:name=".ResultActivity"/>
Java文件夹
FirstActivity
package com.example.administrator.cameratwo;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.content.Intent;import android.view.View;public class FirstActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_first);}public void customCamera(View view){startActivity(new Intent(this,Customcamera.class));}}
Customcamera
这里完全没有用到Butter Knife 框架,因为我用的不熟,就删掉了orz…
package com.example.administrator.cameratwo;import android.content.Intent;import android.graphics.ImageFormat;import android.graphics.PixelFormat;import android.hardware.Camera;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.view.MotionEvent;import android.view.SurfaceHolder;import android.view.SurfaceView;import android.view.View;import android.widget.FrameLayout;import android.widget.ImageButton;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;public class Customcamera extends AppCompatActivity implements SurfaceHolder.Callback{private Camera mCamera;private SurfaceView mPreview;private SurfaceHolder mHolder;private int cameraId=1;private int mHeight;private Camera.PictureCallback mpictureCallback=new Camera.PictureCallback(){@Overridepublic void onPictureTaken(byte[] data,Camera camera){File tempfile=new File("/sdcard/emp.png");try{ FileOutputStream fos =new FileOutputStream(tempfile);fos.write(data);fos.close();Intent intent=new Intent(Customcamera.this,ResultActivity.class);intent.putExtra("picpath",tempfile.getAbsolutePath());startActivity(intent);Customcamera.this.finish();}catch (IOException e){e.printStackTrace();}}};@Overrideprotected void onCreate( Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.custom);mPreview=findViewById(R.id.preview);mPreview.setZOrderOnTop(false);mHolder=mPreview.getHolder();mHolder.setFormat(PixelFormat.TRANSPARENT);mHolder.addCallback(this);mPreview.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {mCamera.autoFocus(null);}});//获取imgButton的坐标,以便蒙板在imgButton处掏空,并获取页面参数ImageButton imgButton=findViewById(R.id.button3);TranslucencyView translucencyView=findViewById(R.id.transView);imgButton.postDelayed(new Runnable() {@Overridepublic void run() {runOnUiThread(new Runnable() {@Overridepublic void run() {ImageButton imgButton=findViewById(R.id.button3);mHeight = getSupportActionBar().getHeight();int left = imgButton.getLeft();int right = imgButton.getRight();int top = imgButton.getTop();int bottom = imgButton.getBottom();int mCoodinate[] = {left, top, right, bottom};TranslucencyView translucencyView=findViewById(R.id.transView);translucencyView.setCircleLocation(mCoodinate);}});}},1200);FrameLayout.LayoutParams layoutParams=(FrameLayout.LayoutParams) translucencyView.getLayoutParams();translucencyView.setLayoutParams(layoutParams);translucencyView.setOnTouchListener(new View.OnTouchListener() {@Overridepublic boolean onTouch(View v, MotionEvent event) {mCamera.autoFocus(null);return false;}});mHolder.lockCanvas();}public void capture(View view){Camera.Parameters parameters=mCamera.getParameters();parameters.setPictureFormat(ImageFormat.JPEG);parameters.setPreviewSize(800,400);parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);mCamera.autoFocus(new Camera.AutoFocusCallback(){@Overridepublic void onAutoFocus(boolean success, Camera camera) {if(success){mCamera.takePicture(null,null, mpictureCallback);}}});}@Overrideprotected void onResume() {super.onResume();if (mCamera==null){mCamera=getCamera();if(mHolder!=null){setStartPreview(mCamera,mHolder);}}}@Overrideprotected void onPause() {super.onPause();releaseCamera(); }private Camera getCamera(){Camera camera;try{camera=Camera.open(cameraId);}catch (Exception e){camera=null;e.printStackTrace(); }return camera;}private void setStartPreview(Camera camera,SurfaceHolder holder){try{camera.setPreviewDisplay(holder);camera.setDisplayOrientation(90);camera.startPreview();}catch (Exception e){e.printStackTrace(); }}private void releaseCamera(){if(mCamera!=null){mCamera.stopPreview();mCamera.setPreviewCallback(null);mCamera.release();mCamera=null;}}@Overridepublic void surfaceCreated(SurfaceHolder holder) {setStartPreview(mCamera,mHolder);}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {mCamera.stopPreview();setStartPreview(mCamera,mHolder);}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {releaseCamera();}@Overridepublic void onWindowFocusChanged(boolean hasFocus) {super.onWindowFocusChanged(hasFocus); }}
TranslucencyView
package com.example.administrator.cameratwo;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.DashPathEffect;import android.graphics.Paint;import android.graphics.Path;import android.graphics.PathEffect;import android.graphics.PorterDuff;import android.graphics.PorterDuffXfermode;import android.graphics.RectF;import android.util.AttributeSet;import android.widget.ImageView;public class TranslucencyView extends ImageView{private final Context mContext;private int[] mCircleLocation;//声明存放坐标的数组public TranslucencyView(Context context){this(context,null);}public TranslucencyView(Context context, AttributeSet attributeSet){this(context,attributeSet,0);}public TranslucencyView(Context context,AttributeSet attributeSet,int defStyleAttr){super(context,attributeSet,defStyleAttr);this.mContext=context;initView();}private void initView(){setBackgroundColor(Color.parseColor("#7f000000"));}//设置半透明底色public void setCircleLocation(int[] location){this.mCircleLocation=location;invalidate();}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);if(mCircleLocation!=null){//掏空一个圆形Paint paintarc=new Paint(Paint.ANTI_ALIAS_FLAG);//创建一个画笔实例PorterDuffXfermode porterDuffXfermode=new PorterDuffXfermode(PorterDuff.Mode.CLEAR);paintarc.setXfermode(porterDuffXfermode);paintarc.setAntiAlias(true);RectF rectF=new RectF(mCircleLocation[0],mCircleLocation[1],mCircleLocation[2],mCircleLocation[3]);canvas.drawArc(rectF,0,360,true,paintarc);//画虚线Paint paintdashed=new Paint(Paint.ANTI_ALIAS_FLAG);paintdashed.setStyle(Paint.Style.STROKE);paintdashed.setColor(Color.WHITE);paintdashed.setStrokeWidth(5);PathEffect pathEffect=new DashPathEffect(new float[]{10,10},0);paintdashed.setPathEffect(pathEffect);canvas.drawArc(rectF,0,360,true,paintdashed);//画矩形框/** Paint paintrect=new Paint(Paint.ANTI_ALIAS_FLAG);PorterDuffXfermode porterDuffXfermode1=new PorterDuffXfermode(PorterDuff.Mode.CLEAR);paintrect.setXfermode(porterDuffXfermode1);paintrect.setAntiAlias(true);//paintrect.setStrokeWidth(5);canvas.drawRect(200, 400, 900, 1300, paintrect);*///画椭圆Paint paintoval=new Paint(Paint.ANTI_ALIAS_FLAG);PorterDuffXfermode porterDuffXfermode2=new PorterDuffXfermode(PorterDuff.Mode.CLEAR);paintoval.setXfermode(porterDuffXfermode2);paintoval.setAntiAlias(true);//paintoval.setStrokeWidth(10);canvas.drawOval(100,200,1000,1200,paintoval);}}}
这里画了个椭圆,注意用的都是绝对坐标,我估计在不同的手机中可能会出现适配问题,不过还没想好相对的怎么画啦
ResultActivity
这个的代码和之前的3.3ResultActivity.java代码一模一样,大家直接看
Android Studio:使用Camera拍照(二)自定义相机 - CSDN博客/Leo_Huang720/article/details/81289309#33resultactivityjava就可以了
小结
上完了代码,我要小结一下给相机加取景蒙版和之前一篇的直接添加(文章后面有附上)有什么差别,我最开始的时候确实是很简单的两处代码合在一起,然后执行时发现两个问题:
1.整个显示出来的是深蓝色的
2.在蒙版还没稳定出现前,surfaceview尚在预览,蒙板稳定出现后,surfaceview瞬间卡在了那时的页面
解决问题1:我又回去看了自定义相机的执行(那个项目叫startcamera),发现surfaceview从开始到预览确实有个从暗变深蓝再变浅的过程,于是我猜是 showMask() 方法(这个方法中的内容后来被单独拿出来放到了onCreate中)中设置的时间太短,该时间用于测量view是够了(因为蒙板能顺利显示,如果时间不够,整个页面其实会闪退),那就是通过intent传给TranslucencyActivity.java的时间太短,surfaceview还没构造完,intent就把坐标信息给TranslucencyActivity了,于是我把时间从500ms改到1200ms
解决问题2:其实从解决问题1的最后几句话已经能看出问题2的端倪了,就是原本的showMask() 最后有几句代码:
Intent intent = new Intent(SecondActivity.this, TranslucencyActivity.class);intent.putExtra("Location", mCoodinate);startActivity(intent);
这就意味着信使不仅将坐标传给TranslucencyActivity,还打开了TranslucencyActivity!!那这个界面就把surfaceview定住了,因为TranslucencyActivity没有任何写预览的方法,它只是把自定义的view和自己的页面绑在一起,所以要弄取景框蒙板没有TranslucencyActivity任何事情,我就把它删掉了,其他所做的更改上面代码已详细给出。
执行效果:
附:Android Studio:增加蒙板/浮层特效 - CSDN博客 /Leo_Huang720/article/details/8154#secondactivityjava
Android Studio:使用Camera拍照(二)自定义相机 - CSDN博客/Leo_Huang720/article/details/81289309#33resultactivityjava