android网络开源框架volley(四)——谈谈图片加载续——九张图片相册的展示(微信微博等)

多附件上传MultiUpload 利用ajax技术一次可以上传多个附件MultiUpload的Demo。 立即下载

    需要实现一个相册的展示,默认最多显示九张,超过了就显示前九张。很常见的功能,比如新浪微博、微信等:

        

不打算再弄个新标题,就在图片加载的后面来个二级标题——九张图片相册的展示(微信微博等)。下面开始进入正题。


1、分析


    选择的上面两张图片还是比较有代表性的,先来分析下他们。

a、九张图片3×3的显示,很自然的想到,其他的比如6张3×2,五张的话3+2的显示;比较特殊的就是四张图片显示时时2×2,而不是3+1的显示。

b、图片之间有间隔

c、点击图片跳到下一个界面展示

d、另外一点也是不定的一点,这个相册宽度要不要充满屏幕,还是固定宽度,这个就看自己需求咯。

    用UI Automator Viewer查看,新浪的整个就是一个view,微信的是FrameLayout + n * view。网上搜了下,有没有现成的实现,貌似不好搜,不知道用什么关键字,带九的话都是关于.9图片的。找不到就算了,利用自己现在掌握的,从头写个吧。

    第一个想到的还是自己去继承一个已经存在的布局,比如LinearLayout,TableLayout等。不过又想起周一的面试被鄙视的情形,没有自己画过一个view,都是继承、拼凑的,所以想,这次自己写吧。然后可能需要自己去画图片,实现监听,等等,代价很大,还是放弃咯。最后选择方案:继承ViewGroup,里面添加ImageView,这样不用关心单击事件和Image的绘制。

    view上决定了剩下的就是处理这个控件对外的接口。设置一个监听,处理图片的点击事件;设置展示图片的数据源;在加几个小的设置,比如设置默认加载的图片size,加载图片之前的显示,加载失败的显示。设置图片的数据源,这个是传一个url还是Bitmap或者其他,最后选择了url,在内部实现图片的记载。所以为什么标题用了一个二级标题——还是用volley的ImageLoader实现图片的加载。在测试的时候发现,可能还需要自己去实现图片的本地保存,这个后面再说。


2、实现


    直接贴代码吧,注释写的都比较详细:

/**
 * 
 * 九张图片相册的展示
 * http://blog.youkuaiyun.com/ttdevs
 * @author ttdevs 2014年3月13日
 * 
 */
public class NineImageView extends ViewGroup implements OnClickListener {

	/** 该view的item单击事件接口 */
	public interface OnItemClickListener {
		/**
		 * 单击回调,会把所有的url都返回,用户自己计算当前url在所有url中的位置
		 * 
		 * @param mLists
		 *            相册所有的url
		 * @param url
		 *            当前被点击的url
		 */
		public void onItemClick(List<String> mLists, String url);
	}

	/** 图片的边距 */
	private static final int ITEM_PADDING = 4;
	/** 图片的默认尺寸 */
	private static final int ITEM_WIDTH = 300;

	private OnItemClickListener mListener;
	private ImageLoader mImageLoader;
	private List<ImageContainer> containerList; // 还没有充分的利用,用来取消请求
	private List<ImageView> cacheViewList;
	private List<ImageView> viewList;
	private List<String> mLists;

	private int mDefaultImageId;
	private int mErrorImageId;

	public NineImageView(Context context) {
		this(context, null);
	}

	public NineImageView(Context context, AttributeSet attrs) {
		super(context, attrs);
		mImageLoader = VolleyQueue.getImageLoader(); // 拿到ImageLoader
		cacheViewList = new ArrayList<ImageView>();
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		if (mLists != null && mLists.size() > 0) {
			int width = MeasureSpec.getSize(widthMeasureSpec);
			int height = width;
			// 开始继续自己的高度
			// 是宽的1倍(7-9张)还是1/3(1-3张)或者2/3(4-6张)
			int size = mLists.size();
			if (size <= 3) {
				height = width / 3;
			} else if (size <= 6) {
				height = 2 * width / 3;
			} else {
				height = width;
			}
			setMeasuredDimension(width, height);
		} else {
			super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		}

		// 发起请求,不知道这个地方是不是合适。
		// 暂时没发现问题(所有请求都是异步的)
		startReqeustImage(); // TODO
	}

	/** 发起网络请求 */
	private void startReqeustImage() {
		for (ImageView image : viewList) {
			requestImageFromNetWork(image);
		}
	}

	@Override
	protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
		if (mLists != null && mLists.size() > 0) {
			int width = (right - left) / 3; // 每张图片的宽占整个父view的1/3
			int height = width; // 宽和好一样,也就是一个正方形的图片
			layoutItemImage(width, height);
		}
	}

	/** 对相册中的图片进行布局 */
	private void layoutItemImage(int width, int height) {
		// 脑袋不好使,第一次写的很恶心,后来优化成这个样子
		int size = mLists.size() >= 9 ? 9 : mLists.size(); // 只处理9条,大于9时只处理前9条
		int mod = (size == 4) ? 2 : 3; // 4条的时候是2*2,其他都是3*X
		int sLeft, sTop, sRight, sBottom;
		for (int i = 0; i < size; i++) {
			sLeft = (i % mod) * width + ITEM_PADDING;
			sTop = (i / mod) * height + ITEM_PADDING;
			sRight = ((i % mod) + 1) * width - ITEM_PADDING;
			sBottom = ((i / mod) + 1) * height - ITEM_PADDING;
			viewList.get(i).layout(sLeft, sTop, sRight, sBottom);
		}
	}

	@Override
	protected void onDetachedFromWindow() {
		// TODO 这个地方不知道是否合适
		if (containerList != null && containerList.size() > 0) {
			for (ImageContainer container : containerList) {
				container.cancelRequest();
			}
		}
		super.onDetachedFromWindow();
	}

	@Override
	protected void drawableStateChanged() {
		super.drawableStateChanged();
		invalidate();
	}

	/**
	 * 设置数据源:数据源的字符串集合
	 * 
	 * @param lists
	 *            数据源
	 * @param defaultImage
	 *            默认显示的图片
	 * @param errorImage
	 *            加载失败时候显示的图片
	 */
	public void setImageList(List<String> lists, int defaultImage, int errorImage) {
		if (defaultImage == 0 || errorImage == 0) {
			return;
		} else {
			mDefaultImageId = defaultImage;
			mErrorImageId = errorImage;
		}

		if (mLists == null) {
			mLists = new ArrayList<String>();
		} else {
			mLists.clear();
		}
		mLists.addAll(lists);

		if (viewList == null) {
			viewList = new ArrayList<ImageView>();
		} else {
			viewList.clear();
		}
		if (containerList == null) {
			containerList = new ArrayList<ImageContainer>();
		} else {
			for (ImageContainer container : containerList) {
				container.cancelRequest();
			}
			containerList.clear();
		}
		
		int size = (mLists.size()) >= 9 ? 9 : mLists.size(); // 默认最多显示9个
		// 这部分是用来实现对view的复用,
		// 当某时刻的某个相册大于等于9就等同于初始化的时候就创建了9个ImageView
		if (size > cacheViewList.size()) { // 维护自己的复用ImageView
			int add = size - cacheViewList.size();
			for (int i = 0; i < add ; i++) {
				ImageView ivImage = new ImageView(getContext());
				ivImage.setImageResource(mDefaultImageId);
				ivImage.setOnClickListener(this);
				ivImage.setScaleType(ScaleType.CENTER_CROP);
				cacheViewList.add(ivImage);
			}
		}
		for (int i = 0; i < size; i++) {
			ImageView ivImage = cacheViewList.get(i);
			ivImage.setImageResource(mDefaultImageId);
			ivImage.setTag(mLists.get(i));
			viewList.add(ivImage);
			addView(ivImage);
		}
		invalidate();// requestLayout();
	}

	/** 请求网络图片 */
	private void requestImageFromNetWork(final ImageView ivImage) {

		int width = getMeasuredWidth();
		width = (width == 0) ? ITEM_WIDTH : (width / 3);

		ImageContainer container = mImageLoader.get((String) ivImage.getTag(), new ImageListener() {

			@Override
			public void onErrorResponse(VolleyError error) {
				if (mErrorImageId != 0) {
					ivImage.setImageResource(mErrorImageId);
				}
			}

			@Override
			public void onResponse(ImageContainer response, boolean isImmediate) {
				if (response.getBitmap() != null) {
					ivImage.setImageBitmap(response.getBitmap());
				} else if (mDefaultImageId != 0) {
					ivImage.setImageResource(mDefaultImageId);
				}
			}
		}, width, width);
		containerList.add(container);
	}

	/**
	 * 监听item的单击事件
	 * 
	 * @param listener
	 */
	public void setOnItemClickListener(OnItemClickListener listener) {
		mListener = listener;
	}

	/**
	 * item(imageview) onclick
	 */
	@Override
	public void onClick(View v) {
		if (mListener != null) {
			mListener.onItemClick(mLists, (String) v.getTag());
		}
	}
}


3、总结


    需要用到volley中的ImageLoader。剩下的就可以直接在你的布局中使用了。不熟悉view的整个处理流程,对部分资源的回收还不知道如何处理。等看明白了再回来优化。开始的时候提到可能要做图片缓存的情况,是因为在测试的时候发现网络加载图片很卡顿,不过我测试的都是1MB以上的图片。考虑到节约流量,可能需要在缓存的时候将图片保存到本地,避免下次去请求。

最终效果如下:




Android 图片选择、预览、九宫格图片控件、拖拽排序九宫格图片控件 Android 图片选择、预览、九宫格图片控件、拖拽排序九宫格图片控件,功能如下: 单图选择 多图选择 拍照选择 图片选择预览(支持微博长图)、缩放查看 图片预览(支持微博长图)、缩放查看 支持 glide、picasso、universal-image-loader、xutils 图片加载库 支持配置列表滚动时是否暂停加载图片,列表停止滚动时恢复加载图片(用 xutils 作为图片加载库时该配置无效) 正方形、圆形头像、带边框的圆形头像控件 朋友圈列表界面的九宫格图片控件 发布朋友圈界面的可拖拽排序的九宫格图片控件 覆盖相应的资源文件来定制界面 BGAPhotoHelper 图片裁剪、拍照 立即下载

相关推荐

MultiImageView:Android库可在一个ImageView中显示一些图像,例如群聊的头像。 由Stfalcon制造

MultiImageView 用于在一个MultiImageView中显示一些图像的库,例如群聊的化身 我们是谁 需要iOS和Android应用程序,MVP开发或原型制作吗? 通过与我们联系。 自2009年以来,我们一直在开发软件,我们是该领域的知名专家。 查看我们的并从查看更多库。 下载 在存储库末尾将jitpack添加到项目的根build.gradle文件中。 allprojects { repositories { ... maven { url 'https://jitpack.io' } } } 添加依赖项 dependencies { ... implementation "com.github.stfalcon-studio:StfalconFixturer-android:[last_version]" } 用法 将MultiImage

Android可拖拽排序的多图上传组件UploadMultiImageView

目录欢迎使用 UploadMultiImageView 多图上传组件先看效果(录的视频) 欢迎使用 UploadMultiImageView 多图上传组件 项目中经常会有多图上传的需求,每次都重复写,实在不是一个好办法。于是基于 recycleview 来实现一个仅仅需要 【十几行代码】 就可拥有拖拽功能的多图上传组件。 先看效果(录的视频) undefined ...

马腾蛟的博客 1375

github开源项目photoview

github开源项目photoview,可实现图片缩放,平移操作。压缩包内包含两个jar包,都是本人手动封装。一个带源码,一个没有。用法请自行搜索

android 多图上传插件,可拖拽排序的多图上传组件UploadMultiImageView

UploadMultiImageView 多图上传组件项目中经常会有多图上传的需求,每次都重复写,实在不是一个好办法。于是基于 【recycleview】 来实现一个仅仅需要 【十几行代码】 就可拥有拖拽排序功能的多图上传组件。目前使用的AndroidX,不是的同学,请尽快升级吧!先看效果使用说明1、在根目录 build.gradle 添加:allprojects {repositories {....

weixin_35809747的博客 2969

实现仿微信选择多张图片,删除, 浏览等,以九宫格的样式显示,最多可显示九张图片

实现仿微信选择多张图片,删除, 浏览等,以九宫格的样式显示,最多可显示九张图片

主板USB接口全部失效解决方案(通用串行总线USB控制器有黄色叹号)保姆级教程亲测有效

通用串行总线控制器总是有叹号解决办法 办公室的崩腾时代老电脑,疫情期间没人用,来了开机之后发现鼠标键盘都用不了,本以为是主机放时间长出了问题,后来想起来就百度了“鼠标键盘都失效”的标题,结果发现了“串行总线控制器总是感叹号”的关联问题。正好办公室电脑都装有teamviwer常用来远程办公(在家偷懒)。所以通过远程发现电脑室可以运行的。并在控制面板发现:通用串行总线控制器总是感叹号,插入外设时USB无反应。如图:​ 并且右键选中其中一个,点击最后一个选项:“属性” 可以发现“设备状态”中会提示“由...

xiao_bai_0_0的博客 2万+

Android 宫格图控件MultiImageView(RecyclerView适配器中展示不定数量的图片)

Android 宫格图控件MultiImageView(RecyclerView适配器中展示不定数量的图片) 最近的github上的996ICU在IT界应该很多人听说了,不知道优快云上什么是最受大家欢迎的,最重要的是大家开心就好,在北京 杭州 上海 广州等各地的同胞们每天记得给自己一个微笑...... 实现效果如下图: 一.实现逻辑: 1.首先创建图片实体类 public...

shenggaofei的博客 1359

FortiClient EMS实战:从安装到配置的全流程优化指南

本文详细解析了FortiClient EMS 7.0版本的部署与优化全流程,帮助企业构建零信任终端安全体系。从环境规划、高效安装、终端纳管到高级运维,提供实战指南和优化技巧,特别适用于Windows Server环境,助力企业提升终端安全管理效率。

weixin_29325007的博客 550

推荐一款强大的多图像显示库——MultiImageView

推荐一款强大的多图像显示库——MultiImageView 去发现同类优质开源项目:https://gitcode.com/ 在Android应用开发中,我们常常会遇到需要在一个视图中展示多个图片的场景,比如群聊头像、团队成员缩略图等。这时,一款优秀的多图像显示库就显得尤为重要。今天,我要向大家推荐的便是MultiImageView,一个专为实现多图合并展示而设计的Android库。 项目介绍 M...

gitblog_00068的博客 402

Alibaba Java Coding Guidelines,以后我的Java代码规范,就靠它了

前言 对于Java代码规范,业界有统一的标准,不少公司对此都有一定的要求。但是即便如此,庞大的Java使用者由于经验很水平的限制,未必有规范编码的意识,而且即便经验丰富的老Java 程序员也无法做到时刻将规范牢记于心。所以对于代码规范扫描工具,一经问世就广受青睐,阿里巴巴出品的Alibaba Java Coding Guidelines(阿里巴巴Java代码规约扫描,以下简称为AJCG)插件便是其...

java梦工厂 860

QCC308X/518X/309X加LDAC解码

QCC308X/518X/309X加LDAC解码。

Alex_886的博客 6612

推荐一款创新图像展示框架:MultiImageViewLayout

推荐一款创新图像展示框架:MultiImageViewLayout 项目简介 在移动应用和网页设计中,如何优雅地展示多张图片常常是一个挑战。 是一个专为 Android 设计的开源库,它提供了一种新颖且灵活的方式来排列和展示多张图片,使得图片布局更加丰富多样。 技术分析 MultiImageViewLayout 基于 Android 的 ViewGroup 框架构建,使用自定义的 Layout 参...

gitblog_00053的博客 402

逆向工程师必备:用MDL绕过游戏保护读取内存数据的完整流程(附POC代码)

本文深入探讨了内核级内存访问技术,重点介绍了如何利用MDL(Memory Descriptor List)机制稳定、隐蔽地绕过游戏反作弊系统读取进程内存。通过对比MmCopyVirtualMemory等方法的优劣,提供了完整的MDL映射实战代码与反检测策略,为逆向工程师在内核态进行安全内存操作提供了专业指导。

weixin_29227425的博客 626

Android经典技术相关文章集合(会不断更新)

Volley系列====================== [Android] Volley源码分析(一)体系结构 [Android] Volley源码分析(二)Cache [Android]Volley源码分析(叁)Network [Android]Volley源码分析(肆)应用   [Android] Volley源码分析(五)答疑

林易木创建者的博客 500

手把手教你学GPU的KMD专栏--3.1 设备初始化流程深度解析

本文深入解析了KMD(内核模式驱动)设备初始化流程,这是GPU驱动开发最基础且关键的环节。初始化流程包括6个核心阶段:KMD模块加载、PCIe设备探测匹配、GPU硬件初始化、显存分配映射、中断系统配置和设备注册。每个阶段都有详细步骤解析,涉及关键数据结构和错误处理机制。文章还分析了常见问题(驱动加载失败、显存分配失败、中断配置失败)的解决方案,并指出未来趋势将向动态初始化、安全增强和AI优化方向发展。正确高效的初始化流程是确保GPU被操作系统安全使用的前提,也是后续内存管理、任务调度等功能的基础。

MHD0815的博客 262

YOLOv12改进策略【卷积层】| 引入注意力卷积模块RFAConv,关注感受野空间特征 助力yolov12精度提升

RFAConv:创新空间注意力和标准卷积运算感受野空间特征是针对卷积核设计的,根据卷积核大小动态生成。以3×3卷积核为例,它由非重叠滑动窗口组成,每个窗口代表一个感受野滑块。

Limiiiing的博客 685

Android相关技术知识点

该文章专门收集Android相关技术知识点,帮助同志们快速找到自己想要的内容,节约大家的查询、学习时间。本文章只提供知识点连接,不会讲解知识;内容的来源来至于庞大的网络,会引用各大朋友们、博主们的文章,在此本人代表各大学习者感谢你们的无私奉献。本文章会不断更新,当鄙人看到有值得学习的内容时就会引用过来供同学们学习,同时也希望同志们在看到经典的内容也能向大家分享(可在评论、或者联系鄙人),再次代表广大

林易木创建者的专栏 434

SAP-ABAP:字符与数值类型转换详细指南

SAP-ABAP:字符与数值类型转换详细指南

baidu_35680696的博客 1487

MultiImageView九宫格图片显示

这是一个很方便的自定义图片显示控件,只需要把图片的Url放在数组传给控件就可。加载逻辑和显示逻辑都做了相应的封装。 看看例子。 直接粘出控件源码 package com.raspberry.library.view; import android.content.Context; import android.util.AttributeSet; import android.vi

SingleShu的博客 5079

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

Android 宫格图控件MultiImageView

先上图: 实现逻辑 首先创建图片实体类 public class PhotoInfo { public String url; public int w; public int h; public String getUrl() { return url; } public void setUrl(St...

little762的博客 1351

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

MultiImageView+PhotoView+ViewPager图片预览

效果截图 PhotoView PhotoView是一个github上的一个开源项目。 将下面加入到根build.gradle文件中 allprojects { repositories { maven { url "https://jitpack.io" } } } 然后,加入库到你的模块build.gradle dependencies { imp...

It一zhai男 551

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

推荐个通用的多图片上传插件 multiimage。

。 其实是KindEditor里面带的一个插件,multiimage,实用方法也非常简单。 1。页面引用相应的样式表文件和js代码,中文语言包。 <link rel="stylesheet" type="text/css" href=" @Url.Content("~/Scripts/KindEditor/themes/default/default.css")" /> ...

weixin_30457551的博客 598

android 添加多个图片,java – Android – 将多个图像组合成一个ImageView

我正在寻找帮助开发(或库),这可以让我将多个图像合并到一个imageview.我的应用程序将用户之间的交互分组在一起,而不是单独显示它们,因此我想合并它们的所有化身,以便一个适配器单元可视化“组”.一个很好的例子是在facebook.com的聊天中完成的:我的问题是,如何在Android / Java中提供此功能?据推测,它可以在1到4之间的图像.请让我知道你可以给出的任何建议:)解决方法:您可以...

weixin_32393875的博客 1021

一个比较强大的提供各种形状的ImageView

github上比较老的项目了,但是还是比较好用的。 各种形状总有一个满足你。 在自己的项目中使用,最好不要将所有的类都导入进来,取自己需要的就可以了。 <com.github.siyamed.shapeimageview.BubbleImageView android:id="@+id/image" android:layout_width="

gundumw100的专栏 1754

仿QQ空间动态显示图片说说

我这里用了别人的封装的东西,直接附上代码,方便下次直接使用,注意:这里最多只能放置3张图片! 从布局文件开始,先是动态列表Item的视图 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"

qq_34949557的博客 1212

Android 仿朋友圈之九宫格多图显示(二)

一个仿微信朋友圈和QQ空间的九宫格图片展示自定义控件效果: 一.介绍: 1、当只有1张图时,可以自己定制图片宽高,也可以使用默认九宫格的宽高; 2、当只有4张图时,以2*2的方式显示; 3、除以上两种情况下,都是按照3列方式显示,但这时有一些细节: a、如果只有9张图,当然是以3*3的方式显示; b、如果超过9张图,可...

shenggaofei的博客 6866
上一篇: android TCP 和 UDP总结
下一篇: 生命周期——Activity和Fragment
ttdevs
博客等级 码龄15年 388粉丝 91原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值