消息流形式的图文混排,最常见的就是微博类应用了,一般包括几个部分:文字和若干张图片;点击条目查看详情;点击某一张图片,滑动查看所有大图;查看原图等。看上去好像东西也不少,其实实现起来极其简单,今天就来记录一下其具体的实现方式。
##图文列表
文字部分没什么好讲的,就是一个 TextView ,直接设置文字即可。重点是图片,图片数量是不确定的,一行一般显示三四个,显示多行,这里基本所有人都能想到用 GridView ,RecyclerView/ListView 里嵌套 GridView ,但是众所周知,这样做其实是不符合 Android 开发规范的,类似的还有 ScrollView 嵌套 ListView 等,虽然网上有很多教程该怎么测量高度,怎么禁止 GridView 或者 ListView 滑动,即使能够解决卡顿问题,可它依旧是不符合规范的。尤其是今年已经是 2015 年,一定不要再用 ListView 取嵌套 GridView 了。
我们可以这样做,因为图片数量不确定,那动态添加图片就可以了。这时,流式布局就应运而生了,具体怎么打造一个流式布局,可以看慕课网的视频打造Android流式布局和热门标签,讲的非常好,这里我们可以直接拿来用。使用 RecyclerView ,在 adapter 里使用 FlowLayout 添加图片即可。
1 | if (!TextUtils.isEmpty(images)) { |
如果使用 Fresco 加载图片,需要初始化 Fresco.initialize(this); 这样,就可以列表展示图文了。当然,一定不能忘记加上联网权限,我发现一个非常诡异的问题,可能是 Android Studio 的 bug 吧。最新的 AS 在没添加需要的权限的时候,使用一些框架,居然没提示,从昨天下午到今天上午加载图片,换了 Picasso,Fresco,ImageLoader,统统不行,最后实在没法,自己手动处理成流再转成 Bitmap 加载,才发现居然是网络权限没加。而之前换了那么多框架,居然一个都没报错,日志也没任何提示。
##ViewPager 展示大图
这里要用到 PhotoView 这个开源库,可以双击放大,初始化 PageAdapter 的时候,添加跟图片地址数量相等的 PhotoView 到 ViewPager 即可。
1 | public ImagePageAdapter(List<String> imageList) { |
然后就是加载大图片,重写 instantiateItem 方法即可。
1 | public Object instantiateItem(View arg0, int arg1) { |
接着重写完 PagerAdapter 其他必须要重写的方法,就完成了大图片的加载。这里为什么不是加载原图?当然是为了避免 OOM ,ViewPager 的预加载不仅会很慢,而且还很卡,甚至会 OOM ,因此在这里图片上加一个点击查看原图的按钮,在新的界面加载原图。
##加载原图
这里就没什么好讲的了,同样使用 Picasso ,只不过传入的参数不一样。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28if (!TextUtils.isEmpty(imageUrl)) {
photoView.setMaximumScale(2.5f);
photoView.setMinimumScale(1f);
photoView.setMediumScale(1.5f);
photoView.setScale(1.0f, true);
if (mDialog == null) {
mDialog = CustomProgressDialog.createDialog(ImageOrginActivity.this, "");
mDialog.show();
}
Log.e("imageUrl", imageUrl);
Picasso.with(ImageOrginActivity.this).load(imageUrl).into(photoView, new Callback() {
@Override
public void onSuccess() {
if (mDialog != null) {
mDialog.dismiss();
}
}
@Override
public void onError() {
if (mDialog != null) {
mDialog.dismiss();
}
}
});
}
再增加一个轻触退出浏览的方法:1
2
3
4
5
6photoView.setOnViewTapListener(new PhotoViewAttacher.OnViewTapListener() {
@Override
public void onViewTap(View view, float x, float y) {
finish();
}
});
然后是长按保存到本地文件夹:
1 | photoView.setOnLongClickListener(new View.OnLongClickListener() { |
至此,一个相对完善,实现起来也极其简单的图文信息流就完成了。具体的代码放在这里PhotoListDemo ,使用了 Picasso PhotoView Fresco 这三个库,感谢作者。