Android截屏一键分享开发与实现方式的反思和总结

本文主要记录android系统截屏一键分享开发,后续优化。

近期接到新需求,需要做截屏,然后弹出小窗口,显示一键分享与截屏小图预览。类似于同花顺app截图弹出框,点击后出现分享界面.

效果图如下:

         

·一,分析该需求的整个流程,大致步骤如下

  • 1,监听到截图的动作
  • 2,获取当前图像
  • 3,弹出提示框(显示截屏预览小图,带计时器自动隐藏)
  • 4,点击分享后弹出分享窗,分享图片预览
  • 5,点击某个平台后,生成自定义拼图分享到第三方

   其中监听截图动作,和图片展示与拼接是重点步骤。

二,实现方式,技术选择

    1,目前兼容性较高的截图监听方案为ContentObserver,可以兼容到android9.0。android10目前还在调研中(目前未发现有效方法)

     具体代码不多赘述,百度一大把,标准套路,记录几个核心问题,首先解决如何精准拿到截图问题。

    String[] KEYWORDS = { "screenshot", "screenshots", "screen_shot", "screen-shot", "screen shot", "screencapture",      "screen_capture", "screen-capture", "screen capture", "screencap", "screen_cap", "screen-cap", "screen cap", "截屏" }

    过滤拿到的路径是否包含上述关键词,此时,没必要继续拿图片,只是监听到有截图动作即可,调用view截图生成bitmap方式,这样,保证最准确。同时,可以排除无用信息提示框,Toast等窗口。

     

此方法生成当前窗口的截图
/ * 截取当前窗体的截图,根据[isShowStatusBar]判断是否包含当前窗体的状态栏
 * 原理是获取当前窗体decorView的缓存生成图片
 */
public static Bitmap captureWindow(Activity activity) {

    boolean isStatuBar = false;
    // 获取当前窗体的View对象
    View view = activity.getWindow().getDecorView();
    view.setDrawingCacheEnabled(true);
    // 生成缓存
    view.buildDrawingCache();

    Bitmap bitmap = null;
    if (isStatuBar) {
        // 绘制整个窗体,包括状态栏
        bitmap = Bitmap.createBitmap(view.getDrawingCache(), 0, 0, view.getMeasuredWidth(),                         view.getMeasuredHeight());
    } else {
        // 获取状态栏高度
        Rect rect = new Rect();
        view.getWindowVisibleDisplayFrame(rect);
        Display display = activity.getWindowManager().getDefaultDisplay();

        // 减去状态栏高度
       bitmap = Bitmap.createBitmap(view.getDrawingCache(), 0,
                rect.top, display.getWidth(), display.getHeight() - rect.top);
    }

    view.setDrawingCacheEnabled(false);
    view.destroyDrawingCache();

    return bitmap;
}

 生成bitmap 之后,考虑如何添加到当前Activity。方式有三种Popuwindow, dialog,和直接addView 方式。综合考虑,直接addView添加小窗口最合适。考虑如下,PopuWindow 和dialog弹出后,会抢占焦点,这样无法继续与原界面交互,那么倒计时小时的功能也变的无用。

 为了考虑通用型,每个Activity可以操作到的根布局为contentView ,为Framelayout。

//直接拿到contentView然后Inflate窗口view。设置好位置后,addView 到contentView,这样,使用倒计时销毁时,直接contentView.remove()即可。保证了每个界面添加的通用型,即使嵌套Fragment,也不用考虑焦点问题。

final ViewGroup viewById = mContext.findViewById(android.R.id.content);
final View view = View.inflate(mContext,R.layout.screen_shot_dialog,null);

FrameLayout.LayoutParams f = new FrameLayout.LayoutParams(width,height);

f.gravity = Gravity.CENTER_VERTICAL | Gravity.RIGHT;

f.rightMargin = DisplayUtil.dip2px(mContext,20); 

view.setLayoutParams(f);

final Bitmap bitmap = Utils.captureWindow(mContext); //获取当前窗口影像图片 替代从文件库取

imageView.setImageDrawable(new BitmapDrawable(bitmap)); 

viewById.addView(view);//最终添加到当前Activity

2,自定义分享图片的拼接问题。

   思路有二,一可以使用canvas绘制bitmap,拼接。方法主要难点在绘制位置,以及性能开销。(标准API,课自行百度)

                    二,可以同样借鉴View生成图片方案,先创建一个布局,在相关位置填好截屏图片,二维码,文字等。然后生成bitmap。注意,在调用以下方法,view必须添加到布局且重绘完毕,所以,可以使用view.postRunable()。在runalbe任务里面生成图片,以保证view准备完毕。

/**
 *抓取view 影像图片
 */
public static Bitmap captureView(View view) {

    
    view.setDrawingCacheEnabled(true);
    // 生成缓存
    view.buildDrawingCache();

    Bitmap bitmap = null;
    
    // 绘制整个view
    bitmap = Bitmap.createBitmap(view.getDrawingCache(), 0, 0,view.getWidth(), view.getHeight());
  

    view.setDrawingCacheEnabled(false);
    view.destroyDrawingCache();
    return bitmap;
}

在此注意,可以先添加到contentview 中,设置为隐藏,待生成完毕后,再移除掉。以保证生成正确。

               final View shareView = View.inflate(mContext,R.layout.share_view_splash,null);//用于生成分享图片的布局
               final ImageView iv_shot_share = shareView.findViewById(R.id.iv_shot_share);

               shareView.setVisibility(View.INVISIBLE);//设置为不可见,但是占用空间
                           contentView.addView(shareView);
                           contentView.requestLayout();
                            iv_shot_share.post(new Runnable() {//使用post方法,保证view绘制完毕
                                @Override
                                public void run() {
                                           Bitmap shareImg = Utils.captureView(shareView);//生成图片

                                            shareView.setVisibility(View.GONE);
                                            contentView.removeView(shareView);//移除
                                        }
                                    });
                                }
                            });

3,关于截屏预览裁剪。

   Android  ImageVIew中现有的适配模式,centerCrop 等,无法满足,宽度充满,从顶部往下,超出则截掉的需求。所以,在ImageView 设置预览图时,需要对生成窗口视图bitmap进行二次处理。思路,使用Matrix将窗口视图缩放到与要展示的容器宽度比例。然后重新生成图片,从顶部开始,截出新图片。

public static Bitmap reClip(Bitmap bitmapOri,int widthTarget,int heightTarget){//xxxTarget 为ImageView 容器宽高

        int width = bitmapOri.getWidth();
        int height = bitmapOri.getHeight();

        Bitmap bitmap = null;

        float scaleWidth = (float) (widthTarget/1.0/width);

        //缩放
        Matrix matrix = new Matrix();
        matrix.postScale(scaleWidth,scaleWidth);

        Bitmap bitmapScale = Bitmap.createBitmap(bitmapOri,0,0,width,height,matrix,false);//按照缩放比例生成新图

       //在此要做判断,新截图片不能大于原始图片高度。否则异常终止,尤其注意普通屏幕,一般没问题。全面屏,不做此判断,会出现崩               溃,具体和要展示的容器宽高有关
        if(bitmapScale.getHeight()> heightTarget){
            bitmap = Bitmap.createBitmap(bitmapScale,0,0,bitmapScale.getWidth(),heightTarget);
        }else{
            bitmap = Bitmap.createBitmap(bitmapScale,0,0,bitmapScale.getWidth(),bitmapScale.getHeight());
        }


        return bitmap;
    }

使用bitmap 注意及时回收。

4,关于分享图片问题,生成的本地图片保存到公共空间,

Environment.getExternalStorageDirectory()//比如这里

开发中,保存到应用包名下(context.getCacheDir),微信可以,但是QQ会出现无反应问题,报错信息也不明显。原因是读取权限问题,之后android10 还会进一步限制,所以,涉及到第三方app传递文件时,注意存储位置。

发布了4 篇原创文章 · 获赞 15 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/zpjsmalltime/article/details/104921880