一行实现QQ群组头像,微信群组,圆角等效果. 并支持url直接加载图片
说点题外话. Coding
中我们总是经历着这么几个过程.
学会使用
: 不管是API
也好, 开源库也好. 总是在最开始的学会去用.了解实现原理
: 可能会因为一些不兼容, 代码的异常状态的处理不够完美等需要查看实现并修改, 或者因为你有一个好奇心向窥探一下内部实现.. 这时我们开始试着去阅读, 试着去理解.是否可以自己写一个更好的?
: 这个时候你可能已经熟悉了一个模块需要如何去写. 如何构造出一个别人没有或者扩展了新功能的一个小Demo
.终极目标
: 写出了一个功能效果更酷的Demo
, 但是这个是否是就变成了一个好的开源库? 不, 一个好的开源库不仅功能强大实用, 并且还有一个不容忽视的特点可扩展
. 这一个比较好的状态. 可以扩展, 通过对出现的问题不断完善, 慢慢的就会演变成一个强大的库
是否造轮子, 每个人看法都不一样, 我认为造轮子最起码的好处如下两点, 当然你得有时间!!!
- 对知识的全面理解的最好实践, 会一个知识点, 需要写一个小
Demo
巩固, 小Demo
放在项目中又会面临实际场景中可能没有想到的问题. 所以尽量不要只做到浅尝辄止
. - 如果不错, 或许可以帮助别人, 能帮到别人, 这应该会让自己在学习知识巩固知识的喜悦上更开心.
当然, 对于苦逼的码农来说, 不停的bug
不停的需求. 这是比较蛋疼的. 没有时间可能会阻碍到自己去学习进步.
看过第一弹的应该看到我列出了三个阶段. 结果差不多是自己挖个坑自己跳了进去. 还好大体目标还是完成了.
好了, 开始说SImageView
控件把.
控件介绍
这是一个简单到sImageView.setImageUrls("http://img3.cache.netease.com/ent/2009/4/17/20090417104402666a4.jpg");
设置一个网址即可显示图片的控件
相对ImageView
功能的扩展的控件, 但是没有继承ImageView
直接继承的View
. 比如QQ群组头像
,微信群组头像
, 设置描边
, 设置圆角矩形头像
,圆形头像
等. 几个参数搞定. 对于多个图片的排列
和图片的具体显示
进行了接口分离. 可以自定义实现任何排列效果和显示效果.
网络图片的下载会原图缓存磁盘, 并根据控件的大小加载到到内存并使用显示.
效果展示
图片可能比较大, 如果不出现, 刷新页面试试或者多等一会.
可以实现的样式
使用说明
引用方式
rootDir/app/build.gradle文件
dependencies {
// ...
compile 'com.szysky.customize:simageview:2.2';
}
xml声明方式
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"> <!--简单的配置, 默认为圆形图像,无描边-->
<com.szysky.customize.siv.SImageView
xmlns:app="http://schemas.android.com/apk/res-auto"
app:img="@mipmap/icon_test"
android:layout_width="200dp"
android:layout_height="200dp" /> <!--稍微完全的配置范例, 下面会有属性的详细说明-->
<com.szysky.customize.siv.SImageView
android:id="@+id/siv_main"
android:layout_width="match_parent"
android:layout_height="200dp"
android:background="@color/colorAccent"
app:displayType="rect"
app:border_color="@color/colorPrimary"
app:border_width="1dp"
app:img="@mipmap/ic_1"
app:scaleType="fix_XY"/> </LinearLayout>
属性说明
displayType
设置控件中的图片要以什么类型显示. 可选值如下:circle
: 圆形图片. (控件的默认值)rect
: 矩形图片.round_rect
: 圆角矩形图片.oval
: 椭圆形图片five_pointed_star
: 五角星形图片
border_color"
图片描边颜色. 只有当border_width>0
的时候才有效. 默认是黑色.border_width
图片描边的宽度. 默认值为0
, 不显示描边.img
前景图片, 以上所有的效果, 都是对前景图片进行操作处理.scaleType
类似于ImageView
的图片缩放选择. 只有当displayType="rect"
是矩形, 并且border_width=0dp
条件下才有效果. 其余场景无意义.可选值如下:center_inside
: 保持图片的完整性缩放, 可能会留白, 图片比例不变center_crop
: 保持控件全部被图片填充. 图片部分可能丢失, 图片比例不变.fix_XY
: 保持图片的完整性并且控件被全部填充. 图片不会丢失, 不会留白. 图片比例会改变.
代码设置形式
最简单暴力的设置方式
// 查找控件
SImageView sImageView = (SImageView) findViewById(R.id.siv_main);
// 直接设置一个图片URL即可, 根据控件大小进行内存缓存, 保存原图到本地磁盘缓存
sImageView.setImageUrls("http://img3.cache.netease.com/ent/2009/4/17/20090417104402666a4.jpg");
关于群组头像
// 如果你想实现QQ群组效果, 很简单因为默认是圆形类型显示, 不需要多余设置
// 直接传入多个URL, 最多支持5张. 例如
sImageView.setImageUrls(
"http://img3.cache.netease.com/ent/2009/4/17/20090417104402666a4.jpg",
"http://img3.cache.netease.com/ent/2009/4/17/20090417104402666a4.jpg",
"http://img3.cache.netease.com/ent/2009/4/17/20090417104402666a4.jpg",
"http://img3.cache.netease.com/ent/2009/4/17/20090417104402666a4.jpg",
"http://img3.cache.netease.com/ent/2009/4/17/20090417104402666a4.jpg"); // 需要微信的样式, 那么改一下 布局管理器 , 并设置显示图片类型为 矩形,
// 最多支持9张. 如下
sImageView.setDisplayShape(SImageView.TYPE_RECT)
.setLayoutManager(new WeChatLayoutManager(getApplicationContext()))
.setImageUrls(
"http://img3.cache.netease.com/ent/2009/4/17/20090417104402666a4.jpg",
"http://img3.cache.netease.com/ent/2009/4/17/20090417104402666a4.jpg",
"http://img3.cache.netease.com/ent/2009/4/17/20090417104402666a4.jpg",
"http://img3.cache.netease.com/ent/2009/4/17/20090417104402666a4.jpg",
"http://img3.cache.netease.com/ent/2009/4/17/20090417104402666a4.jpg");
以下是常用方法
SImageView sImageView = (SImageView) itemView.findViewById(R.id.siv);
// 设置描边颜色
sImageView.setBorderColor(Color.GREEN);
// 设置描边宽度 单位dp值
sImageView.setBorderWidth(1);
// 设置图片显示类型
// 可设置类型: SImageView.TYPE_CIRCLE(默认), SImageView.TYPE_OVAL,
// SImageView.TYPE_RECT, SImageView.TYPE_ROUND_RECT,
// SImageView.TYPE_FIVE_POINTED_STAR
sImageView.setDisplayShape(SImageView.TYPE_ROUND_RECT); // 设置图片的缩放类型, 只有显示类型为矩形, 并且描边宽度为0. 才有效果. 区别在xml中有说明
// 可选类型3种:SCALE_TYPE_CENTER_INSIDE(默认),
// SCALE_TYPE_FIX_XY ,SCALE_TYPE_CENTER_CROP
mSImageView.setScaleType(SImageView.SCALE_TYPE_CENTER_INSIDE); // 设置微信群组样式显示. (可以自定义measure测量排列规则)替换measure测量策略如下:
// 默认为qq群组的测量策略. 只要设置图片时传入多张图片的集合即可.
sImageView.setLayoutManager(new WeChatLayoutManager(context));
// 不仅可以设置url数组, 还支持其他设置图片方式
sImageView.setImages(List<Bitmap>); // 接收一个bitmap集合, 实现qq群组或者微信群组效果
sImageView.setIdRes(id); // 接收图片资源id
sImageView.setDrawable(Drawable); // 接收一个Drawable对象
sImageView.setBitmap(Bitmap); // 接收一个图片的bitmap
加载中的图片和加载失败的图片设置
对于网络下载图片. 会有下载失败和下载中的图片显示. 默认图片加载类ImageLoad
类中会内置两张系统两个对应图片来显示. ImageLoad
类中的加载中
和加载失败
图片会作用于全局的SImageView
控件. 也可以给SImageView
控件实例设置. 如果控件设置了. 那么优先级会比全局ImageLoad
中的图片使用优先. 如果控件没有, 那么就使用全局.
代码设置如下:
// 设置当前控件的场景图片, 优先级高于全局
sImageView.setErrPicResID(R.mipmap.ic_launcher) // 设置加载错误图片
.setLoadingResID(R.mipmap.icon_test) // 设置加载中图片
.setImageUrls("http://xxx.jpg"); // 图片故意填写一个错误 // 对于图片网址满足条件 判断正则为: "https?://.*?.(jpg|png|bmp|jpeg|gif)"
//如果不满足, 那么会认为是一个错误地址, 可动态配置, 后面说明
// 设置全局控件场景图片, (有默认图片可以不设置)
ImageLoader.getInstance(getApplicationContext()).setLoadErrResId(R.mipmap.icon_test); ImageLoader.getInstance(getApplicationContext()).setLoadingResId(R.mipmap.ic_launcher);
控件其他的方法
方法名称 | 参数说明 | 方法作用 |
---|---|---|
setCloseNormalOnePicLoad() |
布尔值 | 设置true 可以强制关闭一张图片时候的默认单张图片处理规则, 而由测量接口 ,绘制显示接口 处理. |
setOvalRatio() |
float类型, 椭圆的宽高比值(必须大于0) | 在单张图片 并且椭圆类型 显示时, 设置椭圆的显示的宽高比例 |
setRectRoundRadius() |
float类型, 设置范围0~2,默认1 | 在单张图片 并且圆角矩形类型 显示时, 设置圆角的弧度大小 |
setDrawStrategy() |
可参考下面的扩展实现, 用来设置自定义图片实现策略 | |
setLayoutManager() |
可参考下面的扩展实现, 用来设置自定义或替换 图片的排列分布规则 |
对应的getter()
方法省略.
设置图片网址匹配
上面提到过默认过滤图片链接的正则判断为"https?://.*?.(jpg|png|bmp|jpeg|gif)"
如果需要实现其他的地址规则. 可重定义过滤策略
ImageLoader.getInstance(getApplicationContext()).setPicUrlRegex("RegexStr");
// 如果设置自定义正则之后需要恢复, 那么直接设置空串即可
ImageLoader.getInstance(getApplicationContext()).setPicUrlRegex("");
输出log开关
默认类库log
是不输出的, 如果需要打开如下:
LogUtil.GlobalLogPrint = true; // 输出类库相关log信息
扩展实现
控件实现了
measure测量布局
和draw具体绘图实现
的功能分离. 你可以任意实现排列规则, 和具体的绘图显示的规则.
自定义measure测量布局
布局测量接口ILayoutManager
. 相当于RecyclerView
设置布局管理器. 或者View#onMeasure()
的作用.
目前内置了2种布局来实现多张图片的排列.
QQLayoutManager
: 控件默认排列规则, 效果类似于qq群组头像
,最大支持5
张图片WeChatLayoutManager
: 效果类似于微信群组头像
, 最大支持9
张图片
通过setLayoutManager(ILayoutManager)
来进行测量规则的具体实现类.
默认情况下, 如果控件只设置了一张图片是不会走测量的流程
. 如果需要一张图片时也需要不规则的排布. 那么通过SImageView#setCloseNormalOnePicLoad(true)
. 强制关闭.
自定义实现: 实现ILayoutManager
接口并在calculate()
实现具体的排列效果. 并返回一个子图片的位置信息集合. 接口如下. 可参考已经实现的两个类.
public interface ILayoutManager {
/**
* 布局measure排列计算方法, 具体规则由子类实现
*
* @param viewWidth 控件的宽
* @param viewHeight 控件的高
* @param viewNum 控件图片的数量
* @return 返回一个信息集合, 提供 {@link com.szysky.customize.siv.effect.IDrawingStrategy#algorithm(Canvas, int, int, Bitmap, SImageView.ConfigInfo)}使用
*/
ArrayList<LayoutInfoGroup> calculate(int viewWidth, int viewHeight, int viewNum);
/**
* 封装控件内部单个元素显示的布局信息
*/
class LayoutInfoGroup implements Cloneable{
/**
* 组合头像时, 每个单独元素可分配的最大宽高
*/
public int innerWidth;
public int innerHeight;
/**
* 每个单独元素,左上点和右下点. 可规划区域
*/
public Point leftTopPoint = new Point();
public Point rightBottomPoint = new Point();
@Override
protected Object clone() throws CloneNotSupportedException {
LayoutInfoGroup clone = (LayoutInfoGroup) super.clone();
clone.leftTopPoint.set(leftTopPoint.x, leftTopPoint.y);
clone.rightBottomPoint.set(rightBottomPoint.x, rightBottomPoint.y);
return clone;
}
}
}
自定义的图片显示
控件内置了两种图片显示. 例如: 椭圆, 圆角矩形, 描边, 五角星等. 相当于View#onDraw()
和Adapter#getView()
作用. 具体显示分离.
绘制显示接口IDrawingStrategy
内置实现:
NormalOnePicStrategy
: 当控件设置单张图片时, 默认都是正中间(矩形除外, 保留了ImageView
三种常用的缩放). 所以无需进行测量步骤. 直接通过配置的形状属性等进行相对应的配置实现效果.ConcreteDrawingStrategy
: 当控件图片为多张的时被触发. 接收ILayoutManager#calculate()
测量布局返回的子图片的信息集合, 进行具体的绘制工作. 可通过SImageView#setCloseNormalOnePicLoad(true)
强制关闭控件单张图片执行NormalOnePicStrategy
的逻辑. 全权由测量布局
,绘制显示
两个逻辑实现所有图片数量的处理.
通过setDrawStrategy(IDrawingStrategy)
来进行图片绘制显示的具体策略类.
自定义绘制策略类. 实现IDrawingStrategy
接口并实现对应方法, 方法里面有图片对应的画布,和需要显示的宽高信息等. 接口如下:
public interface IDrawingStrategy {
/**
* 根据提供的画布, 和可绘制的位置实现具体效果
*
* @param canvas {@link SImageView#onDraw(Canvas)} 中的画布
* @param childTotal 图片的总个数
* @param curChild 当前图片是第几张图片
* @param opeBitmap 需要操作的图片
* @param info 每个内部元素应该摆放的位置信息类
*/
void algorithm(Canvas canvas, int childTotal, int curChild, Bitmap opeBitmap, SImageView.ConfigInfo info);
}
缓存策略自定义
这部分写的自己不是很满意, 写着写着就有点耦合了, 最后精力不够… 好吧这是借口. 反正也能将就自定义, 用默认的就行…. [捂脸]
建议
- 尽量使控件作为头像控件显示, 如果大小低于
100dp
, 内部稍微做了一些特别处理. 性能可以好一些. - 由于内置样式较多, 导致了
cpu密集处理
. 和一些对象的开销. 如果项目性能要求较高那么可通过自定义绘图策略注入控件来优化. 这样项目中常用的效果就可以得到性能提升. - 类库需要
写外部存储的权限
, 对于新版本的动态权限
, 一定要先进行权限判断, 再对ImageLoad
进行初始化(控件的网络图片设置). 否则可能导致, 磁盘缓存无效只有内存缓存.
一行实现QQ群组头像,微信群组,圆角等效果. 并支持url直接加载图片的更多相关文章
- 十代雅阁广东车友群,雅阁广州车友群,深圳雅阁车友群,雅阁微信群、雅阁车友群、十代雅阁交流微信QQ群
最近一直在关注第十代雅阁,不论是普通汽油版本还是油电混动版本都很不错,在网上看到很多评测文章和视频 后续都会整理发布到微信群中. 由于论坛发帖,博客发文都不是很方便,为了及时沟通,先创建了微信群,方便 ...
- 微信小程序开发注意事项总结:上拉加载失效、转义字符等
1.上拉加载失效 问题背景:部分页面上拉加载失效.当使用flex布局,底部固定,中间采用自适应撑满全屏实现滚动时,发现上拉加载失效,不知道是什么原因. 解决问题: 在小程序中,官方为我们提供了原生的下 ...
- 微信小程序wx.login先执行onLaunch与onLoad加载顺序问题
@ 目录 遇到问题 请求api返回需要先登录,实际上登录已成功 问题分析 解决问题 自定义回调函数 app.js index.js 扩展提问 学习交流 随机数字随机幸运数+ My Blog 技术交流 ...
- 微信小程序 加载图片时,先拉长,再恢复正常
今天在写小程序,发现小程序的图片image如过mode设置为widthFix的话, 加载图片会被先拉伸,后恢复正常 我的处理方法是,给他一个初始的height值,或者就直接 height:auto
- 微信小程序开发——设置默认图片、错误加载图片
小程序不支持h5中的onerrorimg,只开放了binderror属性,当错误发生时,会发布到 AppService,事件对象event.detail = {errMsg: 'something w ...
- 雅阁微信群、雅阁车友群、十代雅阁交流微信QQ群
最近一直在关注第十代雅阁,不论是普通汽油版本还是油电混动版本都很不错,在网上看到很多评测文章和视频 后续都会整理发布到微信群中. 由于论坛发帖,博客发文都不是很方便,为了及时沟通,先创建了微信群,方便 ...
- 利用python在微信群中签到、抢沙发(适用于任何账号)
利用python在微信群中签到.抢沙发 注意 程序仅能在电脑上运行,运行时需要保证群界面在最前端且不被移动. 背景 我是一名高中生(2020年),疫情期间,在家上网课,有的老师让我们在班群里签到. 其 ...
- 环境与工具1:微信群刷屏 | itchat
在微信群里面,"刷屏"的行为是被谴责的,伴随着"快发红包道歉"与"送飞机票"的出现.那如果小程硬是要做到"刷屏"来验证自 ...
- Android 超高仿微信图片选择器 图片该这么加载
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/39943731,本文出自:[张鸿洋的博客] 1.概述 关于手机图片加载器,在当今像 ...
随机推荐
- Spring自动注入properties文件
实现spring 自动注入属性文件中的key-value. 1.在applicationContext.xml配置文件中,引入<util />命名空间. xmlns:util=" ...
- MD测试
# 欢迎使用 Cmd - 在线 Markdown 编辑阅读器 ------ 我们理解您需要更便捷更高效的工具记录思想,整理笔记.知识,并将其中承载的价值传播给他人,**Cmd Markdown** 是 ...
- 修改httpd默认端口号
Tomcat: vim /etc/httpd/conf/httpd.conf//别忘了service httpd restart Nginx: vim /etc/nginx/nginx.conf//完 ...
- jQuery之Ajax--快捷方法
1.ajax的快捷方法可以帮我们用最少的代码发送ajax请求. 2. $.get()方法:使用GET方式来进行异步请求.它的结构为:$.get( url [, data] [, calback] [, ...
- iOS小知识点(UI部分)
1. 父视图通过Tag来找到UIView UIView *targetView = [superView viewWithTag:10];//只在当前视图以及subviews中找,不能再孙子中找. 2 ...
- js限制输入框只能输入数字
分享下js限制输入框中只能输入数字的方法,包括整数与小数,分享几个例子,有需要的朋友参考下. 1.使用正则表达式限制输入框只能输入数字: <input type="text" ...
- <<< web里面Servlet高级应用的基础介绍
Servlet中的页面跳转?两种方式,实现跳转:内部跳转(请求转发).外部跳转(重定向)内部跳转(请求转发)特点:在服务器内部完成页面之间的跳转:请求只有一次:浏览器地址不会改变.request.ge ...
- Raspberry Pi 3 --- GPIO control
Before input 'gpio readall', need install wiringPi download "wiringPi":git clone git://git ...
- Yocto开发笔记之《Tip-stdlib库函数strtod返回nan错误》(QQ交流群:519230208)
2015.04-imx_v2015.04_3.14.38_6ul_ga+g5d63276 (Jan 04 2016 - 18:07:08) FSL Community BSP : https://co ...
- [译]JavaScript源码转换:非破坏式与再生式
原文:http://ariya.ofilabs.com/2013/06/javascript-source-transformation-non-destructive-vs-regenerative ...