Android -- 真正的 高仿微信 打开网页的进度条效果

(本博客为原创,http://home.cnblogs.com/u/linguanh/)

目录:

  一,为什么说是真正的高仿?

  二,为什么要搞缓慢效果?

  三,我的实现思路

  四,代码,内含注释

  五,使用方法与截图

  六,完整项目

一,为什么说是真正的高仿?

  阐述这个问题前,先说下之前网上的,各位可以复制这段字,去百度一下  "仿微信打开网页的进度条效果" ,你会看到有很多类似的文章,不过他们有个共同点,就是实现方法都是一样的,而且,都忽略了微信加载网页时,进度条的缓慢动画效果,它不是生硬地一滑而过,而是用户体验很好,有个速度的变化,由慢到快的效果,语言难于描述,相信各位都有下载微信,可以随便打开个公众号的文章看看效果。

  好了,上面说到,之前网上的方法都是都忽略了微信加载网页时,进度条的缓慢动画效果,实现代码也是千篇一律,如下:

/** 先实例化个进度条 */
ProgressBar mProgressBar = (ProgressBar) findViewById(R.id.ProgressBar);

/** 再实例化个 webView */
WebView webView = (WebView) findViewById(R.id.webview);

/** 然后就直接在 webClient 回调函数里面set 进度,这样的做法是生硬的效果 */
webView.setWebChromeClient(new WebChromeClient(){

     @Override
     public void onProgressChanged(WebView view, int newProgress) {
            super.onProgressChanged(view, newProgress);
            mProgressBar.setProgress(newProgress);
      }

});

/** 其他是颜色样式等,不是重点 */
.....

  我以为是 ProgressBar 控件可能自身提供了动画的 API,可惜,没有,故自己动手写了这个,你如果找到了,告诉下我。

二,为什么要搞缓慢效果?

  对,为什么要这么麻烦,你如果要搞个网页加载进度条,上面的代码不过 10 行,妥妥地实现了。因为用户体验,我不是产品经理,我是个程序员,而且这个效果也不是有谁叫我这样去做的,我就是看着别扭,微信的成功,我相信不仅仅是个朋友圈那么简单!

  程序员应该具备注重用户体验的想法。

三,我的实现思路

  方法很多,这话我说在前面,我的这种肯定不是最好的,但不失一用或改进。

  主要是通过改变 view 的 LayoutParam 来实现有不同速度的移动效果,在每一次的进度段,例如第一次0~24,第二次24~56,这就是两个进度段,这两个进度段,具有不同的速度,这个需要计算出来,先根据手机屏幕宽度和 0~100 的进度数值来等比计算出实际的宽度,再计算出移动的速度,计算出来每个进度段的数据后,讲它们放进一个列表容器里面,然后通过一个 handler 来循环提取同期数据,不断地发消息,不停地 setLayoutParam。在达到 100 后,就证明加载完毕。

  在这个过程需要处理计算的误差,例如第一个加载 20,第二次24,24-20 = 4,4/100,程序里面是 0 ,如果计算速度的话,就会差生0,所以要稍微加个 if 判断。

四,代码,内涵注释

  核心类:

package com.slowlyprogressbar;

import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.RelativeLayout;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by 林冠宏 on 2016/7/11.
 *
 * 真正的仿微信网页打开的进度条
 *
 * 下面的所有属性都可以自己采用 get set 来自定义
 *
 */

public class SlowlyProgressBar {

    private static final int StartAnimation = 0x12;

    private Handler handler;
    private View view;

    /** 当前的位移距离和速度 */
    private int thisWidth = 0;
    private int thisSpeed = 0;

    private int progress = 0;  /** 当前的进度长度 */
    private int record = 0;    /** 移动单位 */
    private int width = 10;    /** 10dp each time */
    private int height = 3;    /** 3dp */

    private boolean isStart = false;

    private int phoneWidth = 0; /** 屏幕宽度 */
    private int i = 0;

    /** 每次的移动记录容器,位移对应每帧时间 */
    private List<Integer> progressQuery = new ArrayList<>();
    private List<Integer> speedQuery    = new ArrayList<>();

    public SlowlyProgressBar(View view, int phoneWidth) {
        initHandler();
        this.phoneWidth = phoneWidth;
        this.view = view;
    }

    /** 善后工作,释放引用的持有,方能 gc 生效 */
    public void destroy(){
        if(progressQuery!=null){
            progressQuery.clear();
            progressQuery = null;
        }
        if(speedQuery!=null){
            speedQuery.clear();
            speedQuery = null;
        }
        view = null;
        handler.removeCallbacksAndMessages(null);
        handler = null;
    }

    public void setProgress(int progress){
        if(progress>100 || progress <= 0){ /** 不能超过100 */
            return;
        }
        /** 每次传入的 width 应该是包含之前的数值,所以下面要减去 */
        /** 下面记得转化比例,公式 (屏幕宽度 * progress / 100) */
        this.width = (progress * phoneWidth)/100;

        /** lp.width 总是获取前一次的 大小 */
        /** 移动 100px 时的速度一次倍率 是 2 */
        int size = progressQuery.size();
        if(size != 0){
            size = progressQuery.get(size-1);
        }
        Log.d("zzzzz","width - size = "+(width - size));
        /** 计算倍率,2/100 = x/width */
        int distance = width - size;
        int speedTime;
        if(distance<=100){
            speedTime = 2;
        }else{
            speedTime = (int) ((2 * distance)/100.0);
        }
        /** 添加 */
        progressQuery.add(this.width);
        speedQuery.add(speedTime);
        /** 开始 */
        if(!isStart){
            isStart = true;
            handler.sendEmptyMessage(StartAnimation);
        }
    }

    public SlowlyProgressBar setViewHeight(int height){
        this.height = height;
        return this;
    }

    private void initHandler(){
        handler = new Handler(){
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                switch (msg.what){
                    case StartAnimation:
                        /** 提取队列信息 */
                        if(progress >= thisWidth){ /** 如果已经跑完,那么移出 */
                            if(progressQuery.size() == i){
                                Log.d("zzzzz","break");
                                if(progress >= 100){ /** 全部走完,隐藏进度条 */
                                    view.setVisibility(View.INVISIBLE);
                                }
                                isStart = false;
                                break;
                            }
                            Log.d("zzzzz", "size is " + progressQuery.size());
                            thisWidth = progressQuery.get(i);
                            thisSpeed = speedQuery.get(i);
                            i ++;
                        }
                        move(thisSpeed,view.getLayoutParams().width);
                        Log.d("zzzzz", "send 100 "+thisSpeed);
                        /** 发信息的延时长度并不会影响速度 */
                        handler.sendEmptyMessageDelayed(StartAnimation,1);
                        break;
                }
            }
        };
    }

    /** 移动 */
    private void move(int speedTime,int lastWidth){
        if(speedTime > 9){
            speedTime = 9; /** 控制最大倍率 */
        }
        /** 乘 3 是纠正误差 */
        progress = (record * speedTime);
        /** 纠正 */
        if(progress >= lastWidth){
            view.setLayoutParams(new RelativeLayout.LayoutParams(progress,height*3));
        }else{
            Log.d("zzzzz","hit "+progress+"---"+lastWidth);
        }
        record ++;
    }
}

五,使用方法与截图

  超简单引入,view 可以是随便一个,例如 TextView,给它一个 background 就行了,就有颜色了。

public class MainActivity extends AppCompatActivity {

    private SlowlyProgressBar slowlyProgressBar;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        slowlyProgressBar =
                new SlowlyProgressBar
                        (
                                findViewById(R.id.p),
                                getWindowManager().getDefaultDisplay().getWidth()
                        )
                .setViewHeight(3);

        WebView webView = (WebView) findViewById(R.id.webview);
        webView.setWebChromeClient(new WebChromeClient(){

            @Override
            public void onProgressChanged(WebView view, int newProgress) {
                super.onProgressChanged(view, newProgress);
                slowlyProgressBar.setProgress(newProgress);
            }

        });
        webView.loadUrl("http://www.cnblogs.com/linguanh");
    }

    @Override
    public void finish() {
        super.finish();
        if(slowlyProgressBar!=null){
            slowlyProgressBar.destroy();
            slowlyProgressBar = null;
        }
    }
}

     

六,完整项目

  https://github.com/af913337456/SlowlyProgressBar

时间: 2024-08-01 10:33:00

Android -- 真正的 高仿微信 打开网页的进度条效果的相关文章

Android 高仿微信实时聊天 基于百度云推送

转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38799363 ,本文出自:[张鸿洋的博客] 一直在仿微信界面,今天终于有幸利用百度云推送仿一仿微信聊天了~~~ 首先特别感谢:weidi1989分享的Android之基于百度云推送IM ,大家可以直接下载:省了很多事哈,本例中也使用了weidi的部分代码,凡是@author way的就是weidi1989的代码~~ 1.效果图 核心功能也就上面的两张图了~~~我拿着手机和模拟器

Android控件:高仿微信主UI

高仿微信主UI 之前在Android组件:Fragment切换后保存状态 一文中讲到了Fragment切换后,是如何保存原来的状态的,最重要的就是用add方法取代现在各种教程常见的replace方法.然而我发现有不少App都貌似采用ViewPager + Fragment来做主UI的.于是在Android组件:Fragment切换后保存状态 的基础上加入了ViewPager,看了下微信界面,要高仿就尽力模仿到最像,所以也把ActionBar也修改成微信的样子. 先上一张效果图: 布局 我知道微信

Android高仿微信头像裁剪

最近公司的APP很多用户反应无法上传头像,于是打算修改原来头像裁剪的代码.参考微信.QQ.唱吧头像裁剪的操作,决定就仿微信头像裁剪来上传用户头像,在Android大神鸿洋的一篇高仿微信头像的博客(博客地址结尾会贴出来)的基础上加了一些代码,加的代码主要增加如下的功能: 1.增加对大图的处理,缩放到我们裁剪框的大小. 2.裁剪后的图片保存到临时文件里,把临时文件的路径返回到需要处理的界面,因为在三星S4传byte数组返回数据时会闪退,传路径则正常. 3.对有些系统返回旋转过的图片进行处理. 这个功

Android ActionBar应用实战,高仿微信主界面的设计

转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/26365683 经过前面两篇文章的学习,我想大家对ActionBar都已经有一个相对较为深刻的理解了.唯一欠缺的是,前面我们都只是学习了理论知识而已,虽然知识点已经掌握了,但是真正投入到项目实战当中时会不会掉链子还很难说.那么不用担心,本篇文章我就将带领大家一起进入ActionBar的应用实战,将理论和实践完美结合到一起. 如果你还没有看过我的前两篇文章,建议先去阅读一下 Andr

Android 高仿微信头像截取 打造不一样的自定义控件

转载请表明出处:http://blog.csdn.net/lmj623565791/article/details/39761281,本文出自:[张鸿洋的博客] 1.概述 前面已经写了关于检测手势识别的文章,如果不了解可以参考:Android 手势检测实战 打造支持缩放平移的图片预览效果(下).首先本篇文章,将对之前博客的ZoomImageView代码进行些许的修改与改善,然后用到我们的本篇博客中去,实现仿微信的头像截取功能,当然了,个人觉得微信的截取头像功能貌似做得不太好,本篇博客准备去其糟粕

Android 高仿微信6.0主界面 带你玩转切换图标变色

转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/41087219,本文出自:[张鸿洋的博客] 1.概述 学习Android少不了模仿各种app的界面,自从微信6.0问世以后,就觉得微信切换时那个变色的Tab图标屌屌的,今天我就带大家自定义控件,带你变色变得飞起~~ 好了,下面先看下效果图: 清晰度不太好,大家凑合看~~有木有觉得这个颜色弱爆了了的,,,下面我动动手指给你换个颜色: 有没有这个颜色比较妖一点~~~好了~下面开始介绍

Android控件-Fragment+ViewPager(高仿微信界面)

什么是Fragment? Fragment是Android3.0后新增的概念,Fragment名为碎片,不过却和Activity十分相似,具有自己的生命周期,它是用来描述一些行为或一部分用户界面在一个Activity中,我们可以合并多个Fragment在一个单独的activity中建立多个UI面板,或者重用Fragment在多个activity中. 关于Fragment的生命周期,由于Fragment需要依赖Activity,也就是说当一个Activity的生命周期结束之后,那么Fragment

Android 高仿微信头像截取 打造不一样的自己定义控件

转载请表明出处:http://blog.csdn.net/lmj623565791/article/details/39761281,本文出自:[张鸿洋的博客] 1.概述 前面已经写了关于检測手势识别的文章.假设不了解能够參考:Android 手势检測实战 打造支持缩放平移的图片预览效果(下).首先本篇文章,将对之前博客的ZoomImageView代码进行些许的改动与改善,然后用到我们的本篇博客中去,实现仿微信的头像截取功能.当然了.个人觉得微信的截取头像功能貌似做得不太好.本篇博客准备去其糟粕

android高仿微信拍照、多选、预览、删除(去除相片)相册功能

先声明授人与鱼不如授人与渔,只能提供一个思路,当然需要源码的同学可以私下有偿问我要源码:QQ:508181017 工作了将近三年时间了,一直没正儿八经的研究系统自带的相册和拍照,这回来个高仿微信的拍照.多选.预览.删除(去除相片)相册功能,之前开发的所有应用都带有这需求,但是一直都不实用!废话就不多说了,先来捋一下思路: 1.拍照能实时保存到本地并实时查询(不必用广播或者服务) 2.拍照保存到到自定义路径并根据不同文件夹显示文件夹下的相片 3.多选规定张数图片 4.用到的集合有: (1).所有相