[转载]Android 手把手带你玩转自定义相机

来源:互联网 发布:知乎如何看提问者 编辑:程序博客网 时间:2024/04/30 03:06
转载地址:http://blog.csdn.net/qq_17250009/article/details/52795530

本文已授权微信公众号《鸿洋》原创首发,转载请务必注明出处。

概述

相机几乎是每个APP都要用到的功能,万一老板让你定制相机方不方?反正我是有点方。关于相机的两天奋斗总结免费送给你。

  Intent intent = new Intent();    intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);    startActivity(intent);
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

或者指定返回图片的名称mCurrentPhotoFile

  Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);  intent.putExtra(MediaStore.EXTRA_OUTPUT,Uri.fromFile(mCurrentPhotoFile));  startActivityForResult(intent, CAMERA_WITH_DATA);
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

2.自定义启动相机。

今天以第二种为例。效果图如下
demo

自定义相机的一般步骤

  1. 创建显示相机画面的布局,Android已经为我们选定好SurfaceView
  2. 通过SurfaceView#getHolder()获得链接CameraSurfaceViewSurfaceHolder
  3. Camame.open()打开相机
  4. 通过SurfaceHolder链接CameraurfaceView

一般步骤的代码演示

public class CameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback, Camera.AutoFocusCallback {    private static final String TAG = "CameraSurfaceView";    private Context mContext;    private SurfaceHolder holder;    private Camera mCamera;    private int mScreenWidth;    private int mScreenHeight;    public CameraSurfaceView(Context context) {        this(context, null);    }    public CameraSurfaceView(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    public CameraSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        mContext = context;        getScreenMetrix(context);        initView();    }    private void getScreenMetrix(Context context) {        WindowManager WM = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);        DisplayMetrics outMetrics = new DisplayMetrics();        WM.getDefaultDisplay().getMetrics(outMetrics);        mScreenWidth = outMetrics.widthPixels;        mScreenHeight = outMetrics.heightPixels;    }    private void initView() {        holder = getHolder();//获得surfaceHolder引用        holder.addCallback(this);        holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);//设置类型    }    @Override    public void surfaceCreated(SurfaceHolder holder) {        Log.i(TAG, "surfaceCreated");        if (mCamera == null) {            mCamera = Camera.open();//开启相机            try {                mCamera.setPreviewDisplay(holder);//摄像头画面显示在Surface上            } catch (IOException e) {                e.printStackTrace();            }        }    }    @Override    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {        Log.i(TAG, "surfaceChanged");        mCamera.startPreview();    }    @Override    public void surfaceDestroyed(SurfaceHolder holder) {        Log.i(TAG, "surfaceDestroyed");        mCamera.stopPreview();//停止预览        mCamera.release();//释放相机资源        mCamera = null;        holder = null;    }    @Override    public void onAutoFocus(boolean success, Camera Camera) {        if (success) {            Log.i(TAG, "onAutoFocus success="+success);        }    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75

添加相机和自动聚焦限权

<uses-permission android:name="android.permission.CAMERA" /><uses-feature android:name="android.hardware.camera.autofocus" />
  • 1
  • 2
  • 1
  • 2

CameraSurfaceView放在布局文件中,这里建议最外层为FrameLayout,后面会用到。如此,我们便有了一个没有照相功能的相机。初次之外,仔细观察相机显示画面,图片是不是变形严重?那是因为我们还没有为相机设置各种参数。在预览前要设置摄像头的分辨率、预览分辨率和图片分辨率的宽高比保持一致。这样图片才不会变形。这是个比较难以理解的部分,想深刻理解还需读者自己动手去实践。

   private void setCameraParams(Camera camera, int width, int height) {        Log.i(TAG,"setCameraParams  width="+width+"  height="+height);        Camera.Parameters parameters = mCamera.getParameters();        // 获取摄像头支持的PictureSize列表        List<Camera.Size> pictureSizeList = parameters.getSupportedPictureSizes();        for (Camera.Size size : pictureSizeList) {            Log.i(TAG, "pictureSizeList size.width=" + size.width + "  size.height=" + size.height);        }        /**从列表中选取合适的分辨率*/        Camera.Size picSize = getProperSize(pictureSizeList, ((float) height / width));        if (null == picSize) {            Log.i(TAG, "null == picSize");            picSize = parameters.getPictureSize();        }        Log.i(TAG, "picSize.width=" + picSize.width + "  picSize.height=" + picSize.height);         // 根据选出的PictureSize重新设置SurfaceView大小        float w = picSize.width;        float h = picSize.height;        parameters.setPictureSize(picSize.width,picSize.height);        this.setLayoutParams(new FrameLayout.LayoutParams((int) (height*(h/w)), height));        // 获取摄像头支持的PreviewSize列表        List<Camera.Size> previewSizeList = parameters.getSupportedPreviewSizes();        for (Camera.Size size : previewSizeList) {            Log.i(TAG, "previewSizeList size.width=" + size.width + "  size.height=" + size.height);        }        Camera.Size preSize = getProperSize(previewSizeList, ((float) height) / width);        if (null != preSize) {            Log.i(TAG, "preSize.width=" + preSize.width + "  preSize.height=" + preSize.height);            parameters.setPreviewSize(preSize.width, preSize.height);        }        parameters.setJpegQuality(100); // 设置照片质量        if (parameters.getSupportedFocusModes().contains(android.hardware.Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {            parameters.setFocusMode(android.hardware.Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);// 连续对焦模式        }        mCamera.cancelAutoFocus();//自动对焦。        // 设置PreviewDisplay的方向,效果就是将捕获的画面旋转多少度显示        // TODO 这里直接设置90°不严谨,具体见https://developer.android.com/reference/android/hardware/Camera.html#setPreviewDisplay%28android.view.SurfaceHolder%29        mCamera.setDisplayOrientation(90);        mCamera.setParameters(parameters);    }    /**     * 从列表中选取合适的分辨率     * 默认w:h = 4:3     * <p>tip:这里的w对应屏幕的height     *            h对应屏幕的width<p/>     */    private Camera.Size getProperSize(List<Camera.Size> pictureSizeList, float screenRatio) {        Log.i(TAG, "screenRatio=" + screenRatio);        Camera.Size result = null;        for (Camera.Size size : pictureSizeList) {            float currentRatio = ((float) size.width) / size.height;            if (currentRatio - screenRatio == 0) {                result = size;                break;            }        }        if (null == result) {            for (Camera.Size size : pictureSizeList) {                float curRatio = ((float) size.width) / size.height;                if (curRatio == 4f / 3) {// 默认w:h = 4:3                    result = size;                    break;                }            }        }        return result;    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74

进去的是屏幕宽高,出来的是调整好了的参数。在surfaceChanged方法中执行mCamera.startPreview(); 前调用setCameraParams(mCamera, mScreenWidth, mScreenHeight); 就可以了。最后要在AndroidManifest.xml里设置activity的方向Android:screenOrientation="portrait"代码里有很多注释,其中也有我自己调试时候的Log,大家可以自己调试下,看看不同参数的效果。昨天调参数搞到一点多,都在折腾这个函数。唉,一把辛酸泪。
身为一个相机,居然不能照相?真是太丢脸了!下面给我们的相机添加上照相的功能。照相核心代码就一句:mCamera.takePicture(null, null, jpeg);
可以看到takePicture方法有三个参数,分别是ShutterCallbackPictureCallbackPictureCallback。这里我们只用了PictureCallback

    // 拍照瞬间调用    private Camera.ShutterCallback shutter = new Camera.ShutterCallback() {        @Override        public void onShutter() {            Log.i(TAG,"shutter");        }    };    // 获得没有压缩过的图片数据    private Camera.PictureCallback raw = new Camera.PictureCallback() {        @Override        public void onPictureTaken(byte[] data, Camera Camera) {            Log.i(TAG, "raw");        }    };    //创建jpeg图片回调数据对象    private Camera.PictureCallback jpeg = new Camera.PictureCallback() {        @Override        public void onPictureTaken(byte[] data, Camera Camera) {            BufferedOutputStream bos = null;            Bitmap bm = null;            try {                // 获得图片                bm = BitmapFactory.decodeByteArray(data, 0, data.length);                if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {                    Log.i(TAG, "Environment.getExternalStorageDirectory()="+Environment.getExternalStorageDirectory());                    String filePath = "/sdcard/dyk"+System.currentTimeMillis()+".jpg";//照片保存路径                    File file = new File(filePath);                    if (!file.exists()){                        file.createNewFile();                    }                    bos = new BufferedOutputStream(new FileOutputStream(file));                    bm.compress(Bitmap.CompressFormat.JPEG, 100, bos);//将图片压缩到流中                }else{                    Toast.makeText(mContext,"没有检测到内存卡", Toast.LENGTH_SHORT).show();                }            } catch (Exception e) {                e.printStackTrace();            } finally {                try {                    bos.flush();//输出                    bos.close();//关闭                    bm.recycle();// 回收bitmap空间                    mCamera.stopPreview();// 关闭预览                    mCamera.startPreview();// 开启预览                } catch (IOException e) {                    e.printStackTrace();                }            }        }    };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54

jpeg#onPictureTaken()里。我们将存储照片信息的byte[] data解析成bitmap,然后转换成JPG格式的图片保存在SD卡中。注意finally中最后两句mCamera.stopPreview();// 关闭预览 mCamera.startPreview();// 开启预览 上文也提到:当调用camera.takePiture()方法后,camera关闭了预览,这时需要调用startPreview()来重新开启预览。如果不再次开启预览,则会一直停留在拍摄照片画面。为了方便外部调用拍照。这里我暴露了一个方法供外部拍照。

    public void takePicture(){        //设置参数,并拍照        setCameraParams(mCamera, mScreenWidth, mScreenHeight);        // 当调用camera.takePiture方法后,camera关闭了预览,这时需要调用startPreview()来重新开启预览        mCamera.takePicture(null, null, jpeg);    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

在布局文件中添加一个Button,点击Button执行takePicture()方法。不要忘了添加写SD卡限权

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  • 1
  • 1

至此,一个具有照相并保存拍摄图片功能的相机就做出来了。But,我们就此满足了吗?要是为了这些简单的功能我也不会写这篇博客。这只是个开始

真正的开始

别人APP在照相的时候,屏幕上居然可以显示像效果图那样的框框啦、辅助点啦、图片bulabulabula~。在网上搜索一番实现方式,再加上一些自己的理解,构成了这篇博客。
上文布局文件一直没有贴,现在贴出来大家先扫一眼,有些控件会在接下来展示

<?xml version="1.0" encoding="utf-8"?><FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent">    <com.dyk.cameratest.view.CameraSurfaceView        android:id="@+id/cameraSurfaceView"        android:layout_width="match_parent"        android:layout_height="match_parent" />    <com.dyk.cameratest.view.RectOnCamera        android:layout_width="match_parent"        android:layout_height="match_parent" />    <RelativeLayout        android:layout_width="match_parent"        android:layout_height="match_parent">        <Button            android:layout_alignParentBottom="true"            android:layout_centerHorizontal="true"            android:layout_marginBottom="20dp"            android:id="@+id/takePic"            android:layout_width="80dp"            android:layout_height="50dp"            android:background="#88427ac7"            android:text="拍照"            android:textColor="#aaa" />    </RelativeLayout></FrameLayout>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

布局文件的最外层是个FrameLayout,我们知道FrameLayout是自带覆盖效果的。由来这个思路接下来就很简单了。编程重要的是思想,思想有了,其余的就剩具体的实现细节。

自定义边边框框

为了和CameraSurfaceView区分开,再自定义一个RectOnCamera专门用来画边边框框这些东西。这样做还一个好处是方便维护,不至于将所有东西都放在一个View中。

RectOnCamera

package com.dyk.cameratest.view;.../** * Created by 一口仨馍 on 2016/4/7. */public class RectOnCamera extends View {    private static final String TAG = "CameraSurfaceView";    private int mScreenWidth;    private int mScreenHeight;    private Paint mPaint;    private RectF mRectF;    // 圆    private Point centerPoint;    private int radio;    public RectOnCamera(Context context) {        this(context, null);    }    public RectOnCamera(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    public RectOnCamera(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        getScreenMetrix(context);        initView(context);    }    private void getScreenMetrix(Context context) {        WindowManager WM = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);        DisplayMetrics outMetrics = new DisplayMetrics();        WM.getDefaultDisplay().getMetrics(outMetrics);        mScreenWidth = outMetrics.widthPixels;        mScreenHeight = outMetrics.heightPixels;    }    private void initView(Context context) {        mPaint = new Paint();        mPaint.setAntiAlias(true);// 抗锯齿        mPaint.setDither(true);// 防抖动        mPaint.setColor(Color.RED);        mPaint.setStrokeWidth(5);        mPaint.setStyle(Paint.Style.STROKE);// 空心        int marginLeft = (int) (mScreenWidth*0.15);        int marginTop = (int) (mScreenHeight * 0.25);        mRectF = new RectF(marginLeft, marginTop, mScreenWidth - marginLeft, mScreenHeight - marginTop);        centerPoint = new Point(mScreenWidth/2, mScreenHeight/2);        radio = (int) (mScreenWidth*0.1);    }    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        mPaint.setColor(Color.RED);        canvas.drawRect(mRectF, mPaint);        mPaint.setColor(Color.WHITE);        Log.i(TAG, "onDraw");        canvas.drawCircle(centerPoint.x,centerPoint.y, radio,mPaint);// 外圆        canvas.drawCircle(centerPoint.x,centerPoint.y, radio - 20,mPaint); // 内圆    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63

这里简单的画了一个类似二维码扫描的框框,还有一个类似聚焦的内外圆。那么问题来了,聚焦的内外圆要随着手指滑而改变位置,而且要有聚焦的效果。可又和具有聚焦功能的CameraSurfaceView不是同一个类,不仅如此聚焦内外圆还完全覆盖了CameraSurfaceView。要处理这种问题,需要接口回调。这就是思想下面的细节。现在虽然确定接口回调,但还有一个问题,CameraSurfaceView类和RectOnCamera类中都没有对方的对象或者引用。没错,通过共同持有RectOnCameraCameraSurfaceViewActivity可以实现此功能。下面是具体的实现方法

动起来

首先,想要随着手指的滑动而改变RectOnCamera的位置肯定是要复写onTouchEvent()方法

    @Override    public boolean onTouchEvent(MotionEvent event) {        switch (event.getAction()){            case MotionEvent.ACTION_DOWN:            case MotionEvent.ACTION_MOVE:            case MotionEvent.ACTION_UP:                int x = (int) event.getX();                int y = (int) event.getY();                centerPoint = new Point(x, y);                invalidate();                return true;        }        return true;    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

其次,定义回调接口

 private IAutoFocus mIAutoFocus;    /** 聚焦的回调接口 */    public interface  IAutoFocus{        void autoFocus();    }    public void setIAutoFocus(IAutoFocus mIAutoFocus) {        this.mIAutoFocus = mIAutoFocus;    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

onTouchEvent()return前加入

  if (mIAutoFocus != null){      mIAutoFocus.autoFocus();  }
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

至此我们的回调接口已经定义好了,此时还需要CameraSurfaceView暴露一个聚焦方法,以便Activity调用

    public void setAutoFocus(){        mCamera.autoFocus(this);    }
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

准备工作已经全部完成,下面请看Activity的具体实现:

public class MainActivity extends Activity implements View.OnClickListener,RectOnCamera.IAutoFocus{    private CameraSurfaceView mCameraSurfaceView;    private RectOnCamera mRectOnCamera;    private Button takePicBtn;    private boolean isClicked;    @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_main);        mCameraSurfaceView = (CameraSurfaceView) findViewById(R.id.cameraSurfaceView);        mRectOnCamera = (RectOnCamera) findViewById(R.id.rectOnCamera);        takePicBtn= (Button) findViewById(R.id.takePic);        mRectOnCamera.setIAutoFocus(this);        takePicBtn.setOnClickListener(this);    }    @Override    public void onClick(View v) {        switch (v.getId()){            case R.id.takePic:                mCameraSurfaceView.takePicture();                break;            default:                break;        }    }    @Override    public void autoFocus() {        mCameraSurfaceView.setAutoFocus();    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

可以看到,MainActivity实现了IAutoFocus接口,并且在复写的IAutoFocus#autoFocus()方法中,调用了CameraSurfaceView暴露出来的方法setAutoFocus()。至此,在RectOnCamera每次的滑动过程中都会改变聚焦内外圆的位置,还会增加聚焦功能。一心二用甚至一心多用岂不是更好。

结束语

在经历两次断电没保存和一次CSDN服务器错误内容丢失之后终究还是完成了这篇博客,实属不易。十分感谢能听我啰嗦到结尾~

PS:Demo界面并没有做的很精致,只是提供了一种思路。按照此思路能做出比较华丽的效果,授人以鱼不如授人以渔。

2016.10.12 在经历了上述种种磨难之后,终于发表了这篇博文,然而发表没几天,被我自己覆盖了。这下博文是真的丢了。心塞ing。今天没事百度下自己CSDN昵称“一口仨馍”,发现其他网站爬过这篇博文,随后我复制了自己原创的博文,再次发表。感谢那些爬我博文还不署名的网站。谢谢你全家。

源码下载

http://download.csdn.net/detail/qq_17250009/9484160

(function () {('pre.prettyprint code').each(function () { var lines = (this).text().split(\n).length;varnumbering = $('
    ').addClass('pre-numbering').hide(); (this).addClass(hasnumbering).parent().append(numbering); for (i = 1; i
    0 0
    原创粉丝点击
    热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 电压力锅排气阀漏气怎么办 win10系统上不了网怎么办 手机自拍杆坏了怎么办 车辆遭核生化打击时怎么办? 遭核生化打击时怎么办? 车辆行驶中遭核生化打击时怎么办? 硫酸气体熏到嗓子怎么办 硫酸味儿进嗓子了怎么办 吸入二氧化氯气体后怎么办 衣服84消毒 变色了怎么办 我的身份证被诈骗犯知道了怎么办 母婴店来客人少怎么办 键盘驱动被卸载了怎么办 广州 狗狗随地大小便怎么办 上海 狗狗随地大小便怎么办 服装店人流量少生意差怎么办 2018年服装店生意特别差怎么办 打印机拍的照片打出黑怎么办 租的汽车撞了怎么办 神州租车车坏了怎么办 深圳市公安局办保安员证怎么办? 老婆被车撞了后失忆了怎么办 生气引起的短暂失忆怎么办 win10系统忘记开机密码怎么办 戴尔win10密码忘了怎么办 戴尔电脑win10密码忘了怎么办 出门忘记带身份证了怎么办 一年染了7次头发怎么办 低头久了颈椎疼怎么办 一只眼睛磨得慌怎么办 没有睡好眼睛痛怎么办 好几天没休息好怎么办 血糖高睡不好觉怎么办 眼睛感觉磨的慌怎么办 痔疮手术后大便疼肛裂痛怎么办 肛裂排便困难痛怎么办 智齿导致的牙疼怎么办 肛裂一直不愈合怎么办 孕妇肛裂拉屎疼怎么办 产后50天小肚子突出怎么办 肚子像怀孕一样大怎么办