Android长截图的实现

标签: android jni 长截图
34人阅读 评论(0) 收藏 举报
分类:

源码:https://github.com/zengfw/LongScreenShot

支持截取微博、知乎、今日头条等第三方APP……

先瞅瞅效果图:
效果图

再瞅瞅最终的长截图:

我是长截图一,瞅瞅嘛…

我是长截图二,再瞅一下嘛…

上一周脑子突然冒出长截图这个功能,想着如何截取如微博,知乎,头条等这些第三方APP的界面呢?出于好奇心,花了一周业余时间,撸一个看看。

不就是截屏+拼图,还能有什么难度么?这个。。。好像确实是。

Question:

1.如何截屏?

Android 5.0 API 21之前,想要系统截屏,是需要root,不过Android 5.0开始开放了响应的截屏接口:

MediaProjection (added in API level 21.)
- A token granting applications the ability to capture screen contents and/or record system audio. The exact capabilities
granted depend on the type of MediaProjection.

2.如何优雅的截图?

悬浮窗那么小,难道每次我都得滑一定的距离,然后点一次悬浮窗么,理论上可以,但体验不好。估计更多人倾向只要触摸屏幕就可以截图,所以选择监听悬浮窗外的触屏事件。

3.如何监听悬浮窗口外部的TouchEvent?

悬浮窗外的触屏事件都已经脱离整个应用了,如何监听呢?这里确实卡了些时间,因为确实找不到如何捕获这个事件的好,我感觉这个问题也是最烦的一个,后来来了点灵感,我设置一个全屏的透明背景,然后给这个背景设置onTouch事件,哦!!!恍然大悟,以为这样就可以了?错!!这样会出现整个手机的事件都将被这个透明背景拦截,无法传递到手机桌面,如果非开发人员安装了这个软件。。,告诉他,重新开机吧。。。所以翻了下WindowManager的源码,看到flag参数,把各种flag参数的注释看了遍,最后定位在如下几个flag参数值上。


        /** Window flag: this window won't ever get key input focus, so the
         * user can not send key or other button events to it.  Those will
         * instead go to whatever focusable window is behind it.  This flag
         * will also enable {@link #FLAG_NOT_TOUCH_MODAL} whether or not that
         * is explicitly set.
         *
         * <p>Setting this flag also implies that the window will not need to
         * interact with
         * a soft input method, so it will be Z-ordered and positioned
         * independently of any active input method (typically this means it
         * gets Z-ordered on top of the input method, so it can use the full
         * screen for its content and cover the input method if needed.  You
         * can use {@link #FLAG_ALT_FOCUSABLE_IM} to modify this behavior. */
        public static final int FLAG_NOT_FOCUSABLE      = 0x00000008;

        /** Window flag: this window can never receive touch events. */
        public static final int FLAG_NOT_TOUCHABLE      = 0x00000010;

        /** Window flag: even when this window is focusable (its
         * {@link #FLAG_NOT_FOCUSABLE} is not set), allow any pointer events
         * outside of the window to be sent to the windows behind it.  Otherwise
         * it will consume all pointer events itself, regardless of whether they
         * are inside of the window. */
        public static final int FLAG_NOT_TOUCH_MODAL    = 0x00000020;
        /** Window flag: if you have set {@link #FLAG_NOT_TOUCH_MODAL}, you
         * can set this flag to receive a single special MotionEvent with
         * the action
         * {@link MotionEvent#ACTION_OUTSIDE MotionEvent.ACTION_OUTSIDE} for
         * touches that occur outside of your window.  Note that you will not
         * receive the full down/move/up gesture, only the location of the
         * first down as an ACTION_OUTSIDE.
         */
        public static final int FLAG_WATCH_OUTSIDE_TOUCH = 0x00040000;

在全屏透明背景的环境下,本以为可以监听桌面的Down、Move、Up事件,但是出现事件全部被拦截死在这个透明背景上,无法传到手机桌面,再发现组合这些参数,总结这种思路不可取。

查看注释可以知道设置FLAG_WATCH_OUTSIDE_TOUCH可以在窗口外部(即App外部)接收一个指定事件MotionEvent#ACTION_OUTSIDE,但同时,你将无法接收到任何的Down、Move、Up事件。所以,也只能这样了。。有其它高招的兄弟指点下哈。

4.如何控制截屏频次?

在步骤3的基础上,基本可以做一个截图策略了,比如,每接收一次ACTION_OUTSIDE就截一次图,又或者,每次监听一次ACTION_OUTSIDE,就进行一次计数器的累加,为了保证截图能承上启下连贯,可以设置阈值为2这样。

5.如何拼图?

这里因人而异了,但目的都一样,将上述步骤所截的图对比出不同的地方,然后把不同的地方拼接起来。出于运算效率考虑,这里我是用JNI来实现的,主函数:

JNIEXPORT void JNICALL Java_com_zfw_screenshot_utils_SewUtils_merge(
        JNIEnv *env, jobject thiz, jobject bmp0, jobject bmp1, jobject bmp2, int h0, int h1, int h2, int samePart, int len) {

    int *pixels_0 = lockPixel(env, bmp0);
    int *pixels_1 = lockPixel(env, bmp1);
    int *pixels_2 = lockPixel(env, bmp2);
    /* -------------------- merge the difference ----------------------- */
    int index = 0;
    while(index < h0) {
        if(index < h1) {
            getRowPixels(pixels_0, index, pixels_1, index, len);
        } else {
            getRowPixels(pixels_0, index, pixels_2, index - h1 + samePart, len);
        }
        index++;
    }
    /* -------------------- merge the difference ----------------------- */
    unlockPixel(env, bmp0);
    unlockPixel(env, bmp1);
    unlockPixel(env, bmp2);
}

功能实现上没什么难度,感觉更多的是得选好实现的策略,比如如何优雅的监听悬浮窗外的Touch事件,如何优雅的实现一个“定点”截图的策略,如何优雅的对比两个Bitmap的不同地方,进行拼接。

源码传送门:https://github.com/zengfw/LongScreenShot

有什么好的策略以及问题,欢迎留言,一起探讨哈,看看有没有更优雅的实现方式!

查看评论

截屏的各种实现(全屏or长截屏)

全屏截图+ViewGroup的长截图
  • lpy1223745637
  • lpy1223745637
  • 2017-01-19 17:28:01
  • 1571

截屏与截长图功能的实现

Demo在GitHub的地址:https://github.com/Hebin320/ScreenShootDemo在CSDN上的下载地址:http://download.csdn.net/detai...
  • Hebin320320
  • Hebin320320
  • 2016-04-14 15:09:25
  • 11258

Android长截图与长图分享

1.第一步如何实现长截图Android长截屏– ScrollView,ListView及RecyclerView截屏 这个链接地址写的很清楚了,建议进行实际操作。概述:其实长截图就是将布局存成图像...
  • u013290250
  • u013290250
  • 2017-11-10 12:05:39
  • 597

Android实现截屏和截长图功能的几种方法

一般情况下各种型号的手机都会有自带的截屏功能,也会有诸如“开关机键+音量键”的截屏快捷键,只要手机是亮屏状态,都会将手机屏幕的可视区域(包含状态栏)全部截取下来。如果开发中想要调取系统的截屏功能,理论...
  • Vip99521
  • Vip99521
  • 2018-03-23 18:56:21
  • 270

Android给scrollView截图超过屏幕大小形成长图

很多的时候,我们想要分享一个界面的所有内容,可是内容太多,超过了屏幕的大小,简单的截屏已经满足不了我们的需要,这时候我们就可以根据布局里scrollView的高度来截取图片。 代码如下: /** ...
  • lyy1104
  • lyy1104
  • 2014-10-13 17:44:38
  • 12099

Android之WebView网页滚动截图

WebView 网页滚动截屏,可对整个网页进行截屏而不是仅当前屏幕哦! 注意若Web页面存在position:fixed; 的话得在调用前设置为 position:absolute; 哦,否则会出现...
  • zsjangel
  • zsjangel
  • 2016-07-01 23:41:03
  • 3214

android长截屏beta1

package com.example.wanjian.test; import android.graphics.Bitmap; import android.graphics.Canvas; i...
  • qq909157370
  • qq909157370
  • 2016-08-19 11:02:02
  • 1190

安卓截图代码 安卓截取长屏代码

在Android开发中,有时候会遇到需要截屏分享到朋友圈或者QQ,截屏有截取当前屏幕,也有需要截取不仅一个屏幕,可能会很长。截取当前屏幕并保存到内存卡的方法: // 获取指定Activity的截屏,保...
  • windboy2014
  • windboy2014
  • 2016-09-23 17:02:44
  • 2392

Android截屏与WebView长图分享经验总结

一、概述最近在做新业务需求的同时,我们在 Android 上遇到了一些之前没有碰到过的问题,截屏分享、 WebView 生成长图以及长图在各个分享渠道分享时图片模糊甚至分享失败等问题,在这过程中踩了很...
  • duanyy1990
  • duanyy1990
  • 2017-05-19 18:44:28
  • 2164

android 长布局截图(listView ScrollView)

ScrollView ListView截图 长微博 截图 /** * 截取scrollview的屏幕 * **/ public static Bitmap ge...
  • wlong610
  • wlong610
  • 2015-12-03 17:35:46
  • 1586
    个人资料
    持之以恒
    等级:
    访问量: 4万+
    积分: 946
    排名: 5万+
    最新评论