产品今天说项目分享时要分享出一张  封面图片 + 几行文字 + 二维码图片 的图片。

思索了一下 封面图片和二维码图片让后台给接口得到地址, 主要还是找个方式得到一个包含这些内容的图片。于是就想能不能将View转化成bitmap对象

然后就走了一遍各个前辈的路 整理了下原理和思路。

根据产品的需求  我要实现的步骤  把所有需要的集合在一个View里 —— View转化成bitmap —— 分享出去(第三方分享bitmap对象)

接着搞个demo 实验一下

要转化的view 大致长这样

view_photo.xml

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. android:orientation="vertical" >
  6. <ScrollView
  7. android:id="@+id/textView"
  8. android:layout_width="match_parent"
  9. android:layout_height="match_parent" >
  10. <LinearLayout
  11. android:layout_width="match_parent"
  12. android:layout_height="match_parent"
  13. android:orientation="vertical" >
  14. <!--封面图片  -->
  15. <ImageView
  16. android:layout_width="400dp"
  17. android:layout_height="400dp"
  18. android:background="@drawable/ic_launcher"
  19. android:layout_gravity="center_horizontal" />
  20. <TextView
  21. android:layout_width="wrap_content"
  22. android:layout_height="wrap_content"
  23. android:text="文字 文字"
  24. android:layout_gravity="center_horizontal" />
  25. <Button
  26. android:id="@+id/button"
  27. android:layout_width="wrap_content"
  28. android:layout_height="wrap_content"
  29. android:text="假装是二维码图片"
  30. android:layout_gravity="center_horizontal" />
  31. </LinearLayout>
  32. </ScrollView>
  33. </LinearLayout>

最关键的View转bitmap

好像是有两种方法

DrawingCache方法:
如果使用DrawingCache,则对要截图的View有一个要求:View本身已经显示在界面上。如果View没有添加到界面上或者没有显示(绘制)过,则buildDrawingCache会失败。这种方式比较适合对应用界面或者某一部分的截图。步骤很简单:
  1. view.setDrawingCacheEnabled(true);
  2. view.buildDrawingCache();  //启用DrawingCache并创建位图
  3. Bitmap bitmap = Bitmap.createBitmap(view.getDrawingCache()); //创建一个DrawingCache的拷贝,因为DrawingCache得到的位图在禁用后会被回收
  4. view.setDrawingCacheEnabled(false);  //禁用DrawingCahce否则会影响性能
View.draw方法:
这个也很简单 view对象传进去.draw()就行
  1. private Bitmap loadBitmapFromView(View v) {
  2. int w = v.getWidth();
  3. int h = v.getHeight();
  4. Bitmap bmp = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
  5. Canvas c = new Canvas(bmp);
  6. c.drawColor(Color.WHITE);
  7. /** 如果不设置canvas画布为白色,则生成透明 */
  8. v.layout(0, 0, w, h);
  9. v.draw(c);
  10. return bmp;
  11. }
然而此时适用于需要截图的View并没有添加到界面上,
可能是通过java代码创建的或者inflate创建的,(我需求的情况就适用于这种。分享的时候生成bitmap对象但不显示在界面中)
此时调用DrawingCache方法是获取不到位图的。
因为View在添加到容器中之前并没有得到实际的大小(如果LayoutWidth是MatchParent,它还没有Parent…)
,所以首先需要指定View的大小:
先得到
  1. DisplayMetrics metric = new DisplayMetrics();
  2. getWindowManager().getDefaultDisplay().getMetrics(metric);
  3. int width = metric.widthPixels;     // 屏幕宽度(像素)
  4. int height = metric.heightPixels;   // 屏幕高度(像素)
  5. View view = LayoutInflater.from(this).inflate(R.layout.view_photo, null, false);
  6. layoutView(view, width, height);//去到指定view大小的函数
  1. //然后View和其内部的子View都具有了实际大小,也就是完成了布局,相当与添加到了界面上。接着就可以创建位图并在上面绘制了:
  2. private void layoutView(View v, int width, int height) {
  3. // 指定整个View的大小 参数是左上角 和右下角的坐标
  4. v.layout(0, 0, width, height);
  5. int measuredWidth = View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY);
  6. int measuredHeight = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.AT_MOST);
  7. /** 当然,measure完后,并不会实际改变View的尺寸,需要调用View.layout方法去进行布局。
  8. * 按示例调用layout函数后,View的大小将会变成你想要设置成的大小。
  9. */
  10. v.measure(measuredWidth, measuredHeight);
  11. v.layout(0, 0, v.getMeasuredWidth(), v.getMeasuredHeight());
  12. }

在int measuredHeight = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.AT_MOST);

这里我有点不懂后面函数的取值。在自定义view里onMeasure()里有根据MeasureSpec.getMode()的类型来准确得到设置view的长宽
.makeMeasureSpec(height, View.MeasureSpec.AT_MOST);却貌似取了 自适应和前一个int参数的最小值。
后面我发现有可能合成出超出屏幕的长图,就直接吧前一个int参数赋值成一个很大的数字。。。
 
 
上整个demo的代码
activity_main.xml
  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. xmlns:tools="http://schemas.android.com/tools"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. tools:context="com.example.aa.MainActivity" >
  6. <Button
  7. android:id="@+id/button"
  8. android:layout_width="wrap_content"
  9. android:layout_height="wrap_content"
  10. android:text=" button" />
  11. <ImageView
  12. android:id="@+id/aaa"
  13. android:layout_below="@+id/button"
  14. android:layout_width="wrap_content"
  15. android:layout_height="wrap_content"
  16. />
  17. </RelativeLayout>

view_photo.xml 在上面

MainActivity
  1. public class MainActivity extends Activity {
  2. ImageView aaa ;
  3. @Override
  4. protected void onCreate(Bundle savedInstanceState) {
  5. super.onCreate(savedInstanceState);
  6. setContentView(R.layout.activity_main);
  7. DisplayMetrics metric = new DisplayMetrics();
  8. getWindowManager().getDefaultDisplay().getMetrics(metric);
  9. int width = metric.widthPixels;     // 屏幕宽度(像素)
  10. int height = metric.heightPixels;   // 屏幕高度(像素)
  11. View view = LayoutInflater.from(this).inflate(R.layout.view_photo, null, false);
  12. layoutView(view, width, height);
  13. final ScrollView tv = (ScrollView) view.findViewById(R.id.textView);
  14. aaa = (ImageView) findViewById(R.id.aaa);
  15. final Runnable runnable = new Runnable() {
  16. @Override
  17. public void run() {
  18. viewSaveToImage(tv);
  19. }
  20. };
  21. Button button = (Button) findViewById(R.id.button);
  22. button.setOnClickListener(new View.OnClickListener() {
  23. @Override
  24. public void onClick(View v) {
  25. new Handler().post(runnable);
  26. }
  27. });
  28. }
  29. //然后View和其内部的子View都具有了实际大小,也就是完成了布局,相当与添加到了界面上。接着就可以创建位图并在上面绘制了:
  30. private void layoutView(View v, int width, int height) {
  31. // 整个View的大小 参数是左上角 和右下角的坐标
  32. v.layout(0, 0, width, height);
  33. int measuredWidth = View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY);
  34. int measuredHeight = View.MeasureSpec.makeMeasureSpec(10000, View.MeasureSpec.AT_MOST);
  35. /** 当然,measure完后,并不会实际改变View的尺寸,需要调用View.layout方法去进行布局。
  36. * 按示例调用layout函数后,View的大小将会变成你想要设置成的大小。
  37. */
  38. v.measure(measuredWidth, measuredHeight);
  39. v.layout(0, 0, v.getMeasuredWidth(), v.getMeasuredHeight());
  40. }
  41. public void viewSaveToImage(View view) {
  42. Log.e("ssh","a");
  43. /**
  44. * View组件显示的内容可以通过cache机制保存为bitmap
  45. * 我们要获取它的cache先要通过setDrawingCacheEnable方法把cache开启,
  46. * 然后再调用getDrawingCache方法就可 以获得view的cache图片了
  47. * 。buildDrawingCache方法可以不用调用,因为调用getDrawingCache方法时,
  48. * 若果 cache没有建立,系统会自动调用buildDrawingCache方法生成cache。
  49. * 若果要更新cache, 必须要调用destoryDrawingCache方法把旧的cache销毁,才能建立新的。
  50. */
  51. //        view.setDrawingCacheEnabled(true);
  52. //        view.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
  53. //设置绘制缓存背景颜色
  54. //        view.setDrawingCacheBackgroundColor(Color.WHITE);
  55. // 把一个View转换成图片
  56. Bitmap cachebmp = loadBitmapFromView(view);
  57. aaa.setImageBitmap(cachebmp);//直接展示转化的bitmap
  58. //保存在本地 产品还没决定要不要保存在本地
  59. FileOutputStream fos;
  60. try {
  61. // 判断手机设备是否有SD卡
  62. boolean isHasSDCard = Environment.getExternalStorageState().equals(
  63. android.os.Environment.MEDIA_MOUNTED);
  64. if (isHasSDCard) {
  65. // SD卡根目录
  66. File sdRoot = Environment.getExternalStorageDirectory();
  67. Log.e("ssh",sdRoot.toString());
  68. File file = new File(sdRoot, "test.png");
  69. fos = new FileOutputStream(file);
  70. } else
  71. throw new Exception("创建文件失败!");
  72. //压缩图片 30 是压缩率,表示压缩70%; 如果不压缩是100,表示压缩率为0
  73. cachebmp.compress(Bitmap.CompressFormat.PNG, 90, fos);
  74. fos.flush();
  75. fos.close();
  76. } catch (Exception e) {
  77. e.printStackTrace();
  78. }
  79. view.destroyDrawingCache();
  80. }
  81. private Bitmap loadBitmapFromView(View v) {
  82. int w = v.getWidth();
  83. int h = v.getHeight();
  84. Bitmap bmp = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
  85. Canvas c = new Canvas(bmp);
  86. c.drawColor(Color.WHITE);
  87. /** 如果不设置canvas画布为白色,则生成透明 */
  88. v.layout(0, 0, w, h);
  89. v.draw(c);
  90. return bmp;
  91. }
  92. }

demo转化成结果的bitmap和图片

关于View转化成bitmap保存成图片的更多相关文章

  1. BitmapUtil【缩放bitmap以及将bitmap保存成图片到SD卡中】

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 用于缩放bitmap以及将bitmap保存成图片到SD卡中 效果图 代码分析 bitmapZoomByHeight(Bitmap s ...

  2. 如何把Excel中的单元格等对象保存成图片

    对于Excel中的很多对象,比如单元格(Cell),图形(shape),图表(chart)等等,有时需要将它们保存成一张图片.就像截图一样. 最近做一个Excel相关的项目,项目中遇到一个很变态的需求 ...

  3. OpenGL中的深度、深度缓存、深度测试及保存成图片

    1.深度 所谓深度,就是在openGL坐标系中,像素点Z坐标距离摄像机的距离.摄像机可能放在坐标系的任何位置,那么,就不能简单的说Z数值越大或越小,就是越靠近摄像机. 2.深度缓冲区 深度缓冲区原理就 ...

  4. javacpp-opencv图像处理之1:实时视频添加文字水印并截取视频图像保存成图片,实现文字水印的字体、位置、大小、粗度、翻转、平滑等操作

    欢迎大家积极开心的加入讨论群 群号:371249677 (点击这里进群) javaCV图像处理系列: javaCV图像处理之1:实时视频添加文字水印并截取视频图像保存成图片,实现文字水印的字体.位置. ...

  5. 修改css的(屏蔽)overflow: hidden;实现浏览器能把网页全图保存成图片

    摘要: 1.项目需要,需要对网页内容“下载”保存成全图片 2.QQ浏览器等主流浏览器都支持这种下载保存功能 3.项目需要场景:编写好的项目维护文档,放在服务器上.如果是txt不能带图片可视化,如果wo ...

  6. Java 将 PPT 形状(表格、文本框、心形、图表等)保存成图片

    MS PowerPoint中的表格.文本框.心形.图表.图片等均可以称为形状,将这些形状保存成图片,便可分类储存,方便日后查找,再利用. 本文将介绍如何使用 Spire.Presentation fo ...

  7. 如何实现批量截取整个网页完整长截图,批量将网页保存成图片web2pic/webshot/screencapture/html2picture

    如何实现批量截取整个网页完整长截图,批量将网页保存成图片web2pic/webshot/screencapture [困扰?疑问?]: 您是否正受到:如何将网页保存为图片的困扰?网页很高很长截图截不全 ...

  8. c# 将byte数组保存成图片

    将byte数组保存成图片: 方式一:System.IO.File.WriteAllBytes(@"c:\test.jpg", bytes); 方式二:MemoryStream ms ...

  9. MVC下 把数据库中的byte[]值保存成图片,并显示在view页面

    MVC下 把数据库中的byte[]值转成图片,并显示在view页面 controller中的action方法 //显示图片[AllowAnonymous]public ActionResult Sho ...

随机推荐

  1. Redis命令行之String

    一.Redis之String简介 1. String是redis最基本的数据类型,一个key对应一个value. 2. String是二进制安全的,可以包含任何数据,例如图片或序列化的对象. 3. S ...

  2. BZOJ 1090 字符串折叠(Hash + DP)

    题目链接 字符串折叠 区间DP.$f[l][r]$为字符串在区间l到r的最小值 正常情况下 $f[l][r] = min(f[l][r], f[l][l+k-1]+f[l+k][r]);$ 当$l$到 ...

  3. Spring Boot 2 快速教程:WebFlux 集成 Mongodb(四)

    摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘要,谢谢! 这是泥瓦匠的第104篇原创 文章工程:* JDK 1.8* M ...

  4. noip 2013 luogu P1969 积木大赛

    题目描述 春春幼儿园举办了一年一度的“积木大赛”.今年比赛的内容是搭建一座宽度为n的大厦,大厦可以看成由n块宽度为1的积木组成,第i块积木的最终高度需要是hi. 在搭建开始之前,没有任何积木(可以看成 ...

  5. uml精粹——10.状态机图

    10.状态机图state machine diagram   状态机图是常见的描写叙述一个系统行为的技术. 在面向对象的方法中,为单个类绘制一个状态机图来展示单个对象的生命周期行为. 见图10.1 图 ...

  6. (转) SYSTEM_HANDLE_INFORMATION中ObjectTypeIndex的定义

    typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO{ USHORT UniqueProcessId; USHORT CreatorBackTraceIndex ...

  7. electron 开发拆坑总结

    electron 总结 前言 有一个web项目需要用客户端来包装一下 项目的主要业务都在服务器上 所以项目的大多数功能都用url 地址来访问: 客户端登陆界面在本地 打包客户端的本地登陆界面 做为登陆 ...

  8. Java类载入器(二)——自己定义类载入器

      用户定制自己的ClassLoader能够实现以下的一些应用: 自己定义路径下查找自己定义的class类文件,或许我们须要的class文件并不总是在已经设置好的Classpath以下,那么我们必须想 ...

  9. JDBC MYSQL 学习笔记(一) JDBC 基本使用

    1.JDBC简单介绍 SUN公司为了简化.统一对数据库的操作,定义了一套Java操作数据库的规范.称之为JDBC. JDBC全称为:Java Data Base Connectivity(java数据 ...

  10. react 创建组件 (三)PureComponet

    我们知道,当组件的props或者state发生变化的时候:React会对组件当前的Props和State分别与nextProps和nextState进行比较,当发现变化时,就会对当前组件以及子组件进行 ...