转载请注明出处:王亟亟的大牛之路

从最開始的白页面等待,到后来的进度条告知用户。到如今的WebBO/微信这样的先下缩略图点击才又一次下大图的方式,我们开发人员对用户感知的注意度越来越高。昨天刷微博的时候看到他们是用一个灰色转圈圈的实现,所以就萌生的今天要做的内容的启示(我是在不知道给这样的实现取什么名字。就写了一大堆。感觉在哪见过相似的可是,忘了出自于哪了)

先上下效果:

GIF软件继续把我的效果给吃了。。大家能够自己跑一下,看效果。


HOW to do?

1.我们的图片来自于网络,假设是本地,也不须要这一系列的操作了,差点儿是瞬间。那么我们的下载过程中的进度通知得一直刷新。
2.我们得让图片一直在更新UI至少产生差异性,不然用户不知道这是干什么

带着这2个问题,我们来说一下,首先是下载,用Volley,和api自带的一些库都能够实现。往里面加回调传进度出来即可了,这里楼主用的是git大牛的https://github.com/hongyangAndroid/okhttp-utils

对okhttp的封装简单易用。

第二个问题就是怎么实现,我们有了进度。那就是画。这边用的是源生的bitmap canvas paint三剑客,详细怎么做。等会代码会贴。


包结构:

实现类:MainActivity

父类:Father(提供抽象方法)

图片数据源:Config(正常图片太小了,强行 试了好多次)

public class MainActivity extends Father {
private Button btn;
private ImageView imageView;
private Paint paint;
private Canvas canvas;
private Bitmap bitmap;
private String fileUrl;
private float imageWidth, imageHeight;
private Paint paint2; @Override
public int getLayout() {
return R.layout.activity_main;
} @Override
public void init() {
btn=(Button)findViewById(R.id.btn);
imageView = (ImageView) findViewById(R.id.imageView);
imageWidth = (int) getResources().getDimension(R.dimen.image_width);
imageHeight = (int) getResources().getDimension(R.dimen.image_height);
} @Override
public void setClick() {
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
fileUrl = Environment.getExternalStorageDirectory().getAbsolutePath() + "/wjj/" + "meizi.jpg"; if (checkFile(fileUrl)) {
LogUtils.d("--->onResume checkFile==true");
imageView.setImageBitmap(BitmapFactory.decodeFile(fileUrl));
Toast.makeText(MainActivity.this,"图片已经存在于SD卡内",Toast.LENGTH_SHORT).show();
} else {
LogUtils.d("--->onResume checkFile==false");
DownLoadImage(ConFig.ImageUrl);
}
}
});
} @Override
public void Logic() {
LogUtils.d("--->MainActivity Logic getWidth " + imageWidth + " getHeight " + imageHeight);
if (bitmap == null) {
bitmap = Bitmap.createBitmap((int) imageWidth,
(int) imageHeight, Bitmap.Config.ARGB_8888);
canvas = new Canvas(bitmap);
canvas.drawColor(getResources().getColor(R.color.Gray));
}
paint = new Paint();
paint.setColor(getResources().getColor(R.color.White));
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); paint2 = new Paint(); paint2.setColor(getResources().getColor(R.color.Gray));
paint2.setTextSize(90);
paint2.setTextAlign(Paint.Align.CENTER);
imageView.setImageBitmap(bitmap);
} @Override
protected void onResume() {
super.onResume();
} private void DownLoadImage(String ImageUrl) {
OkHttpUtils
.get()
.url(ImageUrl)
.build()
.execute(new FileCallBack(Environment.getExternalStorageDirectory().getAbsolutePath() + "/wjj/", "meizi.jpg") { @Override
public void inProgress(float progress) {
LogUtils.d((int) (100 * progress) + "高度等于 " + imageHeight * progress);
canvas.drawRect(0, 0, imageWidth, imageHeight * progress, paint);
canvas.drawText((int) (100 * progress) + "%", imageWidth / 2, imageHeight / 2 - 200, paint2); imageView.setImageBitmap(bitmap);
} @Override
public void onError(Request request, Exception e) {
LogUtils.e("onError :" + e.getMessage());
} @Override
public void onResponse(File file) {
LogUtils.d("onResponse :" + file.getAbsolutePath());
imageView.setImageBitmap(BitmapFactory.decodeFile(file.getAbsolutePath()));
}
});
} /**
* 控件的高度
*
* @param view 控件View
* @return 返回控件的高度
*/
public static int getHeight(View view) {
if (view == null) {
throw new IllegalArgumentException("view is null");
} view.measure(0, 0);
return view.getMeasuredHeight();
} /**
* 获取控件的宽度
*
* @param view 控件
* @return 返回控件的宽度
*/
public static int getWidth(View view) {
if (view == null) {
throw new IllegalArgumentException("view is null");
} view.measure(0, 0);
return view.getMeasuredWidth();
} private boolean checkFile(String checkFile) {
File mFile = new File(fileUrl);
//若该文件存在
if (mFile.exists()) {
return true;
} else {
return false;
}
}
}

代码都在上面了。来说一下里面的坑。

坑1

image.getHeight()和image.getWidth,粗略看来是不是假设我们设置的不是wrap_content那么一定能获取到參数?

事实是NO,不管怎么整他都是0,那怎么获取呢?方法例如以下!

//------------------------------------------------方法一
int w = View.MeasureSpec.makeMeasureSpec(0,View.MeasureSpec.UNSPECIFIED);
int h = View.MeasureSpec.makeMeasureSpec(0,View.MeasureSpec.UNSPECIFIED);
imageView.measure(w, h);
int height =imageView.getMeasuredHeight();
int width =imageView.getMeasuredWidth();
LogUtils.d("\n"+height+","+width); //-----------------------------------------------方法二
ViewTreeObserver vto = imageView.getViewTreeObserver();
vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
public boolean onPreDraw() {
int height = imageView.getMeasuredHeight();
int width = imageView.getMeasuredWidth();
LogUtils.d("\n"+height+","+width);
return true;
}
});
//-----------------------------------------------方法三
ViewTreeObserver vto2 = imageView.getViewTreeObserver();
vto2.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
imageView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
LogUtils.d("\n\n"+imageView.getHeight()+","+imageView.getWidth());
}
});

这些都能获取到參数。可是仅仅要离开那行代码。东西就没了还是0 .WHY 什么鬼。?

onCreate方法运行完了,我们定义的控件才会被度量(measure),所以我们在onCreate方法里面通过view.getHeight()获取控件的高度或者宽度肯定是0,由于它自己还没有被度量,也就是说他自己都不知道自己有多高,而你这时候去获取它的尺寸,是不行的.

那有两个办法,1.我去设一张图片。然后图片的大小就是我控件的大小。

2.也就是我用的方法,人工控件的大小。脑洞来源于:http://stackoverflow.com/questions/19271609/imageview-getwidth-returns-0

文章中是这样

  imageWidth = (int) getResources().getDimension(R.dimen.image_width);
imageHeight = (int) getResources().getDimension(R.dimen.image_height);

那么有人要问了,我实际场景下也设定死吗?

我们的业务层不可能整一个页面都是一张图。那么UI给与我们界面定稿的时候总有一个相对大小,而我们的控件大小能够在适配的大小区间里来游走(反正在现实场景时,这图片总是点击放大才去载入。而那时候不已经全屏看了?你还在意控件大小么?)

所以。这个实现的使用场景就是在看大图时(一定得大。不然怎么都是瞬间),才有他的使用价值。


小解释:

代码中的paint 是用来画背景的 paint2 是用来画进度的文字的。

文字位置是 x=宽/2 y=长/2

图片更新方式:总长/100=每1%的Y向长度,然后每次更新的进度数*这个1%Y长度即可。

文章中的图片最后还是存于SD卡里的,假设想直接下载完Set到ImageView上的话就别存把流转一下就好了。

源代码地址:https://github.com/ddwhan0123/BlogSample/tree/master/ImageLoadingAnim

记得点个赞哦!!

改善用户体验,用图片的自身变化以及进度通知摆脱传统的进度条,okhttp,Canvas,Paint实现的更多相关文章

  1. 改善用户体验之wordpress添加图片弹出层效果 (插件 FancyBox)

    下面说说在改善用户体验之wordpress添加图片弹出层效果.效果图如下:   像这篇文章如何在百度搜索结果中显示网站站点logo? 文章内有添加图片,没加插件之前用户点击图片时,是直接_black打 ...

  2. paip.提升用户体验--radio图片选择器 easyui 实现..

    #paip.提升用户体验--radio图片选择器 easyui 实现.. =================================== ##原因... ------------------- ...

  3. 自己定义progressdialog,改善用户体验

    自己定义progressdialog,改善用户体验 效果图: 详细实现方式: 1.定义Dialog的Layout布局 2.设置动画anim 3.创建自己定义dialog的样式 4.创建共同拥有方法来控 ...

  4. 自定义progressdialog,改善用户体验

    自定义progressdialog,改善用户体验

  5. 提升网站用户体验—WebP 图片的高效使用

    一.WebP 的由来 现代图像压缩技术对我们的生活方式影响很大.数码相机能将上千张高质量图片存储到一张内存卡里.智能手机可以与邻近设备快速分享高分辨率的图片.网站与手机等移动设备能快速展示各种富媒体. ...

  6. 改善用户体验 Web前端优化策略总结

    前端是庞大的,包括HTML.CSS.Javascript.Image.Flash等等各种各样的资源.前端优化是复杂的,针对方方面面的资源都有不同的方式.那么,前端优化的目的是什么? 1. 从用户角度而 ...

  7. 使用JS&jQuery改善用户体验

    第一章  JavaScript基本语法 一.运算符 运算符就是完成操作的一系列符号,它有七类: 赋值运算符(=,+=,-=,*=,/=,%=,<<=,>>=,|=,&= ...

  8. 【读书笔记】iOS-反溃网络信息改善用户体验

    一,iOS6表视图刷新控件的使用. 二,使用等待指示器控件. 三,使用网络等待指示器. 四,使用MBProgressHUD等待指示器. 参考资料:<iOS网络编程与云端应用-最佳实践>

  9. web设计经验<二>设计华丽的用户体验的6个热门技巧

    你是否曾经下载了一个应用,却发现它“很难使用”?对于大多数智能手机用户来说,答案是肯定的. 有趣的是,每四个手机应用中就有一个应用在下载后被“打入冷宫”. 如果一个应用能够吸引一个人下载并且打开它,但 ...

随机推荐

  1. MNI模板和Talairach 模板的对比

    The MNI brain and the Talairach atlas SPM 96 and later use standard brains from the Montreal Neurolo ...

  2. 把Jar文件转成exe安装文件

    1.你要清楚的目标文件是32位还是64位的,如果生成的是32位,你就要使用32位的jre,如果生成的是64位,就要使用64位的jre. 图 1 在圆圈位置进行32bit或64bit的选择.因为我要创建 ...

  3. jquery省市选择案例

    1.代码实例 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UT ...

  4. [Android Pro] Android系统手机端抓包方法 和 通过File查看应用程序流量

    adb shellcat proc/uid_stat/%uid%/tcp_snd  proc/uid_stat/%uid%/tcp_rcv ------------------------------ ...

  5. Python 字符串前面加'r'

    在Python的string前面加上‘r’, 是为了告诉编译器这个string是个raw string,不要转意backslash '\' . 例如,\n 在raw string中,是两个字符,\和n ...

  6. Django admin管理

    admin的配置 admin是django强大功能之一,它能共从数据库中读取数据,呈现在页面中,进行管理.默认情况下,它的功能已经非常强大,如果你不需要复杂的功能,它已经够用,但是有时候,一些特殊的功 ...

  7. 如何在SharePoint的列表中使用通配符来filter出ListItem?

    一个朋友问我这样一个问题, 他想要快速从SharePoint的文档库中filter出来名字中先带有一个Q, 接着一些其他的字符, 后面再跟着有一个数字20这样的文件.   第一个想法就是修改Share ...

  8. .net使用自定义类属性

    .net中可以使用Type.GetCustomAttributes获取类上的自定义属性,可以使用PropertyInfo.GetCustomAttributes获取属性信息上的自定义属性. 下面以定义 ...

  9. Error: Cannot find module 'express' 之 解决方案

    出现如题错误,是因为执行了#npm install -g express的缘故,express没有被写到package.json里面去. 解决也好办,在程序目录下执行#npm install expr ...

  10. C++ 11 - STL - 函数对象(Function Object) (中)

    我们再来看一个复杂的例子 需求: 我们需要对集合内每个元素加上一个特定的值 代码如下: AddInt.h class AddInt { private: int theValue; // the va ...