• Android滚动截屏,ScrollView截屏,Listview截屏,Recyclerview截屏


    在做分享功能的时候,需要截取全屏内容,一屏展示不完的内容,一般我们会用到 ListView ,ScrollView或Recyclerview

    一: 普通截屏的实现

    获取当前Window 的 DrawingCache 的方式,即decorView的DrawingCache

      /**
       * shot the current screen ,with the status but the status is trans *
       *
       * @param ctx current activity
       */
      public static Bitmap shotActivity(Activity ctx) {
    
        View view = ctx.getWindow().getDecorView();
        view.setDrawingCacheEnabled(true);
        view.buildDrawingCache();
    
        Bitmap bp = Bitmap.createBitmap(view.getDrawingCache(), 0, 0, view.getMeasuredWidth(),
            view.getMeasuredHeight());
    
        view.setDrawingCacheEnabled(false);
        view.destroyDrawingCache();
    
        return bp;
      }

    获取当前View的DrawingCache

       public static Bitmap getViewBp(View v) {
            if (null == v) {
                return null;
            }
            v.setDrawingCacheEnabled(true);
            v.buildDrawingCache();
            if (Build.VERSION.SDK_INT >= 11) {
                v.measure(MeasureSpec.makeMeasureSpec(v.getWidth(),
                        MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(
                        v.getHeight(), MeasureSpec.EXACTLY));
                v.layout((int) v.getX(), (int) v.getY(),
                        (int) v.getX() + v.getMeasuredWidth(),
                        (int) v.getY() + v.getMeasuredHeight());
            } else {
                v.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
                        MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
                v.layout(0, 0, v.getMeasuredWidth(), v.getMeasuredHeight());
            }
            Bitmap b = Bitmap.createBitmap(v.getDrawingCache(), 0, 0, v.getMeasuredWidth(), v.getMeasuredHeight());
    
            v.setDrawingCacheEnabled(false);
            v.destroyDrawingCache();
            return b;
        }


    二:开源方案

    在滚动视图中,如果当前View并没有在视图中全部绘制出来,我们可以利用View的ScrollTo()和ScrollBy()方法来移动画布,同时获取当前View的可视部分的DrawingCache,最后进行拼接得到其Bitmap,参考:PGSSoft/scrollscreenshot@[Github],原理图如下:

    illustration


    三: ScrollView截屏

    三个截屏中,ScrollView最简单,因为ScrollView只有一个childView,虽然没有全部显示在界面上,但是已经全部渲染绘制,因此可以直接 调用`scrollView.draw(canvas)`来完成截图,

      /**
       * http://blog.csdn.net/lyy1104/article/details/40048329
       */
      public static Bitmap shotScrollView(ScrollView scrollView) {
        int h = 0;
        Bitmap bitmap = null;
        for (int i = 0; i < scrollView.getChildCount(); i++) {
          h += scrollView.getChildAt(i).getHeight();
          scrollView.getChildAt(i).setBackgroundColor(Color.parseColor("#ffffff"));
        }
        bitmap = Bitmap.createBitmap(scrollView.getWidth(), h, Bitmap.Config.RGB_565);
        final Canvas canvas = new Canvas(bitmap);
        scrollView.draw(canvas);
        return bitmap;
      }

    四: ListView截屏

    而ListView就是会回收与重用Item,并且只会绘制在屏幕上显示的ItemView,根据stackoverflow上大神的建议,采用一个List来存储Item的视图,这种方案依然不够好,当Item足够多的时候,可能会发生oom。

    /**
       * http://stackoverflow.com/questions/12742343/android-get-screenshot-of-all-listview-items
       */
      public static Bitmap shotListView(ListView listview) {
    
        ListAdapter adapter = listview.getAdapter();
        int itemscount = adapter.getCount();
        int allitemsheight = 0;
        List<Bitmap> bmps = new ArrayList<Bitmap>();
    
        for (int i = 0; i < itemscount; i++) {
    
          View childView = adapter.getView(i, null, listview);
          childView.measure(
              View.MeasureSpec.makeMeasureSpec(listview.getWidth(), View.MeasureSpec.EXACTLY),
              View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
    
          childView.layout(0, 0, childView.getMeasuredWidth(), childView.getMeasuredHeight());
          childView.setDrawingCacheEnabled(true);
          childView.buildDrawingCache();
          bmps.add(childView.getDrawingCache());
          allitemsheight += childView.getMeasuredHeight();
        }
    
        Bitmap bigbitmap =
            Bitmap.createBitmap(listview.getMeasuredWidth(), allitemsheight, Bitmap.Config.ARGB_8888);
        Canvas bigcanvas = new Canvas(bigbitmap);
    
        Paint paint = new Paint();
        int iHeight = 0;
    
        for (int i = 0; i < bmps.size(); i++) {
          Bitmap bmp = bmps.get(i);
          bigcanvas.drawBitmap(bmp, 0, iHeight, paint);
          iHeight += bmp.getHeight();
    
          bmp.recycle();
          bmp = null;
        }
    
        return bigbitmap;
      }

    五: RecyclerView截屏

    我们都知道,在新的Android版本中,已经可以用RecyclerView来代替使用ListView的场景,相比较ListView,RecyclerView对Item View的缓存支持的更好。可以采用和ListView相同的方案,这里也是在stackoverflow上看到的方案。

    /**
       * https://gist.github.com/PrashamTrivedi/809d2541776c8c141d9a
       */
      public static Bitmap shotRecyclerView(RecyclerView view) {
        RecyclerView.Adapter adapter = view.getAdapter();
        Bitmap bigBitmap = null;
        if (adapter != null) {
          int size = adapter.getItemCount();
          int height = 0;
          Paint paint = new Paint();
          int iHeight = 0;
          final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
    
          // Use 1/8th of the available memory for this memory cache.
          final int cacheSize = maxMemory / 8;
          LruCache<String, Bitmap> bitmaCache = new LruCache<>(cacheSize);
          for (int i = 0; i < size; i++) {
            RecyclerView.ViewHolder holder = adapter.createViewHolder(view, adapter.getItemViewType(i));
            adapter.onBindViewHolder(holder, i);
            holder.itemView.measure(
                View.MeasureSpec.makeMeasureSpec(view.getWidth(), View.MeasureSpec.EXACTLY),
                View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
            holder.itemView.layout(0, 0, holder.itemView.getMeasuredWidth(),
                holder.itemView.getMeasuredHeight());
            holder.itemView.setDrawingCacheEnabled(true);
            holder.itemView.buildDrawingCache();
            Bitmap drawingCache = holder.itemView.getDrawingCache();
            if (drawingCache != null) {
    
              bitmaCache.put(String.valueOf(i), drawingCache);
            }
            height += holder.itemView.getMeasuredHeight();
          }
    
          bigBitmap = Bitmap.createBitmap(view.getMeasuredWidth(), height, Bitmap.Config.ARGB_8888);
          Canvas bigCanvas = new Canvas(bigBitmap);
          Drawable lBackground = view.getBackground();
          if (lBackground instanceof ColorDrawable) {
            ColorDrawable lColorDrawable = (ColorDrawable) lBackground;
            int lColor = lColorDrawable.getColor();
            bigCanvas.drawColor(lColor);
          }
    
          for (int i = 0; i < size; i++) {
            Bitmap bitmap = bitmaCache.get(String.valueOf(i));
            bigCanvas.drawBitmap(bitmap, 0f, iHeight, paint);
            iHeight += bitmap.getHeight();
            bitmap.recycle();
          }
        }
        return bigBitmap;
      }
     

    六: 其他屏幕相关工具

    1.获取状态来高度常见方式

     /**
         * get the height of status *
         */
        public static int getStatusH(Activity ctx) {
            Rect s = new Rect();
            ctx.getWindow().getDecorView().getWindowVisibleDisplayFrame(s);
            return s.top;
        }
     /**
         * get the height of status *
         */
        public static int getStatusH(Context ctx) {
            int statusHeight = -1;
            try {
                Class<?> clazz = Class.forName("com.android.internal.R$dimen");
                Object object = clazz.newInstance();
                int height = Integer.parseInt(clazz.getField("status_bar_height")
                        .get(object).toString());
                statusHeight = ctx.getResources().getDimensionPixelSize(height);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return statusHeight;
        }
        /**
         * get the height of status *
         */
        public static int getStatusHeight(Activity activity) {
            int resourceId = activity.getResources().getIdentifier("status_bar_height", "dimen", "android");
            return resourceId > 0 ? activity.getResources().getDimensionPixelSize(resourceId) : 0;
        }
    
    

    2.获取标题栏高度

     /**
         * get the height of title *
         */
        public static int getTitleH(Activity ctx) {
            int contentTop = ctx.getWindow()
                    .findViewById(Window.ID_ANDROID_CONTENT).getTop();
            return contentTop - getStatusH(ctx);
        }

    3.获取屏幕宽高

     /**
         * get the width of screen **
         */
        public static int getScreenW(Context ctx) {
            int w = 0;
            if (Build.VERSION.SDK_INT > 13) {
                Point p = new Point();
                ((WindowManager) ctx.getSystemService(Context.WINDOW_SERVICE))
                        .getDefaultDisplay().getSize(p);
                w = p.x;
            } else {
                w = ((WindowManager) ctx.getSystemService(Context.WINDOW_SERVICE))
                        .getDefaultDisplay().getWidth();
            }
            return w;
        }
     
     /**
         * get the height of screen *
         */
        public static int getScreenH(Context ctx) {
            int h = 0;
            if (Build.VERSION.SDK_INT > 13) {
                Point p = new Point();
                ((WindowManager) ctx.getSystemService(Context.WINDOW_SERVICE))
                        .getDefaultDisplay().getSize(p);
                h = p.y;
            } else {
                h = ((WindowManager) ctx.getSystemService(Context.WINDOW_SERVICE))
                        .getDefaultDisplay().getHeight();
            }
            return h;
        }
     /**
         * 获得屏幕高度
         *
         * @param context
         * @return
         */
        public static int getScreenWidth(Context context) {
            WindowManager wm = (WindowManager) context
                    .getSystemService(Context.WINDOW_SERVICE);
            DisplayMetrics outMetrics = new DisplayMetrics();
            wm.getDefaultDisplay().getMetrics(outMetrics);
            return outMetrics.widthPixels;
        }


    相关源码:

    ScreenUtil@[Github]

  • 相关阅读:
    数据结构学习(一)、线性表
    内容太多用省略号代替、内容不换行,鼠标移上去显示详情
    时间格式化
    51Nod--1018排序
    51Nod--1085背包问题
    51Nod--1049最大子段和
    51Nod--1051最大子矩阵和(DP入门)
    POj1852--Ants
    c# static用法
    group by用法
  • 原文地址:https://www.cnblogs.com/BoBoMEe/p/4556917.html
Copyright © 2020-2023  润新知