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


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

    从最開始的白页面等待,到后来的进度条告知用户。到如今的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("
    "+height+","+width);  
    
    
    
    
    //-----------------------------------------------方法二  
    ViewTreeObserver vto = imageView.getViewTreeObserver();  
    vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {  
        public boolean onPreDraw() {  
            int height = imageView.getMeasuredHeight();  
            int width = imageView.getMeasuredWidth();  
            LogUtils.d("
    "+height+","+width);  
            return true;  
        }  
    });  
    //-----------------------------------------------方法三     
    ViewTreeObserver vto2 = imageView.getViewTreeObserver();    
    vto2.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {  
        @Override    
        public void onGlobalLayout() {  
            imageView.getViewTreeObserver().removeGlobalOnLayoutListener(this);    
            LogUtils.d("
    
    "+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

    记得点个赞哦!!

    这里写图片描写叙述

  • 相关阅读:
    spring4之依赖注入的三种方式
    Hibernate之总结
    Hibernate之dynamic-update
    ThinkPhp调用webservice
    Robot Framework:Web自动化之-元素处理
    Robot Framework:Web自动化之-元素定位
    RobotFramework:python+robotframework+selenium2library测试环境部署说明文档
    Robot Framework:Httplibrary库
    URL备忘
    Windows:CMD命令备忘
  • 原文地址:https://www.cnblogs.com/slgkaifa/p/7300016.html
Copyright © 2020-2023  润新知