当前位置: 首页 > news >正文

重庆市网站编辑网站seo外链建设

重庆市网站编辑,网站seo外链建设,给公司做网站风险,做单平台网站制作最近一段时间,在做一个需求,需要实现一个聊天气泡的动画效果,如下图所示: GitHub源码demo ,建议下载demo,运行查看。 动态聊天气泡动画 静态聊天气泡 经过一段时间调研,实现方案如下: 实现方…

最近一段时间,在做一个需求,需要实现一个聊天气泡的动画效果,如下图所示:

GitHub源码demo ,建议下载demo,运行查看。

动态聊天气泡动画

在这里插入图片描述

静态聊天气泡

在这里插入图片描述

经过一段时间调研,实现方案如下:

实现方案

  • 从服务端下载zip文件,文件中包含配置文件和多张png图片,配置文件定义了图片的横向拉伸拉伸区域、纵向拉伸区域、padding信息等。
  • 从本地加载配置文件,加载多张png图片为bitmap。
  • 将bitmap存储在内存里。LruCache,避免多次解析。
  • 根据配置文件,将png图片转换为.9图,NinePatchDrawable。
  • 使用多张NinePatchDrawable创建一个帧动画对象AnimationDrawable
  • 将AnimationDrawable设置为控件的背景,并让AnimationDrawable播放动画,执行一定的次数后停止动画。

其中的难点在于第3步,将png图片转换为.9图 NinePatchDrawable

NinePatchDrawable 的构造函数。

/*** Create drawable from raw nine-patch data, setting initial target density* based on the display metrics of the resources.*/
public NinePatchDrawable(Resources res,Bitmap bitmap,byte[]chunk,Rect padding,String srcName){this(new NinePatchState(new NinePatch(bitmap,chunk,srcName),padding),res);
}

其中最关键的点在于构建byte[] chunk参数。通过查看这个类NinePatchChunk.java,并参阅了许多博客,通过反向分析NinePatchChunk类的deserialize方法,得到了如何构建byte[] chunk的方法。

// See "frameworks/base/include/utils/ResourceTypes.h" for the format of
// NinePatch chunk.
class NinePatchChunk {public static final int NO_COLOR = 0x00000001;public static final int TRANSPARENT_COLOR = 0x00000000;public Rect mPaddings = new Rect();public int mDivX[];public int mDivY[];public int mColor[];private static void readIntArray(int[] data, ByteBuffer buffer) {for (int i = 0, n = data.length; i < n; ++i) {data[i] = buffer.getInt();}}private static void checkDivCount(int length) {if (length == 0 || (length & 0x01) != 0) {throw new RuntimeException("invalid nine-patch: " + length);}}//注释1处,解析byte[]数据,构建NinePatchChunk对象public static NinePatchChunk deserialize(byte[] data) {ByteBuffer byteBuffer =ByteBuffer.wrap(data).order(ByteOrder.nativeOrder());byte wasSerialized = byteBuffer.get();if (wasSerialized == 0)//第一个字节不能为0return null;NinePatchChunk chunk = new NinePatchChunk();chunk.mDivX = new int[byteBuffer.get()];//第二个字节为x方向上的切割线的个数chunk.mDivY = new int[byteBuffer.get()];//第三个字节为y方向上的切割线的个数chunk.mColor = new int[byteBuffer.get()];//第四个字节为颜色的个数checkDivCount(chunk.mDivX.length);//判断x方向上的切割线的个数是否为偶数checkDivCount(chunk.mDivY.length);//判断y方向上的切割线的个数是否为偶数// skip 8 bytes,跳过8个字节byteBuffer.getInt();byteBuffer.getInt();//注释2处,处理padding,发现都设置为0也可以。chunk.mPaddings.left = byteBuffer.getInt();//左边的paddingchunk.mPaddings.right = byteBuffer.getInt();//右边的paddingchunk.mPaddings.top = byteBuffer.getInt();//上边的paddingchunk.mPaddings.bottom = byteBuffer.getInt();//下边的padding// skip 4 bytesbyteBuffer.getInt();//跳过4个字节readIntArray(chunk.mDivX, byteBuffer);//读取x方向上的切割线的位置readIntArray(chunk.mDivY, byteBuffer);//读取y方向上的切割线的位置readIntArray(chunk.mColor, byteBuffer);//读取颜色return chunk;}
}

注释1处,解析byte[]数据,构建NinePatchChunk对象。我们添加了一些注释,意思已经很清晰了。

然后我们根据这里类来构建byte[] chunk参数。

private fun buildChunk(): ByteArray {// 横向和竖向端点的数量 = 线段数量 * 2,这里只有一个线段,所以都是2val horizontalEndpointsSize = 2val verticalEndpointsSize = 2//这里计算的 arraySize 是 int 值,最终占用的字节数是 arraySize * 4val arraySize = 1 + 2 + 4 + 1 + horizontalEndpointsSize + verticalEndpointsSize + COLOR_SIZE//这里乘以4,是因为一个int占用4个字节val byteBuffer = ByteBuffer.allocate(arraySize * 4).order(ByteOrder.nativeOrder())byteBuffer.put(1.toByte()) //第一个字节无意义,不等于0就行byteBuffer.put(horizontalEndpointsSize.toByte()) //mDivX x数组的长度byteBuffer.put(verticalEndpointsSize.toByte()) //mDivY y数组的长度byteBuffer.put(COLOR_SIZE.toByte()) //mColor数组的长度// skip 8 bytesbyteBuffer.putInt(0)byteBuffer.putInt(0)//Note: 目前还没搞清楚,发现都 byteBuffer.putInt(0),也没问题。//左右paddingbyteBuffer.putInt(mRectPadding.left)byteBuffer.putInt(mRectPadding.right)//上下paddingbyteBuffer.putInt(mRectPadding.top)byteBuffer.putInt(mRectPadding.bottom)//byteBuffer.putInt(0)//byteBuffer.putInt(0)//上下padding//byteBuffer.putInt(0)//byteBuffer.putInt(0)//skip 4 bytesbyteBuffer.putInt(0)//mDivX数组,控制横向拉伸的线段数据,目前只支持一个线段patchRegionHorizontal.forEach {byteBuffer.putInt(it.start * width / originWidth)byteBuffer.putInt(it.end * width / originWidth)}//mDivY数组,控制竖向拉伸的线段数据,目前只支持一个线段patchRegionVertical.forEach {byteBuffer.putInt(it.start * height / originHeight)byteBuffer.putInt(it.end * height / originHeight)}//mColor数组for (i in 0 until COLOR_SIZE) {byteBuffer.putInt(NO_COLOR)}return byteBuffer.array()
}

完整的类请参考 AnimationDrawableFactory.kt

使用

完整的使用请查看 ChatAdapter 类。

AnimationDrawableFactory 支持从文件构建动画,也支持从Android的资源文件夹构建动画。

!!!注意,从文件构建动画,需要将请把工程下的bubbleframe文件夹拷贝到手机的Android/data/包名/files
目录下val fileDir = getExternalFilesDir(null),否则会报错。

从文件构建动画

 return AnimationDrawableFactory(context).setDrawableDir(pngsDir)//图片文件所在的目录.setHorizontalStretchBean(PatchStretchBean(60, 61))//水平拉伸区域.setVerticalStretchBean(PatchStretchBean(52, 53))//垂直拉伸区域.setOriginSize(128, 112)//原始图片大小.setPadding(Rect(31, 37, 90, 75))//padding区域.setHorizontalMirror(isSelf)//是否水平镜像,不是必须的.setScaleFromFile(true)//是否从文件中读取图片的缩放比例,不是必须的.setFinishCount(3)//动画播放次数.setFrameDuration(100)//每帧动画的播放时间.buildFromFile()

这里注意一下:因为文件中的图片是一倍图,所以这里需要放大,所以设置了setScaleFromFile(true)
如果文件中的图片是3倍图,就不需要设置这个参数了。如果需要更加精细的缩放控制,后面再增加支持。

从Android的资源文件夹构建动画


private val resIdList = mutableListOf<Int>().apply {add(R.drawable.bubble_frame1)add(R.drawable.bubble_frame2)add(R.drawable.bubble_frame3)add(R.drawable.bubble_frame4)add(R.drawable.bubble_frame5)add(R.drawable.bubble_frame6)add(R.drawable.bubble_frame7)add(R.drawable.bubble_frame8)add(R.drawable.bubble_frame9)add(R.drawable.bubble_frame10)add(R.drawable.bubble_frame11)add(R.drawable.bubble_frame12)
}/*** 从正常的资源文件加载动态气泡*/
return AnimationDrawableFactory(context).setDrawableResIdList(resIdList)//图片资源id列表.setHorizontalStretchBean(PatchStretchBean(60, 61))//水平拉伸区域.setVerticalStretchBean(PatchStretchBean(52, 53))//垂直拉伸区域.setOriginSize(128, 112)//原始图片大小.setPadding(Rect(31, 37, 90, 75))//padding区域.setHorizontalMirror(isSelf)//是否水平镜像,不是必须的.setFinishCount(3)//动画播放次数,不是必须的.setFrameDuration(100)//每帧动画的播放时间,不是必须的.buildFromResource()

有时候可能我们只需要构建静态气泡,也就是只需要一张 NinepatchDrawable,我们提供了一个类来构建静态气泡,NinePatchDrawableFactory.kt

从文件加载

return NinePatchDrawableFactory(context).setDrawableFile(pngFile)//图片文件.setHorizontalStretchBean(PatchStretchBean(60, 61))//水平拉伸区域.setVerticalStretchBean(PatchStretchBean(52, 53))//垂直拉伸区域.setOriginSize(128, 112)//原始图片大小.setScaleFromFile(true)//是否从文件中读取图片的缩放比例,不是必须的.setPadding(Rect(31, 37, 90, 75))//padding区域.setHorizontalMirror(isSelf)//是否水平镜像,不是必须的.buildFromFile()

从资源加载

return NinePatchDrawableFactory(context).setDrawableResId(R.drawable.bubble_frame1)//图片资源id.setHorizontalStretchBean(PatchStretchBean(60, 61))//水平拉伸区域.setVerticalStretchBean(PatchStretchBean(52, 53))//垂直拉伸区域.setOriginSize(128, 112)//原始图片大小.setPadding(Rect(31, 37, 90, 75))//padding区域.setHorizontalMirror(isSelf)//是否水平镜像,不是必须的.buildFromResource()

padding 取值

如图所示:宽高是128*112。横向padding取值为31、90,纵向padding取值为37、75。

在这里插入图片描述

其他

在实现过程中发现Android 的 帧动画 AnimationDrawable无法控制动画执行的次数。最后自定义了一个类,CanStopAnimationDrawable.kt 解决。

参考链接:

  • Carson带你学Android:关于逐帧动画的使用都在这里了!-腾讯云开发者社区-腾讯云
  • 聊天气泡图片的动态拉伸、镜像与适配 - 掘金
  • Android 点九图机制讲解及在聊天气泡中的应用 - 掘金
  • Android动态布局入门及NinePatchChunk解密
  • Android点九图总结以及在聊天气泡中的使用-腾讯云开发者社区-腾讯云
  • https://developer.android.com/studio/write/draw9patch?utm_source=android-studio&hl=zh-cn
http://www.yidumall.com/news/88334.html

相关文章:

  • 加快政务网站群建设管理百度高级搜索页面
  • 浙江网站建设哪里有线上营销推广方式
  • wordpress 下载弹窗家居seo整站优化方案
  • 网站的线下推广怎么做推广软文范文
  • 网站中的文字滑动怎么做app推广接单网
  • 中小网站推广 一级域名还是二级域名免费外链平台
  • 东莞虎门做网站百度首页官网
  • 学校网站建设多少钱湖南seo公司
  • 高埗镇网站建设营销软文案例
  • 做标书经验分享网站深圳博惠seo
  • 网站 配色表搜索引擎有哪些类型
  • 夫唯seo系统培训广州灰色优化网络公司
  • 长沙专业网络推广公司郑州seo技术服务
  • 页面设计介绍优化百度seo技术搜索引擎
  • 动态网站开发难吗推广哪些app最挣钱
  • 光谷做网站推广价格seo上海公司
  • 美德的网站建设广州seo和网络推广
  • 网站建设团购免费网站模板网
  • 做奶茶吧店网站推广论坛有哪些
  • 网站手机模板源码代运营公司哪家好一些
  • 广西做网站建设的公司公司免费推广网站
  • 1核1g可以做几个网站seo站群优化技术
  • 企业网站管理系统asp淘宝指数查询工具
  • 建站怎么建郑州seo顾问热狗hotdoger
  • 工程公司有哪些轻松seo优化排名 快排
  • 网站页面统计代码头条今日头条新闻头条
  • app免费制作网站模板宁波seo外包优化
  • 上海网站建设哪家专业广州疫情最新情况
  • 网站2级目录怎么做的宁波关键词优化平台
  • c net 做网站好吗服务营销案例100例