span从入门到精通4 ImageSpan从熟悉到自定义

2024-05-29 00:32

本文主要是介绍span从入门到精通4 ImageSpan从熟悉到自定义,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前面我们写到GifDrawable我们知道giftdrawable通过一系列的处理可以将gif图转换到giftdrawable中去在这里如果我们要设置ImageView的src或者要设置控件的背景,到这里也就结束了我们只需要用好giftdrawable这个类就行了,但是如果我们想要给textview或者edittext添加文本内容我们需要借助一个工具,这个工具就是ImageSpan。

下面我们看ImageSpan是如何使用的代码如下:

Drawable d = getResources().getDrawable(R.drawable.about_info);
//d.setBounds(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
ImageSpan spa2n=new ImageSpan(d);
ImageSpan span=new ImageSpan(this,R.drawable.about_info);

这东西看上去是挺简单的我们通过getResouces获取资源文件中的drawable并将drawable赋值给imageSpan这样的话我们的span应该和下面的new ImageSpan(this,R.drawable.about_info)显示出来效果是一样的,大家如果测试这两个ImageSpan的话会发现奇怪的事情,第一个span没显示出来,第二个span显示没有问题,这是为什么呢,我们来看下ImageSpan的源码。

 public Drawable getDrawable() {Drawable drawable = null;if (mDrawable != null) {drawable = mDrawable;} else  if (mContentUri != null) {Bitmap bitmap = null;try {InputStream is = mContext.getContentResolver().openInputStream(mContentUri);bitmap = BitmapFactory.decodeStream(is);drawable = new BitmapDrawable(mContext.getResources(), bitmap);drawable.setBounds(0, 0, drawable.getIntrinsicWidth(),drawable.getIntrinsicHeight());is.close();} catch (Exception e) {Log.e("sms", "Failed to loaded content " + mContentUri, e);}} else {try {drawable = mContext.getDrawable(mResourceId);drawable.setBounds(0, 0, drawable.getIntrinsicWidth(),drawable.getIntrinsicHeight());} catch (Exception e) {Log.e("sms", "Unable to find resource: " + mResourceId);}                }return drawable;}

这里有我们需要的答案,我们看到在getDrawable的过程,当drawable不为空的时候直接不处理return,当mContentUri 不为空即从assert文件中取出文件的时候通过流获取drawable,当mResourceId不为空的时候我们是从res中将资源文件解析为drawable,我们分析这里面有两个很重要的地方drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());这块儿的处理是给drawable设置边距,但是设置它有什么用呢我们继续看它的父类DynamicDrawableSpan这个类的核心draw是如何处理的。

public int getSize(Paint paint, CharSequence text,int start, int end,Paint.FontMetricsInt fm) {Drawable d = getCachedDrawable();Rect rect = d.getBounds();if (fm != null) {fm.ascent = -rect.bottom; fm.descent = 0; fm.top = fm.ascent;fm.bottom = 0;}return rect.right;}@Overridepublic void draw(Canvas canvas, CharSequence text,int start, int end, float x, int top, int y, int bottom, Paint paint) {Drawable b = getCachedDrawable();canvas.save();int transY = bottom - b.getBounds().bottom;if (mVerticalAlignment == ALIGN_BASELINE) {transY -= paint.getFontMetricsInt().descent;}canvas.translate(x, transY);b.draw(canvas);canvas.restore();}

我们来看getSize如果我们不给drawable设置Bounds值的话获取到的内容将全部为0,这样的话 fm.ascent和fm.descent以及rect.right将全为空,它所占的控件将是0,0,再到draw中的处理首先获取到drawable,在这里transY 为bottom因为b.getBounds().bottom为0,因此不会移动任何距离因此我们要在设置imageSpan的时候如果为drawable一定要设置/d.setBounds(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());这样才能保证能正确画出来。

好了既然写到了这里我们之前也写到过gifdrawable我们就将这两套东西结合一下在edittext中显示gif,当然这里是没有经过优化处理的后续有时间的话我们再对它进行优化。
首先是自定义的FullHeightSpan代码如下

public class FullHeightSpan extends ImageSpan {private int drawableHeight = 0;private Paint.FontMetricsInt fm;public FullHeightSpan(Drawable d) {super(d);}public FullHeightSpan(Context context, Uri uri) {super(context, uri);}@Overridepublic int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) {if (fm != null) {this.fm = fm;drawableHeight = fm.descent - fm.ascent;}Drawable drawable = getResizedDrawable();Rect bounds = drawable.getBounds();return bounds.right;}private Drawable getResizedDrawable() {Drawable d = getDrawable();if (drawableHeight == 0) {return d;}d.setBounds(new Rect(0, 0, (int) (1f * drawableHeight * d.getIntrinsicWidth() / d.getIntrinsicHeight()), drawableHeight));return d;}@Overridepublic void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint) {Drawable d = getResizedDrawable();canvas.save();int transY;fm = paint.getFontMetricsInt();transY = y + fm.ascent;canvas.translate(x, transY);d.draw(canvas);canvas.restore();}
}

我们先来看getSize的处理获取drawableHeight为文字的高度这里不知道 fm.descent - fm.ascent的同志最好查查资料去,然后获取getResizedDrawable这里面的处理是给drawable设置Bounds这块为什么要设置这个东西上面已经说明了如果没有会导致画不出来,最后将drawable的rect的right赋值给getSize即图片宽度。
后面的draw处理再次取出drawable的边距然后设置transY 画出图片重置canvas。
最后是调用处理

 GifDrawable d1 = new GifDrawable(getResources(), R.drawable.a);FullHeightSpan span=new FullHeightSpan(d1);Spannable spannable = new SpannableString("sss");spannable.setSpan(span, 0, 3, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);spEditText.setText(spannable);

这样的话我们就将gif图设置到了editText中了。好了代码先介绍到这里,祝大家生活愉快。
github链接点击这里

这篇关于span从入门到精通4 ImageSpan从熟悉到自定义的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1012136

相关文章

聊聊springboot中如何自定义消息转换器

《聊聊springboot中如何自定义消息转换器》SpringBoot通过HttpMessageConverter处理HTTP数据转换,支持多种媒体类型,接下来通过本文给大家介绍springboot中... 目录核心接口springboot默认提供的转换器如何自定义消息转换器Spring Boot 中的消息

Java List 使用举例(从入门到精通)

《JavaList使用举例(从入门到精通)》本文系统讲解JavaList,涵盖基础概念、核心特性、常用实现(如ArrayList、LinkedList)及性能对比,介绍创建、操作、遍历方法,结合实... 目录一、List 基础概念1.1 什么是 List?1.2 List 的核心特性1.3 List 家族成

c++日志库log4cplus快速入门小结

《c++日志库log4cplus快速入门小结》文章浏览阅读1.1w次,点赞9次,收藏44次。本文介绍Log4cplus,一种适用于C++的线程安全日志记录API,提供灵活的日志管理和配置控制。文章涵盖... 目录简介日志等级配置文件使用关于初始化使用示例总结参考资料简介log4j 用于Java,log4c

史上最全MybatisPlus从入门到精通

《史上最全MybatisPlus从入门到精通》MyBatis-Plus是MyBatis增强工具,简化开发并提升效率,支持自动映射表名/字段与实体类,提供条件构造器、多种查询方式(等值/范围/模糊/分页... 目录1.简介2.基础篇2.1.通用mapper接口操作2.2.通用service接口操作3.进阶篇3

Python自定义异常的全面指南(入门到实践)

《Python自定义异常的全面指南(入门到实践)》想象你正在开发一个银行系统,用户转账时余额不足,如果直接抛出ValueError,调用方很难区分是金额格式错误还是余额不足,这正是Python自定义异... 目录引言:为什么需要自定义异常一、异常基础:先搞懂python的异常体系1.1 异常是什么?1.2

Linux中的自定义协议+序列反序列化用法

《Linux中的自定义协议+序列反序列化用法》文章探讨网络程序在应用层的实现,涉及TCP协议的数据传输机制、结构化数据的序列化与反序列化方法,以及通过JSON和自定义协议构建网络计算器的思路,强调分层... 目录一,再次理解协议二,序列化和反序列化三,实现网络计算器3.1 日志文件3.2Socket.hpp

C语言自定义类型之联合和枚举解读

《C语言自定义类型之联合和枚举解读》联合体共享内存,大小由最大成员决定,遵循对齐规则;枚举类型列举可能值,提升可读性和类型安全性,两者在C语言中用于优化内存和程序效率... 目录一、联合体1.1 联合体类型的声明1.2 联合体的特点1.2.1 特点11.2.2 特点21.2.3 特点31.3 联合体的大小1

Python实现Word转PDF全攻略(从入门到实战)

《Python实现Word转PDF全攻略(从入门到实战)》在数字化办公场景中,Word文档的跨平台兼容性始终是个难题,而PDF格式凭借所见即所得的特性,已成为文档分发和归档的标准格式,下面小编就来和大... 目录一、为什么需要python处理Word转PDF?二、主流转换方案对比三、五套实战方案详解方案1:

Spring WebClient从入门到精通

《SpringWebClient从入门到精通》本文详解SpringWebClient非阻塞响应式特性及优势,涵盖核心API、实战应用与性能优化,对比RestTemplate,为微服务通信提供高效解决... 目录一、WebClient 概述1.1 为什么选择 WebClient?1.2 WebClient 与

springboot自定义注解RateLimiter限流注解技术文档详解

《springboot自定义注解RateLimiter限流注解技术文档详解》文章介绍了限流技术的概念、作用及实现方式,通过SpringAOP拦截方法、缓存存储计数器,结合注解、枚举、异常类等核心组件,... 目录什么是限流系统架构核心组件详解1. 限流注解 (@RateLimiter)2. 限流类型枚举 (