Talking about Android Screenshot and Specifying View to Generate Screenshot

  • 2021-12-13 09:28:21
  • OfStack

Screenshot of current page of directory (intercepting the whole screen) intercepting common View intercepting ScrollView intercepting ListView intercepting RecyclerView intercepting WebView

Screenshot of the current page (capturing the whole screen)

Take a screenshot of the current Activity page, which can be cached through decorView at the bottom of the form, and then generate a picture according to this cached object. Some need not need the status bar, you can also specify the width and height of the generated picture, and remove the status bar.


/**
 *  Capture a screenshot of the current form, according to the [isShowStatusBar] Determines whether to include the status bar of the current form 
 *  The principle is to get the current form decorView Generate pictures from the cache of 
 */
fun captureWindow(activity: Activity, isShowStatusBar: Boolean): Bitmap? {
    //  Object of the current form View Object 
    val view = activity.window.decorView
    view.isDrawingCacheEnabled = true
    //  Generate cache 
    view.buildDrawingCache()

    val bitmap = if (isShowStatusBar) {
        //  Draws the entire form, including the status bar 
        Bitmap.createBitmap(view.drawingCache, 0, 0, view.measuredWidth, view.measuredHeight)
    } else {
        //  Get the height of the status bar 
        val rect = Rect()
        view.getWindowVisibleDisplayFrame(rect)
        val display = activity.windowManager.defaultDisplay

        //  Subtract the height of the status bar 
        Bitmap.createBitmap(view.drawingCache, 0,
                rect.top, display.width, display.height - rect.top)
    }

    view.isDrawingCacheEnabled = false
    view.destroyDrawingCache()

    return bitmap
}

Intercept commonly used View

Be sure that View has been drawn before interception, so be careful to use post method to ensure that View is drawn. Some shared screenshot pages are not in the UI style currently displayed to users, so a container can be hidden in the current layout to store screenshots, and this container is not displayed to users.


/**
  * View Has been shown on the interface, and can be obtained directly View Cache of 
  *  Right View Generate after measurement and layout View Cache of 
  * View Is a fixed-size View , including TextView,ImageView,LinearLayout,FrameLayout,RelativeLayout Etc 
  * @param view  Intercepted View,View Must have a fixed size, otherwise drawingCache Return null
  * @return  Generated Bitmap
  */
fun captureView(view: View): Bitmap? {
        view.isDrawingCacheEnabled = true
        view.buildDrawingCache()
        //  Re-measurement 1 Pass View Width and height of 
        view.measure(View.MeasureSpec.makeMeasureSpec(view.width, View.MeasureSpec.EXACTLY),
                View.MeasureSpec.makeMeasureSpec(view.height, View.MeasureSpec.EXACTLY))
        //  Determine View Location of 
        view.layout(view.x.toInt(), view.y.toInt(), view.x.toInt() + view.measuredWidth,
                view.y.toInt() + view.measuredHeight)
        //  Generate View Width and height 1 Like Bitmap
        val bitmap = Bitmap.createBitmap(view.drawingCache, 0, 0, view.measuredWidth,
                view.measuredHeight)
        view.isDrawingCacheEnabled = false
        view.destroyDrawingCache()
        return bitmap
}

Intercept ScrollView

The difficulty of ScrollView screenshot is that the height of ScrollView is uncertain. If the height can be determined, you can use the cache of ScrollView to generate pictures. ScrollView has only one child View, so the height of ScrollView can be determined only by measuring the child View and obtaining the height of the child View.


/**
 *  Interception ScrollerView
 *  The principle is to get scrollView Son of View The height of, and then create 1 Sub View Wide and high canvas, which will ScrollView Draw on a canvas 
 * @param scrollView  Control 
 * @return  Return to the after the screenshot Bitmap
 */
fun captureScrollView(scrollView: ScrollView): Bitmap? {
     var h = 0
     for (i in 0 until scrollView.childCount) {
         val childView = scrollView.getChildAt(i)
         //  Acquirer View The height of 
         h += childView.height
         //  Set the background color to avoid the background color not set in the layout and the background of the cut-off image is black 
         childView.setBackgroundColor(Color.parseColor("#FFFFFF"))
     }

     val bitmap = createBitmap(scrollView.width, h)
     val canvas = Canvas(bitmap)
     //  Will ScrollView Draw on a canvas 
     scrollView.draw(canvas)
     return bitmap
}

Intercept ListView

The principle of ListView screenshot is to obtain Bitmap object of every sub-View, then use Paint to splice screenshots of sub-View onto Canvas according to the height of sub-View, and finally generate a screenshot containing all sub-View.


/**
 *  Interception ListView
 *  Principle: Get every 1 Sub View , will son View Generated bitmap Save into the collection and accumulate ListView Height 
 *  After the traversal is complete, create 1 A ListView A canvas of the size of the collection, and the Bitmap Draw to canvas 
 * @param listView  Screenshot control object 
 * @return  Generated screenshot object 
 */
fun captureListView(listView: ListView): Bitmap? {
        val adapter = listView.adapter
        val itemCount = adapter.count
        var allitemsheight = 0
        val bitmaps = ArrayList<Bitmap>()

        for (i in 0 until itemCount) {
            //  Gets every 1 Sub View
            val childView = adapter.getView(i, null, listView)
            //  Measure width and height 
            childView.measure(
                    View.MeasureSpec.makeMeasureSpec(listView.width, View.MeasureSpec.EXACTLY),
                    View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED))

            //  Layout position 
            childView.layout(0, 0, childView.measuredWidth, childView.measuredHeight)
            //  Set the background color to avoid black 
            childView.setBackgroundColor(Color.parseColor("#FFFFFF"))
            childView.isDrawingCacheEnabled = true
            //  Generate cache 
            childView.buildDrawingCache()
            //  Will each 1 A View Add screenshots of to the collection 
            bitmaps.add(childView.drawingCache)
            //  Overlay screenshot height 
            allitemsheight += childView.measuredHeight
        }

        //  Create and ListView Width and height 1 A kind of canvas 
        val bitmap = createBitmap(listView.measuredWidth, allitemsheight)
        val canvas = Canvas(bitmap)

        val paint = Paint()
        var iHeight = 0f

        for (i in bitmaps.indices) {
            val bmp: Bitmap = bitmaps[i]
            //  Will each 1 Generated bitmap Draw on a canvas 
            canvas.drawBitmap(bmp, 0f, iHeight, paint)
            iHeight += bmp.height

            bmp.recycle()
        }
        return bitmap
}

Intercept RecyclerView

RecyclerView screenshot and ListView screenshot have the same principle, both of which splice the screenshots of sub-View, and finally generate a large screenshot.


/**
 *  Interception RecyclerView
 *  Principle and ListView The set is 1 Sample, get every 1 A Holder The screenshots of are put into the collection, and the final system is unified 1 Draw to Bitmap Upper 
 * @param recyclerView&emsp; Control to take a screenshot of 
 * @return  Generated screenshots 
 */
fun captureRecyclerView(recyclerView: RecyclerView): Bitmap? {
        val adapter = recyclerView.adapter
        var bigBitmap: Bitmap? = null
        if (adapter != null) {
            val size = adapter.itemCount
            var height = 0
            val paint = Paint()
            var iHeight = 0
            val maxMemory = (Runtime.getRuntime().maxMemory() / 1024).toInt()

            // Use 1/8th of the available memory for this memory cache.
            val cacheSize = maxMemory / 8
            val bitmapCache = LruCache<String, Bitmap>(cacheSize)
            for (i in 0 until size) {
                val holder = adapter.createViewHolder(recyclerView, adapter.getItemViewType(i))
                adapter.onBindViewHolder(holder, i)
                holder.itemView.measure(
                        View.MeasureSpec.makeMeasureSpec(recyclerView.width, View.MeasureSpec.EXACTLY),
                        View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED))
                holder.itemView.layout(0, 0, holder.itemView.measuredWidth,
                        holder.itemView.measuredHeight)
                holder.itemView.setBackgroundColor(Color.parseColor("#FFFFFF"))
                holder.itemView.isDrawingCacheEnabled = true
                holder.itemView.buildDrawingCache()
                val drawingCache = holder.itemView.drawingCache
                if (drawingCache != null) {
                    bitmapCache.put(i.toString(), drawingCache)
                }
                height += holder.itemView.measuredHeight
            }

            bigBitmap = createBitmap(recyclerView.measuredWidth, height)
            val bigCanvas = Canvas(bigBitmap!!)
            val lBackground = recyclerView.background
            if (lBackground is ColorDrawable) {
                val lColor = lBackground.color
                bigCanvas.drawColor(lColor)
            }

            for (i in 0 until size) {
                val bitmap = bitmapCache.get(i.toString())
                bigCanvas.drawBitmap(bitmap, 0f, iHeight.toFloat(), paint)
                iHeight += bitmap.height
                bitmap.recycle()
            }
        }
        return bigBitmap
}

Intercept WebView

WebView can load very long and complicated pages, so it is easy to overflow memory for screenshots, but there will be no big pictures to share for 1-like needs, so only simple screenshots will be made here.


/**
 *  Interception WebView , including WebView The entire length of 
 *  In WebView Before rendering, add the following code to open Html Cache, or the screen shot will be blank 
 *  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
 *      WebView.enableSlowWholeDocumentDraw()
 *  }
 *  WebView Screenshots of are prone to memory overflow problems because WebView You can load a lot of content, resulting in a very long picture. Create a Bitmap Time is easy OOM
 */
fun captureWebView(webView: WebView): Bitmap? {
        //&emsp; Recall WebView Adj. measure Method to measure the actual situation View Set the measurement mode to UNSPECIFIED Pattern means that you can get as much space as you need.) 
        webView.measure(View.MeasureSpec.makeMeasureSpec(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED),
                View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED))
        //&emsp; Call layout Method to set the layout (using the newly measured size) 
        webView.layout(0, 0, webView.measuredWidth, webView.measuredHeight)
        //&emsp; Open WebView Cache of ( When this switch is turned on, the next call is made getDrawingCache() Method will put view Draw to 1 A bitmap Upper )
        webView.isDrawingCacheEnabled = true
        //&emsp; Force the drawing cache (must be in the setDrawingCacheEnabled(true) It can only be called after, or it needs to be called manually destroyDrawingCache() Clear cache) 
        webView.buildDrawingCache()

        val bitmap = createBitmap(webView.measuredWidth, webView.measuredHeight)

        //&emsp; Has picture Create for the background 1 Canvas 
        val canvas = Canvas(bitmap)  //  Width and height of canvas  WebView  The web page of remains 1 To 
        val paint = Paint()
        //&emsp; Set the fixed point position of the brush, that is, the upper left corner 
        canvas.drawBitmap(bitmap, 0f, webView.measuredHeight * 1f, paint)
        //&emsp; Will WebView Draw on the drawing board just created 
        webView.draw(canvas)
        webView.isDrawingCacheEnabled = false
        webView.destroyDrawingCache()
        return bitmap
}

Basically, View can take screenshots, but OOM is easy to take screenshots for controls like WebView, which can load long and complex pages, so we should consider what controls to use for screenshots. The above code can be used for pro-testing.

The above is the details of Android screenshots and specifying View screenshots. For more information about Android screenshots and specifying View screenshots, please pay attention to other related articles on this site!


Related articles: