Android仿Instagram图片加载策略(模糊图片占位+下载进度条)
来源:互联网 发布:php反射机制和作用 编辑:程序博客网 时间:2024/05/18 01:56
前言:
Instagram的Android客户端用户体验很棒,我分析了一下大概有这3个要点:
1、屏幕外图片预加载
意思是如果你在注视屏幕中显示的一张图片,但同时屏幕下方你没有拉出来的图片已经在后台下载,此功能我使用RecyclerView的预加载功能很好的模拟出来了。
2、模糊图占位
首先在你获取别人动态的时候,那个人的用户名,头像,图片url和图片的缩略图都同时返回回来,并在屏幕上显示缩略图,而真实的图片是异步下载的,在下载结束之后替换之前的模糊图
3、下载进度提示
Instagram有一个白色的进度条,可以提示当前下载进度的百分比。
对于这三个主要功能,我已经全部模拟出来了相似的效果,本文是在基于我之前两篇博客的基础上,重点描述模糊占位图的实现过程,前两篇博客请看-->《使用okhttp3做Android图片框架Picasso的下载器和缓存器》《为Android图片加载添加百分比进度条(Picasso+Okhttp3)》
实现效果:
项目github地址:https://github.com/AlexZhuo/AlxPicassoProgress
实现思路:
首先第一点是图片的url信息,用户信息,评论信息等等要和缩略图同步获取,实现起来就是服务器在发挥JSON字符串数据的时候,将jpg格式的缩略图(我这里分辨率为25x25)使用Base64压缩成可读字符串放在JSON的某个字段中,相当于把一个图片塞在字符串中发过来,客户端收到该Base64编码的缩略图后进行解码,并在主线程中将该缩略图进行放大+高斯模糊,放在ImageView中显示,然后Piasso在下载完成之后将真实的图片替换掉原来放进去的bitmap,完成效果的显示。
为此,服务器端应该做的准备是:
1、提前将图片裁剪成等比例的缩略图,并使用Base64压缩,存放到数据库中
2、在发送JSON字符串时,将上面的Base64字符串同图片真实的URL一同发送
3、在使用url请求真正的图片时,Http的响应头应添加Content-Length字段提示这个图片的完整大小,以便计算下载百分比
Android端只需添加Picasso2和OkHttp3两个框架和一个自定义进度条控件即可完成这个效果
注意:如果直接将25x25的缩略图放置到ImageView中,理论上也能实现效果,但是模糊出来非常难看,我的方法是先将25x25的缩略图变成300x300的大图,然后高斯模糊这一章300x300的大图,模糊半径尽量的大。在我上面的demo中,虽然已经实现了高斯模糊,但是使用的是一个普通的模糊算法,模糊出来以后没有Ins那么柔和,如果有机会我会更新一下那个模糊算法。
下面贴一些主要代码,其他代码请到github上查看
将Base64字符转转换为Bitmap的方法:
public static Bitmap base64ToBitmap(String sourceBase64){ if(TextUtils.isEmpty(sourceBase64)) sourceBase64 = "/9j/4AAQSkZJRgABAQEAYABgAAD//gA7Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcgSlBFRyB2ODApLCBxdWFsaXR5ID0gOTAK/9sAQwADAgIDAgIDAwMDBAMDBAUIBQUEBAUKBwcGCAwKDAwLCgsLDQ4SEA0OEQ4LCxAWEBETFBUVFQwPFxgWFBgSFBUU/9sAQwEDBAQFBAUJBQUJFA0LDRQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQU/8AAEQgAMgAyAwEiAAIRAQMRAf/EAB8AAAEFAQEBAQEBAAAAAAAAAAABAgMEBQYHCAkKC//EALUQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJD...省略不写"; byte[] sourceBytes = Base64.decode(sourceBase64.getBytes(),Base64.DEFAULT); if(sourceBytes == null || sourceBytes.length == 0)return null; Bitmap bitmap = BitmapFactory.decodeByteArray(sourceBytes,0,sourceBytes.length); if(bitmap == null)return null; if(bitmap.getHeight()<2)return null; return bitmap; }这里提示一下,一般JPG使用Base64压缩后都会以/9j/开头,用这个可以判断一下有没有转换正确,Base64压缩完后会出现很多'/'字符,要注意不要写成‘\\/’的形式,否则会转换Bitmap出错
将小Bitmap转换为大Bitmap的方法:
/** * 传入一个bitmap,根据传入比例进行大小缩放 * @param bitmap * @param widthRatio 宽度比例,缩小就比1小,放大就比1大 * @param heightRatio * @return */ public static Bitmap scaleBitmap(Bitmap bitmap, float widthRatio, float heightRatio) { Matrix matrix = new Matrix(); matrix.postScale(widthRatio,heightRatio); return Bitmap.createBitmap(bitmap,0,0,bitmap.getWidth(),bitmap.getHeight(),matrix,true); }
高斯模糊的方法:
if (Build.VERSION.SDK_INT > 16) { Bitmap bitmap = sentBitmap.copy(sentBitmap.getConfig(), true); final RenderScript rs = RenderScript.create(context); final Allocation input = Allocation.createFromBitmap(rs, sentBitmap, Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT); final Allocation output = Allocation.createTyped(rs, input.getType()); final ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs)); script.setRadius(radius /* e.g. 3.f */); script.setInput(input); script.forEach(output); output.copyTo(bitmap); return bitmap; }
上面这个是Android原生支持的高斯算法,底层采用c实现,效率比较高,如果SDK版本低于17,那么去github上看if之外的方法,是一个Java实现的模糊算法,用于低版本的机器,我在demo中使用的模糊半径是8。
屏幕外图片预加载方法:
本demo为了效果明显,并没有添加预加载的功能,我在实际的项目中使用的是RecyclerView做为容器,而RecyclerView添加预加载的方法如下:
首先需要自定义一个LayoutManager
mport android.content.Context;import android.support.v7.widget.LinearLayoutManager;import android.support.v7.widget.RecyclerView;/** * Created by Alex on 2016/9/18. * 用于预加载recyclerView下一张卡的layoutmanager */public class AlxPreloadLinearManager extends LinearLayoutManager{ private static final int DEFAULT_EXTRA_LAYOUT_SPACE = 1280; private int extraLayoutSpace = DEFAULT_EXTRA_LAYOUT_SPACE; public AlxPreloadLinearManager(Context context) { super(context); } public AlxPreloadLinearManager(Context context, int extraLayoutSpace) { super(context); this.extraLayoutSpace = extraLayoutSpace; } public AlxPreloadLinearManager(Context context, int orientation, boolean reverseLayout) { super(context, orientation, reverseLayout); } public void setExtraLayoutSpace(int extraLayoutSpace) { this.extraLayoutSpace = extraLayoutSpace; } @Override protected int getExtraLayoutSpace(RecyclerView.State state) { if (extraLayoutSpace > 0) { return extraLayoutSpace; } return DEFAULT_EXTRA_LAYOUT_SPACE; }}
LayoutManager layoutManager = new AlxPreloadLinearManager(context);int screenHeigth =getScreenHeigth();if(screenHeigth > 500)((AlxPreloadLinearManager)layoutManager).setExtraLayoutSpace(screenHeight);//设置预加载下一张卡的模式layoutManager.setOrientation(LinearLayoutManager.VERTICAL);recyclerView.setLayoutManager(layoutManager);
调用方法:
只需一行即可:如果想添加模糊图占位功能
AlxPicassoUtils.displayImageProgress(url,imageView,progressWheel,textView,base64Str);
参数分别为:图片url地址,ImageView控件,圆形进度条控件,进度显示TextView,经过Base64压缩的图片缩略图
AlxPicassoUtils.displayImageProgress(url,imageView,progressWheel,textView);
参数分别为:图片url地址,ImageView控件,圆形进度条控件,进度显示TextView
- Android仿Instagram图片加载策略(模糊图片占位+下载进度条)
- android图片滤镜(仿Instagram滤镜)
- android 图片加载进度条
- 仿UC浏览器图片加载进度条
- Android笔记之(图片高斯+Glide实现微信图片加载策略+仿微信进度条)
- android 下载instagram动态中图片的demo
- 圆形进度条(包括仿QQ图片加载进度图)
- Android之加载图片时自定义进度条
- Android之加载图片时自定义进度条
- Android有进度条异步任务下载图片
- Android AsyncTask下载图片和ProgressBar进度条
- 设置图片加载进度条
- 仿qq加载图片
- android有进度条的下载图片并且显示图片
- android-下载保存网络图片并显示下载进度条
- 关于ImageLoader加载图片模糊
- Android 模糊图片技术
- android图片模糊处理
- 洛谷 1313
- 建立一个Odoo Module (四)- Computed fields、Model constriants
- 面向对象程序设计上机练习十一(运算符重载)
- iOS开发之直播App流程介绍
- win7 caffe使用笔记——solver求解器参数以及损失函数的使用
- Android仿Instagram图片加载策略(模糊图片占位+下载进度条)
- Android Preference置灰显示
- Android应用开发中Activity类的用法
- 装饰者模式
- Eclipse中下载SVN插件以及SVN的实际操作
- 代码结构优化工作中的细节
- App优化之提升你的App启动速度
- C语言模拟学生学籍管理系统
- 4.22