Android|Android 把View转为图片

在开发的过程中有时会碰到这样的需求,把一个activity或者一个view变成图片分享出去。从网上收集了一些资料之后经过整理现在分享出来,教大家实现activity,scrollview,listview,recycleview,画中画以及在后台把layout生成图片的方法。如有侵权的地方,请及时告诉我改正,谢谢。
代码在这里 https://github.com/iotxc/ScreenShootDemo
在贴方法之前我要提醒大家注意一点,view中有图片的,如果是本地图片那么网上的代码你拿过来直接用就行了,如果是根据url加载的你要注意了,直接写Glide.with(this).load(url).into(imageview); 你得到的将会是一片空白,要使用simpleTarget的回调加载图片才行

Glide.with(this) .load(url) .asBitmap() .into(new SimpleTarget() { @Override public void onResourceReady(Bitmap resource, GlideAnimation glideAnimation) { imageview.setImageBitmap(resource); } });

具体是为什么我还不清楚。

screenshoot.gif
我也不知道视频为什么会这么模糊,凑合看一下吧= =,有知道怎么做的清晰点的请留言告诉我
1. activity截图
/** * 获取指定Activity的截屏 */ public static Bitmap activityScreenShot(Activity activity) { // View是你需要截图的View View view = activity.getWindow().getDecorView(); view.setDrawingCacheEnabled(true); view.buildDrawingCache(); Bitmap bitmap = view.getDrawingCache(); // 获取状态栏高度 Rect frame = new Rect(); activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame); int statusBarHeight = frame.top; // 获取屏幕长和高 int width = activity.getWindowManager().getDefaultDisplay().getWidth(); int height = activity.getWindowManager().getDefaultDisplay().getHeight(); // 去掉标题栏 Bitmap b = Bitmap.createBitmap(bitmap, 0, statusBarHeight, width, height - statusBarHeight); view.destroyDrawingCache(); return b; }

2. scrollview截图
因为ScrollView只有一个childView,虽然没有全部显示在界面上,但是已经全部渲染绘制,因此可以直接调用scrollView.draw(canvas)来完成截图
/** * 获取scrollview的截屏 */ public static Bitmap scrollViewScreenShot(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; }

【Android|Android 把View转为图片】3. listview截图
因为listview布局复用的问题并且只能绘制在屏幕上显示的ItemView,所以我们需要把它的item放到一个view的集合里最后通过拼接来完成整图的效果。但是当Item足够多的时候,肯定会发生oom的所以记得在获得bitmap之后对其进行压缩处理。
/** * 获取listview的截屏 * @param listview * @return */ public static Bitmap shotListView(ListView listview) { ListAdapter adapter = listview.getAdapter(); int itemscount = adapter.getCount(); int allitemsheight = 0; List bmps = new ArrayList(); //循环对listview的item进行截图, 最后拼接在一起 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(); //这里可以把listview中单独的item进行保存 //viewSaveToImage(childView.getDrawingCache()); } int w = listview.getMeasuredWidth(); Bitmap bigbitmap = Bitmap.createBitmap(w, 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; }

4. recycleview截图
recycleview和listView使用相同的方案
/** * recycleview截图 * @param view * @return */ 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 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; }

5. 任意View转bitmap
/** * view转bitmap */ public Bitmap viewConversionBitmap(View v) { int w = v.getWidth(); int h = v.getHeight(); Bitmap bmp = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); Canvas c = new Canvas(bmp); c.drawColor(Color.WHITE); /** 如果不设置canvas画布为白色,则生成透明 */v.layout(0, 0, w, h); v.draw(c); return bmp; }

注意:这里的view只能是已经显示在界面上的,那没显示在界面上的怎么处理?往下看
此方法也是后台生成view的方法:
/** * 计算view的大小 */ public void measureSize(Activity activity, String url) { //将布局转化成view对象 View viewBitmap = LayoutInflater.from(activity).inflate(R.layout.background_layout, null); WindowManager manager = activity.getWindowManager(); DisplayMetrics outMetrics = new DisplayMetrics(); manager.getDefaultDisplay().getMetrics(outMetrics); int width = outMetrics.widthPixels; int height = outMetrics.heightPixels; //然后View和其内部的子View都具有了实际大小,也就是完成了布局,相当与添加到了界面上。接着就可以创建位图并在上面绘制了: layoutView(viewBitmap, width, height, url, activity); }/** * 填充布局内容 */ public void layoutView(final View viewBitmap, int width, int height, String url, Activity activity) { // 整个View的大小 参数是左上角 和右下角的坐标 viewBitmap.layout(0, 0, width, height); int measuredWidth = View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY); int measuredHeight = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.AT_MOST); viewBitmap.measure(measuredWidth, measuredHeight); viewBitmap.layout(0, 0, viewBitmap.getMeasuredWidth(), viewBitmap.getMeasuredHeight()); TextView tv = viewBitmap.findViewById(R.id.tv_background); tv.setText("这是后台生成图片的标题"); final ImageView imageView = viewBitmap.findViewById(R.id.iv_background); //注意加载网络图片时一定要用SimpleTarget回调 Glide.with(activity).load(url).asBitmap().into(new SimpleTarget() { @Override public void onResourceReady(Bitmap resource, GlideAnimation glideAnimation) { imageView.setImageBitmap(resource); viewSaveToImage(viewBitmap); } }); }/** * 把view转成图片 * @param view */ private void viewSaveToImage(View view) { view.setDrawingCacheEnabled(true); view.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH); view.setDrawingCacheBackgroundColor(Color.WHITE); // 把一个View转换成图片 Bitmap cachebmp = viewConversionBitmap(view); if (mBitmapDoneListener != null){ mBitmapDoneListener.bitmapDone(cachebmp); }view.destroyDrawingCache(); }

6. 圆角画中画
/** * view转bitmap */ public Bitmap viewConversionBitmap(View v) { int w = v.getWidth(); int h = v.getHeight(); Bitmap bmp = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); Canvas c = new Canvas(bmp); c.drawColor(Color.WHITE); /** 如果不设置canvas画布为白色,则生成透明 */v.layout(0, 0, w, h); v.draw(c); return bmp; }/** * 把上面获得的bitmap传进来就可以得到圆角的bitmap了 */ public void bitmapInBitmap(Bitmap bitmap, ImageView imageView) { Bitmap tempBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true); Canvas canvas = new Canvas(tempBitmap); //图像上画矩形 Paint paint = new Paint(); paint.setColor(Color.TRANSPARENT); paint.setStyle(Paint.Style.STROKE); //不填充 paint.setStrokeWidth(10); //线的宽度 canvas.drawRect(10, 20, 100, 100, paint); imageView.setImageBitmap(tempBitmap); //画中画 Paint photoPaint = new Paint(); // 建立画笔 photoPaint.setDither(true); // 获取跟清晰的图像采样 photoPaint.setFilterBitmap(true); // 过滤一些Rect src = https://www.it610.com/article/new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()); // 创建一个指定的新矩形的坐标 Rect dst = new Rect(0, 0, 300, 350); // 创建一个指定的新矩形的坐标 canvas.drawBitmap(tempBitmap, src, dst, photoPaint); // 将photo 缩放或则扩大到 imageView.setImageBitmap(getRoundedCornerBitmap(tempBitmap)); }/** *生成圆角图片 */ public Bitmap getRoundedCornerBitmap(Bitmap bitmap) { try { Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(output); final Paint paint = new Paint(); final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()); final RectF rectF = new RectF(new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight())); //设置圆角大小 final float roundPx = 30; paint.setAntiAlias(true); canvas.drawARGB(0, 0, 0, 0); paint.setColor(Color.BLACK); canvas.drawRoundRect(rectF, roundPx, roundPx, paint); paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); final Rect src = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()); canvas.drawBitmap(bitmap, src, rect, paint); return output; } catch (Exception e) { return bitmap; } }

以上就是所有的view转bitmap操作,得到bitmap之后你们就可以为所欲为了- -
再次提醒一下:加载网络图片要使用simpleTarget回调,直接加载得到的是一片空白,切记!!!
目前博主只试过glide一种图片框架,其他框架请自行试验,有需要demo的私聊我
第一次写博客,写的不好的地方望指正。

    推荐阅读