前言

    很多时候我们都在刷微博或者微信朋友圈的时候都会看到很多图片,而这些图片的显示跟我们平时很多控件的显示方式都不一样,而且,当我们仔细去观察后就会发现,他加载的图片都是根据图片数量动态加载的,根据不同的图片数量来用不同的布局显示
当图片是4张的时候,就会形成一个2x2的正方形,除了一张的情况,另外的都是按照九宫格的方式显示和排列图片的。那么这种布局是怎么实现的呢,一开始,好多人都可能认为用原生的GridView就能搞掂,但是,却有几种特殊的情况是GridView解决不了的,例如4张图片的情况,或者1张,其实也可以根据图片的数量然后用几个不同布局的GridView来实现,不过那样的话就复杂得多了。而且处理起来很麻烦,其实,大部分的实现都是通过自定义ViewGroup来实现的,通过代码编写来设定childrenView的layout来实现这种布局,而NineGridView控件就是这么一个东西,代码其实很简单,100行就够了。

代码编写                         
     先自定义一个View集成ViewGroup,编辑器会提示你实现OnLayout方法,实现之,这里我们动态的添加的话其实不用到OnLayout方法,自定义一个layoutChildrenView()用来为子view设定位置就行了,该方法的实现如下:
        这代码里面在调用子view的layout方法的同时设定了本身ViewGroup的高度大小,因为NineGridView的高度是要根据子View的高度来确定的.

  1. private void layoutChildrenView(){
  2. int childrenCount = listData.size();
  3. int singleWidth = (totalWidth - gap * (3 - 1)) / 3;
  4. int singleHeight = singleWidth;
  5. //根据子view数量确定高度
  6. ViewGroup.LayoutParams params = getLayoutParams();
  7. params.height = singleHeight * rows + gap * (rows - 1);
  8. setLayoutParams(params);
  9. for (int i = 0; i < childrenCount; i++) {
  10. CustomImageView childrenView = (CustomImageView) getChildAt(i);
  11. childrenView.setImageUrl(((Image) listData.get(i)).getUrl());
  12. int[] position = findPosition(i);
  13. int left = (singleWidth + gap) * position[1];
  14. int top = (singleHeight + gap) * position[0];
  15. int right = left + singleWidth;
  16. int bottom = top + singleHeight;
  17. childrenView.layout(left, top, right, bottom);
  18. }
  19. }

复制代码

添加一个设置图片资源的接口,一般情况下我们都是用在listview来显示数据,而数据都是封装好的,这里提供一个Image封装类,接口和封装类代码如下:

  1. public void setImagesData(List<Image> lists) {
  2. if (lists == null || lists.isEmpty()) {
  3. return;
  4. }
  5. //初始化布局
  6. generateChildrenLayout(lists.size());
  7. //这里做一个重用view的处理
  8. if (listData == null) {
  9. int i = 0;
  10. while (i < lists.size()) {
  11. CustomImageView iv = generateImageView();
  12. addView(iv,generateDefaultLayoutParams());
  13. i++;
  14. }
  15. } else {
  16. int oldViewCount = listData.size();
  17. int newViewCount = lists.size();
  18. if (oldViewCount > newViewCount) {
  19. removeViews(newViewCount - 1, oldViewCount - newViewCount);
  20. } else if (oldViewCount < newViewCount) {
  21. for (int i = 0; i < newViewCount - oldViewCount; i++) {
  22. CustomImageView iv = generateImageView();
  23. addView(iv,generateDefaultLayoutParams());
  24. }
  25. }
  26. }
  27. listData = lists;
  28. layoutChildrenView();
  29. }

复制代码

Image封装类:

  1. public class Image {
  2. private String url;
  3. private int width;
  4. private int height;
  5. public Image(String url, int width, int height) {
  6. this.url = url;
  7. this.width = width;
  8. this.height = height;
  9. L.i(toString());
  10. }
  11. public String getUrl() {
  12. return url;
  13. }
  14. public void setUrl(String url) {
  15. this.url = url;
  16. }
  17. public int getWidth() {
  18. return width;
  19. }
  20. public void setWidth(int width) {
  21. this.width = width;
  22. }
  23. public int getHeight() {
  24. return height;
  25. }
  26. public void setHeight(int height) {
  27. this.height = height;
  28. }
  29. @Override
  30. public String toString() {
  31. return "image---->>url="+url+"width="+width+"height"+height;
  32. }
  33. }

复制代码

在添加数据的时候,我们要根据图片的个数来确定具体的布局情况,这个函数就是generateChildrenLayout(),实现如下:

  1. /**
  2. * 根据图片个数确定行列数量
  3. * 对应关系如下
  4. * num        row        column
  5. * 1           1        1
  6. * 2           1        2
  7. * 3           1        3
  8. * 4           2        2
  9. * 5           2        3
  10. * 6           2        3
  11. * 7           3        3
  12. * 8           3        3
  13. * 9           3        3
  14. *
  15. * @param length
  16. */
  17. private void generateChildrenLayout(int length) {
  18. if (length <= 3) {
  19. rows = 1;
  20. columns = length;
  21. } else if (length <= 6) {
  22. rows = 2;
  23. columns = 3;
  24. if (length == 4) {
  25. columns = 2;
  26. }
  27. } else {
  28. rows = 3;
  29. columns = 3;
  30. }
  31. }

复制代码

这些,就是NineGridLayout的核心代码了,是不是很简单,整个类的源码如下:

  1. package com.weixinninegridlayout;
  2. import android.content.Context;
  3. import android.graphics.Color;
  4. import android.graphics.drawable.ColorDrawable;
  5. import android.util.AttributeSet;
  6. import android.view.View;
  7. import android.view.ViewGroup;
  8. import android.widget.ImageView;
  9. import java.util.List;
  10. /**
  11. * Created by Pan_ on 2015/2/2.
  12. */
  13. public class NineGridlayout extends ViewGroup {
  14. /**
  15. * 图片之间的间隔
  16. */
  17. private int gap = 5;
  18. private int columns;//
  19. private int rows;//
  20. private List listData;
  21. private int totalWidth;
  22. public NineGridlayout(Context context) {
  23. super(context);
  24. }
  25. public NineGridlayout(Context context, AttributeSet attrs) {
  26. super(context, attrs);
  27. ScreenTools screenTools=ScreenTools.instance(getContext());
  28. totalWidth=screenTools.getScreenWidth()-screenTools.dip2px(80);
  29. }
  30. @Override
  31. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  32. super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  33. }
  34. @Override
  35. protected void onLayout(boolean changed, int l, int t, int r, int b) {
  36. }
  37. private void layoutChildrenView(){
  38. int childrenCount = listData.size();
  39. int singleWidth = (totalWidth - gap * (3 - 1)) / 3;
  40. int singleHeight = singleWidth;
  41. //根据子view数量确定高度
  42. ViewGroup.LayoutParams params = getLayoutParams();
  43. params.height = singleHeight * rows + gap * (rows - 1);
  44. setLayoutParams(params);
  45. for (int i = 0; i < childrenCount; i++) {
  46. CustomImageView childrenView = (CustomImageView) getChildAt(i);
  47. childrenView.setImageUrl(((Image) listData.get(i)).getUrl());
  48. int[] position = findPosition(i);
  49. int left = (singleWidth + gap) * position[1];
  50. int top = (singleHeight + gap) * position[0];
  51. int right = left + singleWidth;
  52. int bottom = top + singleHeight;
  53. childrenView.layout(left, top, right, bottom);
  54. }
  55. }
  56. private int[] findPosition(int childNum) {
  57. int[] position = new int[2];
  58. for (int i = 0; i < rows; i++) {
  59. for (int j = 0; j < columns; j++) {
  60. if ((i * columns + j) == childNum) {
  61. position[0] = i;//行
  62. position[1] = j;//列
  63. break;
  64. }
  65. }
  66. }
  67. return position;
  68. }
  69. public int getGap() {
  70. return gap;
  71. }
  72. public void setGap(int gap) {
  73. this.gap = gap;
  74. }
  75. public void setImagesData(List<Image> lists) {
  76. if (lists == null || lists.isEmpty()) {
  77. return;
  78. }
  79. //初始化布局
  80. generateChildrenLayout(lists.size());
  81. //这里做一个重用view的处理
  82. if (listData == null) {
  83. int i = 0;
  84. while (i < lists.size()) {
  85. CustomImageView iv = generateImageView();
  86. addView(iv,generateDefaultLayoutParams());
  87. i++;
  88. }
  89. } else {
  90. int oldViewCount = listData.size();
  91. int newViewCount = lists.size();
  92. if (oldViewCount > newViewCount) {
  93. removeViews(newViewCount - 1, oldViewCount - newViewCount);
  94. } else if (oldViewCount < newViewCount) {
  95. for (int i = 0; i < newViewCount - oldViewCount; i++) {
  96. CustomImageView iv = generateImageView();
  97. addView(iv,generateDefaultLayoutParams());
  98. }
  99. }
  100. }
  101. listData = lists;
  102. layoutChildrenView();
  103. }
  104. /**
  105. * 根据图片个数确定行列数量
  106. * 对应关系如下
  107. * num        row        column
  108. * 1           1        1
  109. * 2           1        2
  110. * 3           1        3
  111. * 4           2        2
  112. * 5           2        3
  113. * 6           2        3
  114. * 7           3        3
  115. * 8           3        3
  116. * 9           3        3
  117. *
  118. * @param length
  119. */
  120. private void generateChildrenLayout(int length) {
  121. if (length <= 3) {
  122. rows = 1;
  123. columns = length;
  124. } else if (length <= 6) {
  125. rows = 2;
  126. columns = 3;
  127. if (length == 4) {
  128. columns = 2;
  129. }
  130. } else {
  131. rows = 3;
  132. columns = 3;
  133. }
  134. }
  135. private CustomImageView generateImageView() {
  136. CustomImageView iv = new CustomImageView(getContext());
  137. iv.setScaleType(ImageView.ScaleType.CENTER_CROP);
  138. iv.setOnClickListener(new OnClickListener() {
  139. @Override
  140. public void onClick(View v) {
  141. }
  142. });
  143. iv.setBackgroundColor(Color.parseColor("#f5f5f5"));
  144. return iv;
  145. }
  146. }

复制代码

因为微信那些图片在点击的时候是有一个灰色的蒙版的,实现起来其实很简单,我们这里在自定义一个imageview,叫做CustomImageView,复写onTouchEvent方法,在onKeyDown的时候添加一个colorfilter,然后再onKeyUp的时候clear掉,这样就实现了点击有灰色蒙版的效果,同时为了方便项目加载图片的解耦,我加载图片用了picasso这个开源库,这个开源库的地址为点击打开链接 ,具体的代码如下:

  1. package com.weixinninegridlayout;
  2. import android.content.Context;
  3. import android.graphics.Color;
  4. import android.graphics.PorterDuff;
  5. import android.graphics.drawable.ColorDrawable;
  6. import android.graphics.drawable.Drawable;
  7. import android.text.TextUtils;
  8. import android.util.AttributeSet;
  9. import android.view.MotionEvent;
  10. import android.widget.ImageView;
  11. import com.squareup.picasso.Picasso;
  12. /**
  13. * Created by Pan_ on 2015/2/2.
  14. */
  15. public class CustomImageView extends ImageView {
  16. private String url;
  17. private boolean isAttachedToWindow;
  18. public CustomImageView(Context context, AttributeSet attrs) {
  19. super(context, attrs);
  20. }
  21. public CustomImageView(Context context) {
  22. super(context);
  23. }
  24. @Override
  25. public boolean onTouchEvent(MotionEvent event) {
  26. switch (event.getAction()) {
  27. case MotionEvent.ACTION_DOWN:
  28. Drawable drawable=getDrawable();
  29. if(drawable!=null) {
  30. drawable.mutate().setColorFilter(Color.GRAY,
  31. PorterDuff.Mode.MULTIPLY);
  32. }
  33. break;
  34. case MotionEvent.ACTION_MOVE:
  35. break;
  36. case MotionEvent.ACTION_CANCEL:
  37. case MotionEvent.ACTION_UP:
  38. Drawable drawableUp=getDrawable();
  39. if(drawableUp!=null) {
  40. drawableUp.mutate().clearColorFilter();
  41. }
  42. break;
  43. }
  44. return super.onTouchEvent(event);
  45. }
  46. @Override
  47. public void onAttachedToWindow() {
  48. isAttachedToWindow = true;
  49. setImageUrl(url);
  50. super.onAttachedToWindow();
  51. }
  52. @Override
  53. public void onDetachedFromWindow() {
  54. Picasso.with(getContext()).cancelRequest(this);
  55. isAttachedToWindow = false;
  56. setImageBitmap(null);
  57. super.onDetachedFromWindow();
  58. }
  59. public void setImageUrl(String url) {
  60. if (!TextUtils.isEmpty(url)) {
  61. this.url = url;
  62. if (isAttachedToWindow) {
  63. Picasso.with(getContext()).load(url).placeholder(new ColorDrawable(Color.parseColor("#f5f5f5"))).into(this);
  64. }
  65. }
  66. }
  67. }
源码要的留言

一百行代码实现微信朋友圈九宫格图片显示相关推荐

  1. Android 实现仿微信朋友圈九宫格图片+NineGridView+ImageWatcher(图片查看:1.预览,2.拖动,3.放大,4.左右滑动,5.长按保存到手机)的功能

    一.测试 实现: 二.添加依赖包: implementation 'androidx.appcompat:appcompat:1.1.0'implementation 'androidx.recycl ...

  2. 30行代码实现微信朋友圈自动点赞

    首先祝大家新年快乐,过年了,允许我水一篇博客.不知道大家都回老家了没,不过我是没有回去,晚上吃完年夜饭看到很多人发朋友圈,为了增进和大家的友谊,于是就想着给大家点个赞,无奈内容太多了,就搞个自动化脚本 ...

  3. 【Android 控件使用及源码解析】 GridView规则显示图片仿微信朋友圈发图片

    今天闲下来想用心写一点东西,发现没什么可写的,就写一下最近项目上用到的一些东西吧.最近项目要求上传多图并且多图显示,而且要规则的显示,就像微信朋友圈的图片显示一样. 想了一下用GridView再适合不 ...

  4. android从九宫格全屏预览,仿微信朋友圈展示图片的九宫格图片展示控件,支持点击图片全屏预览大图...

    AssNineGridView 仿微信朋友圈展示图片的九宫格图片展示控件,支持点击图片全屏预览大图(可自定义). 写在前面 这是一个九宫格控件,本来是很久之前就写好了,现在才开源出来,也是看了很多优秀 ...

  5. 世界那么大,我想去看看。Django仿制微信朋友圈九宫格相册(1)

    前面文章里的Python和Django知识点很重要,但过于零散.我们学习最终的目的还是应用.我们今天就来看下如何利用Django仿制微信朋友圈的九宫格相册.本教程比较长,会分成2部分发布,欢迎持续关注 ...

  6. 微信朋友圈的图片上传,多图上传怎么去撸才合适?我们一起来实现吧!

    微信朋友圈的图片上传,多图上传怎么去撸才合适?我们一起来实现吧! 图片上传是非常常见的功能,而多图上传在大多数应用中也是非常常见的,比如微信的朋友圈,微博的动态,都是有九宫格图片的,那这里肯定涉及了多 ...

  7. 一个仿微信朋友圈的图片查看框架 - PhotoViewer

    PhotoViewer 该图片查看器是模仿微信朋友圈查看图片编写 allprojects {repositories {...maven { url 'https://jitpack.io' }}}复 ...

  8. 安卓开发仿微信图片拖拽_仿微信朋友圈发表图片拖拽和删除功能

    原标题:仿微信朋友圈发表图片拖拽和删除功能 中国联通在香港公布了上市公司2017年中期业绩.2017年上半年,公司主要业绩指标持续向好,收入稳步回升,服务收入达到人民币1,241.1亿元,同比增长3. ...

  9. 朋友圈(类似微信朋友圈)的显示

    我们都知道,朋友圈的图片显示基本是随机的(一张图片时一排显示一张,两张图片时一排显示两张,三张图片时显示三张,超过三张就换行显示),这在很多应用中都经常运用到.这是示例图片 以android stud ...

最新文章

  1. 当人工智能遇到神经科学,二者联手势不可挡!
  2. python中outside loop_Python: 'break' outside loop
  3. (转载)如斯场景 似曾相识
  4. 面试问:Kafka 为什么速度那么快?
  5. OPEN(SAP) UI5 扫盲
  6. Spring(2)bean注入--Set方法注入
  7. 委托、事件的个人理解
  8. 视觉工程师面试指南_选择正确视觉效果的终极指南
  9. centos7--shell脚本自动实现bond配置-第二版
  10. drools 7.x DSL领域语言入门
  11. ecshop修改后台登陆密码
  12. HTML+CSS淘宝 页眉导航栏以及Logo搜索框的实现
  13. kaldi中文语音识别
  14. 六大接口管理平台,总有一款适合你的!
  15. aspen压缩因子_Aspen物性参数中英文对照
  16. 智慧金融系统软件需求规格说明(IEEE 830 标准)最终版
  17. python之dict
  18. linux chown sh,chown命令示例
  19. JavaScript mongodb(数据库)简单值
  20. android常用控件实验报告,ui设计实验报告.doc

热门文章

  1. Stay Hungry,Stay Foolish的解读
  2. 高级架构师_Redis_第1章_缓存原理与设计
  3. 计算机windows7启动不了桌面,电脑开机进不了桌面,教您电脑开机进不了桌面怎么办...
  4. 第二章:IEEE2030.5官网相关资料介绍
  5. 破解分布式数据库全局死锁难题 GBase 8c引领数据库领域变革
  6. python识别汉字笔画_Python识别图片中的文字
  7. Bootstrap 组件:缩略图组件(thumbnail)
  8. 注册淘宝安装工要求 淘宝安装工怎么接活
  9. 【数据库原理】概念结构、逻辑结构设计案例
  10. 聚类dbi指数_聚类算法