• 一行实现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文件

    1 dependencies {
    2     // ...
    3     compile 'com.szysky.customize:simageview:2.2';
    4 }

    xml声明方式

     1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     2     xmlns:app="http://schemas.android.com/apk/res-auto"
     3     android:orientation="vertical"
     4     android:layout_width="match_parent"
     5     android:layout_height="match_parent">
     6     
     7     <!--简单的配置, 默认为圆形图像,无描边-->
     8    <com.szysky.customize.siv.SImageView
     9        xmlns:app="http://schemas.android.com/apk/res-auto"
    10        app:img="@mipmap/icon_test"
    11        android:layout_width="200dp"
    12        android:layout_height="200dp" />
    13     
    14     <!--稍微完全的配置范例, 下面会有属性的详细说明-->
    15     <com.szysky.customize.siv.SImageView
    16        android:id="@+id/siv_main"
    17        android:layout_width="match_parent"
    18        android:layout_height="200dp"
    19        android:background="@color/colorAccent"
    20        app:displayType="rect"
    21        app:border_color="@color/colorPrimary"
    22        app:border_width="1dp"
    23        app:img="@mipmap/ic_1"
    24        app:scaleType="fix_XY"/>
    25        
    26 </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 : 保持图片的完整性并且控件被全部填充. 图片不会丢失, 不会留白. 图片比例会改变.

    代码设置形式

    最简单暴力的设置方式

    1 // 查找控件
    2 SImageView sImageView = (SImageView) findViewById(R.id.siv_main);
    3 // 直接设置一个图片URL即可, 根据控件大小进行内存缓存, 保存原图到本地磁盘缓存
    4 sImageView.setImageUrls("http://img3.cache.netease.com/ent/2009/4/17/20090417104402666a4.jpg");

    关于群组头像

     1 // 如果你想实现QQ群组效果, 很简单因为默认是圆形类型显示, 不需要多余设置
     2 // 直接传入多个URL, 最多支持5张. 例如
     3 sImageView.setImageUrls(
     4                         "http://img3.cache.netease.com/ent/2009/4/17/20090417104402666a4.jpg",
     5                         "http://img3.cache.netease.com/ent/2009/4/17/20090417104402666a4.jpg",
     6                         "http://img3.cache.netease.com/ent/2009/4/17/20090417104402666a4.jpg",
     7                         "http://img3.cache.netease.com/ent/2009/4/17/20090417104402666a4.jpg",
     8                         "http://img3.cache.netease.com/ent/2009/4/17/20090417104402666a4.jpg");
     9                         
    10                         
    11 // 需要微信的样式, 那么改一下 布局管理器 , 并设置显示图片类型为 矩形,
    12 // 最多支持9张.  如下
    13 sImageView.setDisplayShape(SImageView.TYPE_RECT)
    14         .setLayoutManager(new WeChatLayoutManager(getApplicationContext()))
    15         .setImageUrls(
    16               "http://img3.cache.netease.com/ent/2009/4/17/20090417104402666a4.jpg",
    17               "http://img3.cache.netease.com/ent/2009/4/17/20090417104402666a4.jpg",
    18               "http://img3.cache.netease.com/ent/2009/4/17/20090417104402666a4.jpg",
    19               "http://img3.cache.netease.com/ent/2009/4/17/20090417104402666a4.jpg",
    20               "http://img3.cache.netease.com/ent/2009/4/17/20090417104402666a4.jpg");

    以下是常用方法

     1 SImageView sImageView = (SImageView) itemView.findViewById(R.id.siv);
     2 // 设置描边颜色
     3 sImageView.setBorderColor(Color.GREEN);
     4 // 设置描边宽度 单位dp值
     5 sImageView.setBorderWidth(1);
     6  // 设置图片显示类型 
     7  // 可设置类型: SImageView.TYPE_CIRCLE(默认), SImageView.TYPE_OVAL,     
     8  //           SImageView.TYPE_RECT, SImageView.TYPE_ROUND_RECT, 
     9  //           SImageView.TYPE_FIVE_POINTED_STAR
    10  sImageView.setDisplayShape(SImageView.TYPE_ROUND_RECT);
    11  
    12  // 设置图片的缩放类型, 只有显示类型为矩形, 并且描边宽度为0. 才有效果. 区别在xml中有说明
    13  // 可选类型3种:SCALE_TYPE_CENTER_INSIDE(默认), 
    14  //           SCALE_TYPE_FIX_XY ,SCALE_TYPE_CENTER_CROP
    15  mSImageView.setScaleType(SImageView.SCALE_TYPE_CENTER_INSIDE);
    16  
    17  // 设置微信群组样式显示.  (可以自定义measure测量排列规则)替换measure测量策略如下:
    18  // 默认为qq群组的测量策略. 只要设置图片时传入多张图片的集合即可.
    19 sImageView.setLayoutManager(new WeChatLayoutManager(context));
    20 // 不仅可以设置url数组, 还支持其他设置图片方式
    21 sImageView.setImages(List<Bitmap>); // 接收一个bitmap集合, 实现qq群组或者微信群组效果
    22 sImageView.setIdRes(id);            // 接收图片资源id
    23 sImageView.setDrawable(Drawable);   // 接收一个Drawable对象
    24 sImageView.setBitmap(Bitmap);       // 接收一个图片的bitmap

    加载中的图片和加载失败的图片设置

    对于网络下载图片. 会有下载失败下载中的图片显示. 默认图片加载类ImageLoad类中会内置两张系统两个对应图片来显示. ImageLoad类中的加载中加载失败图片会作用于全局的SImageView控件. 也可以给SImageView控件实例设置. 如果控件设置了. 那么优先级会比全局ImageLoad中的图片使用优先. 如果控件没有, 那么就使用全局.

    代码设置如下:

     1 // 设置当前控件的场景图片, 优先级高于全局
     2 sImageView.setErrPicResID(R.mipmap.ic_launcher)     // 设置加载错误图片
     3         .setLoadingResID(R.mipmap.icon_test)        // 设置加载中图片
     4         .setImageUrls("http://xxx.jpg");            // 图片故意填写一个错误
     5         
     6         
     7 // 对于图片网址满足条件 判断正则为: "https?://.*?.(jpg|png|bmp|jpeg|gif)"
     8 //如果不满足, 那么会认为是一个错误地址, 可动态配置, 后面说明
     9 // 设置全局控件场景图片, (有默认图片可以不设置)
    10 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)"

    如果需要实现其他的地址规则. 可重定义过滤策略

    1 ImageLoader.getInstance(getApplicationContext()).setPicUrlRegex("RegexStr");
    2 // 如果设置自定义正则之后需要恢复, 那么直接设置空串即可
    3 ImageLoader.getInstance(getApplicationContext()).setPicUrlRegex("");

    输出log开关

    默认类库log是不输出的, 如果需要打开如下:

    1 LogUtil.GlobalLogPrint = true;      // 输出类库相关log信息

    扩展实现

    控件实现了measure测量布局draw具体绘图实现的功能分离. 你可以任意实现排列规则, 和具体的绘图显示的规则.

    自定义measure测量布局

    布局测量接口ILayoutManager. 相当于RecyclerView设置布局管理器. 或者View#onMeasure()的作用.

    目前内置了2种布局来实现多张图片的排列.

    • QQLayoutManager: 控件默认排列规则, 效果类似于qq群组头像,最大支持5张图片
    • WeChatLayoutManager: 效果类似于微信群组头像, 最大支持9张图片

    通过setLayoutManager(ILayoutManager)来进行测量规则的具体实现类.

    默认情况下, 如果控件只设置了一张图片是不会走测量的流程. 如果需要一张图片时也需要不规则的排布. 那么通过SImageView#setCloseNormalOnePicLoad(true). 强制关闭.

    自定义实现: 实现ILayoutManager接口并在calculate()实现具体的排列效果. 并返回一个子图片的位置信息集合. 接口如下. 可参考已经实现的两个类.

     1 public interface ILayoutManager {
     2     /**
     3      * 布局measure排列计算方法, 具体规则由子类实现
     4      *
     5      * @param viewWidth 控件的宽
     6      * @param viewHeight 控件的高
     7      * @param viewNum   控件图片的数量
     8      * @return  返回一个信息集合, 提供 {@link com.szysky.customize.siv.effect.IDrawingStrategy#algorithm(Canvas, int, int, Bitmap, SImageView.ConfigInfo)}使用
     9      */
    10     ArrayList<LayoutInfoGroup> calculate(int viewWidth, int viewHeight, int viewNum);
    11     /**
    12      * 封装控件内部单个元素显示的布局信息
    13      */
    14     class LayoutInfoGroup implements Cloneable{
    15         /**
    16          * 组合头像时, 每个单独元素可分配的最大宽高
    17          */
    18         public int innerWidth;
    19         public int innerHeight;
    20         /**
    21          * 每个单独元素,左上点和右下点.   可规划区域
    22          */
    23         public Point leftTopPoint = new Point();
    24         public Point rightBottomPoint = new Point();
    25         @Override
    26         protected Object clone() throws CloneNotSupportedException {
    27             LayoutInfoGroup clone = (LayoutInfoGroup) super.clone();
    28             clone.leftTopPoint.set(leftTopPoint.x, leftTopPoint.y);
    29             clone.rightBottomPoint.set(rightBottomPoint.x, rightBottomPoint.y);
    30             return clone;
    31         }
    32     }
    33 }

    自定义的图片显示

    控件内置了两种图片显示. 例如: 椭圆, 圆角矩形, 描边, 五角星等. 相当于View#onDraw()Adapter#getView()作用. 具体显示分离.

    绘制显示接口IDrawingStrategy

    内置实现:

    • NormalOnePicStrategy: 当控件设置单张图片时, 默认都是正中间(矩形除外, 保留了ImageView三种常用的缩放). 所以无需进行测量步骤. 直接通过配置的形状属性等进行相对应的配置实现效果.
    • ConcreteDrawingStrategy: 当控件图片为多张的时被触发. 接收ILayoutManager#calculate()测量布局返回的子图片的信息集合, 进行具体的绘制工作. 可通过SImageView#setCloseNormalOnePicLoad(true)强制关闭控件单张图片执行NormalOnePicStrategy的逻辑. 全权由测量布局,绘制显示两个逻辑实现所有图片数量的处理.

    通过setDrawStrategy(IDrawingStrategy)来进行图片绘制显示的具体策略类.

    自定义绘制策略类. 实现IDrawingStrategy接口并实现对应方法, 方法里面有图片对应的画布,和需要显示的宽高信息等. 接口如下:

     1 public interface IDrawingStrategy {
     2     /**
     3      * 根据提供的画布, 和可绘制的位置实现具体效果
     4      *
     5      * @param canvas    {@link SImageView#onDraw(Canvas)} 中的画布
     6      * @param childTotal 图片的总个数
     7      * @param curChild  当前图片是第几张图片                  
     8      * @param opeBitmap 需要操作的图片                                                  
     9      * @param info      每个内部元素应该摆放的位置信息类
    10      */
    11     void algorithm(Canvas canvas, int childTotal, int curChild, Bitmap opeBitmap, SImageView.ConfigInfo info);
    12 }

    缓存策略自定义

    这部分写的自己不是很满意, 写着写着就有点耦合了, 最后精力不够… 好吧这是借口. 反正也能将就自定义, 用默认的就行…. [捂脸]

    建议

    • 尽量使控件作为头像控件显示, 如果大小低于100dp, 内部稍微做了一些特别处理. 性能可以好一些.
    • 由于内置样式较多, 导致了cpu密集处理. 和一些对象的开销. 如果项目性能要求较高那么可通过自定义绘图策略注入控件来优化. 这样项目中常用的效果就可以得到性能提升.
    • 类库需要写外部存储的权限, 对于新版本的动态权限, 一定要先进行权限判断, 再对ImageLoad进行初始化(控件的网络图片设置). 否则可能导致, 磁盘缓存无效只有内存缓存.
  • 相关阅读:
    harbor 报错,注意harbor.yml文件格式。
    nginx中rewrite文件
    改善github网络连接
    代码层实现六种质量属性战术
    读漫谈架构有感
    “淘宝网”的六个质量属性的六个常见属性
    寒假学习进度16:tensorflow2.0 波士顿房价预测
    寒假学习进度15:tensorflow2.0 优化器
    寒假学习进度14:对mnist数据集实现逻辑回归
    寒假学习进度13:tensorflow2.0 mnist简介
  • 原文地址:https://www.cnblogs.com/huolongluo/p/6214172.html
Copyright © 2020-2023  润新知