有用过微信分享SDK的都应该知道,微信分享到朋友圈的时候是不能同时分享图片和文字的,只要有缩略图,那么文字就不会生效。那么问题就来了,如果我们想把APP内的某些内容连带图片一起分享到微信,是不是没办法了呢?

再想想我们常用的网易云音乐,允许我们把歌词连带着歌曲的图片拼在一起变成一张图,我们再把这张图片分享出去就好了。

那么,本篇的内容就是动手做一个带文字的图片。

这里也记录下上下文,因为做了一个失物招领的App,当有人上交了失物之后,可以将这个消息分享出去,这个消息内容有物品的信息和图片,而微信SDK始终无法做到,就想着把物品信息嵌入到图片中分享出去,先放一个效果图:

这个分享出去的图片很简单,上面是图片,下面是文字组合在一起。

先要知道,方案的原理是通过操作一个以Bitmap为基础的Canvas来做到的,思路很简单:

① 让画布作用在Bitmap上

② 在画布的上方绘制拍摄所得的图片

③ 在②所绘制的图片下面绘制文字

第一步很简单,我们只需要构造一个Bitmap并且装载到Canvas中就可以了,假设拍摄得到的图片名为bitmap,则代码如下:

Bitmap.Config config = bitmap.getConfig();
Bitmap shareBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), config);
Canvas canvas = new Canvas(shareBitmap);

到这里我们就要思考了,这个图片的宽高应该怎么设置比较合理呢?上面的代码设置为跟拍摄所得图片一样,也就是说,如果再需要添加文字,文字只能显示在图片上。这个时候,如果图片的颜色比较丰富,那么文字叠在上面就会很难看得清楚了。按照我上面图片的做法,是在拍摄图片的下面增加一些空间来绘制文字,这里要设置的高度应该要更加大一点。而究竟要多大我们等下再讨论。

第二步是在画布中绘制拍摄所得的图片,这里就很简单了,直接有这样的代码:

canvas.drawBitmap(bitmap, , , paint);

接着是第三步,也是最难的地方。这里不能直接在canvas中直接调用drawText方法来绘制文字!为什么?因为我们的文字内容有可能比图片的宽度要大,当文字比图片更宽的时候,使用drawText是无法让文字内容换行的,这样文字就被截断了。

解决的方案是使用TextPaint这个Paint的子类。这个类还需要配合StaticLayout来绘制文字,我们看看它的用法:

Paint paint = new Paint();
paint.setColor(Color.BLACK); // 画笔颜色
TextPaint textpaint = new TextPaint(paint);
textpaint.setTextSize(textSize); // 文字大小
textpaint.setAntiAlias(true); // 抗锯齿
StaticLayout title_layout = new StaticLayout(title.getText().toString(), textpaint, sourceBitmapWidth, Layout.Alignment.ALIGN_CENTER, 1f, 1f, true);

直接通过我们的Paint对象来创建一个TextPaint,接着设置抗锯齿和文字大小。接着创建一个StaticLayout对象,构造方法需要传入的参数分别是:文字内容、TextPaint对象、文本宽度、对齐方式、行距倍数、行距加数和是否包含内边距。这里比较重要的地方是设置文本宽度,当文本宽度比这个值大的时候就会自动换行。

当我们构造好了这个StaticLayout之后,就可以对画布进行定位,然后将文字绘制出来:

canvas.translate(, sourceBitmapHeight); // 移动位置到图片的下面
title_layout.draw(canvas); // 在画布中绘制文字

完成了这几步之后,Canvas中的Bitmap就会有图片和文字了。

但是我们的问题其实还没有解决。

① 这个分享出去的Bitmap的高度究竟是多少呢?上面我们跳过了这个问题,其实已经有答案了,我们可以让它的高度为图片的内容加上我们创建的StaticLayout的高度就可以了。这样图片的高度会跟随文字内容的多少变化。获取StaticLayout的高度比较简单:

title_layout.getHeight()

②  这个时候,如果我们直接在App中显示这个图片,是没有什么问题的,但是如果我们把图片分享到微信,你会发现,图片的文字部分完全变成了黑色,连文字都看不到了。这里的解决办法也很简单,在绘制的时候,先给整个图片绘制一个白色的背景:

canvas.drawColor(Color.WHITE);

这里就基本完成了,代码也给出来大家参考下吧:

// 拍摄所得的图片为imageBitmap
private Bitmap getShareingBitmap(int textSize) {
Bitmap.Config config = imageBitmap.getConfig();
int sourceBitmapHeight = imageBitmap.getHeight();
int sourceBitmapWidth = imageBitmap.getWidth();
Paint paint = new Paint();
paint.setColor(Color.BLACK); // 画笔颜色
TextPaint textpaint = new TextPaint(paint);
textpaint.setTextSize(textSize); // 文字大小
textpaint.setAntiAlias(true); // 抗锯齿
StaticLayout title_layout = new StaticLayout(title.getText().toString(), textpaint,
sourceBitmapWidth, Layout.Alignment.ALIGN_CENTER, 1f, 1f, true);
StaticLayout desc_layout = new StaticLayout("物品描述:"+description.getText().toString(), textpaint,
sourceBitmapWidth, Layout.Alignment.ALIGN_NORMAL, 1f, 1f, true);
StaticLayout phone_layout = new StaticLayout("联系电话:"+phone.getText().toString(), textpaint,
sourceBitmapWidth, Layout.Alignment.ALIGN_NORMAL, 1f, 1f, true);
Bitmap share_bitmap = Bitmap.createBitmap(sourceBitmapWidth, sourceBitmapHeight +
title_layout.getHeight() + desc_layout.getHeight() + phone_layout.getHeight(),
config);
Canvas canvas = new Canvas(share_bitmap);
canvas.drawColor(Color.WHITE);
canvas.drawBitmap(imageBitmap, , , paint); // 绘制图片
canvas.translate(, sourceBitmapHeight);
title_layout.draw(canvas); canvas.translate(, title_layout.getHeight());
phone_layout.draw(canvas); canvas.translate(, phone_layout.getHeight());
desc_layout.draw(canvas);
return share_bitmap;
}

先计算所有文字内容的高度,然后构建图片的大小,绘制白色背景,绘制拍摄图片,在拍摄图片下绘制文字。

Android开发学习之路-带文字的图片分享的更多相关文章

  1. Android开发学习之路--Android系统架构初探

    环境搭建好了,最简单的app也运行过了,那么app到底是怎么运行在手机上的,手机又到底怎么能运行这些应用,一堆的电子元器件最后可以运行这么美妙的界面,在此还是需要好好研究研究.这里从芯片及硬件模块-& ...

  2. Android开发学习之路-RecyclerView滑动删除和拖动排序

    Android开发学习之路-RecyclerView使用初探 Android开发学习之路-RecyclerView的Item自定义动画及DefaultItemAnimator源码分析 Android开 ...

  3. Android开发学习之路--基于vitamio的视频播放器(二)

      终于把该忙的事情都忙得差不多了,接下来又可以开始good good study,day day up了.在Android开发学习之路–基于vitamio的视频播放器(一)中,主要讲了播放器的界面的 ...

  4. Android开发学习之路--Android Studio cmake编译ffmpeg

      最新的android studio2.2引入了cmake可以很好地实现ndk的编写.这里使用最新的方式,对于以前的android下的ndk编译什么的可以参考之前的文章:Android开发学习之路– ...

  5. Android开发学习之路--网络编程之xml、json

    一般网络数据通过http来get,post,那么其中的数据不可能杂乱无章,比如我要post一段数据,肯定是要有一定的格式,协议的.常用的就是xml和json了.在此先要搭建个简单的服务器吧,首先呢下载 ...

  6. Android开发学习之路--Activity之初体验

    环境也搭建好了,android系统也基本了解了,那么接下来就可以开始学习android开发了,相信这么学下去肯定可以把android开发学习好的,再加上时而再温故下linux下的知识,看看androi ...

  7. Android开发学习之路--MAC下Android Studio开发环境搭建

    自从毕业开始到现在还没有系统地学习android应用的开发,之前一直都是做些底层的驱动,以及linux上的c开发.虽然写过几个简单的app,也对android4.0.3的源代码做过部分的分析,也算入门 ...

  8. Android开发学习之路--UI之简单聊天界面

    学了很多的ui的知识,这里就来实现个聊天的界面,首先来实现个layout的xml,代码如下: <?xml version="1.0" encoding="utf-8 ...

  9. Android开发学习之路-记一次CSDN公开课

    今天的CSDN公开课Android事件处理重难点快速掌握中老师讲到一个概念我觉得不正确. 原话是这样的:点击事件可以通过事件监听和回调两种方法实现. 我一听到之后我的表情是这样的: 这跟我学的看的都不 ...

随机推荐

  1. WebApi防重复提交方案

    使用Redis锁机制. 偽代碼: void post { var key = GetKey(); var value = Redis.Incre(key); if(value == 1) { var ...

  2. c#比较两个List相等

    1.if(ListA.Count == ListB.Count && ListA.Count(t => !ListB.Contains(c)) == 0) 数量相等,元素值相等即 ...

  3. [BZOJ1106][POI2007] Tet 立方体大作战

    Description 一个叫做立方体大作战的游戏风靡整个Byteotia.这个游戏的规则是相当复杂的,所以我们只介绍他的简单规则:给定玩家一个有2n个元素的栈,元素一个叠一个地放置.这些元素拥有n个 ...

  4. jmobile学习之路 ---- 视口

    当我们的浏览器在窗口最大化的时候,此时屏幕的宽度,就是我们桌面的分辨率.这个规则仅仅适用于PC! 我们试图在iPhone中输出屏幕宽度,你会发现屏幕宽度是980!居然和PC屏幕差不多大! 苹果主导的这 ...

  5. winfrom自定义滚动条

    panel或图片什么的跟着鼠标走,这里panel自己可以加背景图或直接搞个图就行了.为了演示清楚,有个滚动条控件做对比,与自定义的同步. using System; using System.Coll ...

  6. sql server2008 代码折叠

    方法一: 用‘GO’来分开使代码折叠 可以看出go后面的自动有折叠 ,如果只有一行代码,则不会显示 方法二: 用’begin end‘来分开使代码折叠 使用begin end 可以使代码折叠 方法三: ...

  7. Mac系统中配置Tomcat环境

    第一步:下载Tomcat 下载地址:http://tomcat.apache.org/download-80.cgi 直接下载如图选中的即可 第二步: 下载完成后,解压,随意放入目录.如我就把它放在/ ...

  8. Spotlight监控Oracle数据库的链接创建

    最近在做性能测试时,由于要挂载空间数据,开发人员直接将所有业务表都挂到了Oracle数据库中.最近做了几次测试发现响应时间和吞吐量都不是很理想,进行一番分析后怀疑可能在Oracle中出现问题,因此再网 ...

  9. git上传文件出错的时候

    $ git pull --rebase origin master 运行这个基本OK!

  10. 浅析PHP中for与foreach两个循环结构遍历数组的区别

    遍历一个数组是编程中最常见不过的了,这里跟大家讨论下for和foreach两种方法.用这两种方法执行遍历的场景太多太多了,这里我们只针对以下两个数组作为例子来讨论.所谓管中窥豹,多少能理清一点两者的区 ...