这次分享的功能比较简单,是osc的截屏模块,效果如下

图片说明文字

这个功能用户体验还是不错的,在很多软件都也都内置了这个功能

这个功能的原理是:

1.在需要截屏的activity的window上覆盖一个ScreenShotView

2.用户选定了截屏区域并双击后,ScreenShotView就会把当前activity的Decview画到一个canvas上,并进行裁剪图片和保存

具体实现过程:

时序图如下:
图片说明文字

1.由于这些操作都是在UIHelper中完成的,所以这里从UIHelper开始,之前是在新闻详情页面点击分享按钮就调用UIHelper来生成contextmenu了 如果此时用户选择了截屏分享,那么就会开始上图的流程了首先是addScreenShot函数的执行

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
addScreenShot(context, new OnScreenShotListener() {

                                @SuppressLint("NewApi")
                                public void onComplete(Bitmap bm) {
                                    Intent intent = new Intent(context,ScreenShotShare.class);
                                    intent.putExtra("title", title);
                                    intent.putExtra("url", url);
                                    intent.putExtra("cut_image_tmp_path",ScreenShotView.TEMP_SHARE_FILE_NAME);
                                    try {
                                        ImageUtils.saveImageToSD(context,ScreenShotView.TEMP_SHARE_FILE_NAME,bm, 100);
                                    } catch (IOException e) {
                                        e.printStackTrace();
                                    }
                                    context.startActivity(intent);
                                }
                            });

很简单,就是传入了context 并实现了一个listener,这个listener用来处理ScreenShotview的回调,addScreenShot函数如下:我们来一步步分析:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
/**
     * 添加截屏功能
     */
    @SuppressLint("NewApi")
    public static void addScreenShot(Activity context,
            OnScreenShotListener mScreenShotListener) {
        BaseActivity cxt = null;
        if (context instanceof BaseActivity) {
            cxt = (BaseActivity) context;
            cxt.setAllowFullScreen(false);
            ScreenShotView screenShot = new ScreenShotView(cxt,
                    mScreenShotListener);
            LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT,
                    LayoutParams.MATCH_PARENT);
            context.getWindow().addContentView(screenShot, lp);
        }
    }

2.初始化ScreenShotView 这个构造函数主要是给当前的ScreenShotView添加了一个遮罩,也就是我们点击截屏后会显示为灰色然后让用户滑动选择截屏区域

 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
@SuppressLint("NewApi")
    public ScreenShotView(BaseActivity context, OnScreenShotListener listener) {
        super(context);

        mListener = listener;
        mContext = context;
        mContext.setAllowDestroy(false, this);

        Point p = getDisplaySize(context.getWindowManager().getDefaultDisplay());
        screenWidth = p.x;
        screeenHeight = p.y;

        mGrayPaint = new Paint();
        mGrayPaint.setARGB(100, 0, 0, 0);

        topRect = new Rect();
        rightRect = new Rect();
        bottomRect = new Rect();
        leftRect = new Rect();

        topRect.set(0, 0, screenWidth, screeenHeight);

        setOnTouchListener(this);

        if(bmDoubleClickTip==null){
            bmDoubleClickTip = BitmapFactory.decodeStream(getResources().openRawResource(R.drawable._pointer));
        }

        UIHelper.ToastMessage(mContext, "请滑动手指确定选区!");
    }

ScreenShotView的其他处理也是围绕怎么跟随用户画出选区展开的,这里就不一一描述了
3.初始化完毕了ScreenShotView只会 会调用

1
2
3
LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT,
                    LayoutParams.MATCH_PARENT);
            context.getWindow().addContentView(screenShot, lp);

这样就把ScreenShotView添加到了当前的activity的window中去了.
4.如果用户操作完之后,双击了屏幕,经过一系列的判断,就会执行回调了,代码如下:

mListener.onComplete(getCutImage());

5-8 我们看一下getCutImage函数,原来是先获取当前decorview的bitmap,然后按照用户操作界面计算出来的模板进行裁剪 就得到截图区域的bitmap了

 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
/**
     * 截取内层边框中的View.
     */
    private Bitmap getCutImage() {
        View view = mContext.getWindow().getDecorView();
        Bitmap bmp = Bitmap.createBitmap(view.getWidth(), view.getHeight(),
                Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bmp);
        view.draw(canvas);
        return imageCrop(bmp);
    }

    /**
     * 裁剪图片
     */
    private Bitmap imageCrop(Bitmap bitmap) {
        int x =  left<0?0:left;
        int y = top + getStatusHeight();
        int width = right- left;
        int height = bottom - top;
        if((width+x)>bitmap.getWidth()){
            width = bitmap.getWidth()-x;
        }
        if((y+height)>bitmap.getHeight()){
            height = bitmap.getHeight()-y;
        }
        return Bitmap.createBitmap(bitmap,x,y,width,height , null, false);
    }

9.拿到这个bitmap ,就可以在UIHelper中进行分享和保存了

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
addScreenShot(context, new OnScreenShotListener() {

                                @SuppressLint("NewApi")
                                public void onComplete(Bitmap bm) {
                                    Intent intent = new Intent(context,ScreenShotShare.class);
                                    intent.putExtra("title", title);
                                    intent.putExtra("url", url);
                                    intent.putExtra("cut_image_tmp_path",ScreenShotView.TEMP_SHARE_FILE_NAME);
                                    try {
                                        ImageUtils.saveImageToSD(context,ScreenShotView.TEMP_SHARE_FILE_NAME,bm, 100);
                                    } catch (IOException e) {
                                        e.printStackTrace();
                                    }
                                    context.startActivity(intent);
                                }
                            });

当然,其实在实际开发中,我们只需要调用这个ScreenShotView就可以了.

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐