content: package com.slowlyprogressbar;
  
  import android.animation.Animator;
  import android.animation.AnimatorListenerAdapter;
  import android.animation.ObjectAnimator;
  import android.animation.ValueAnimator;
  import android.os.Handler;
  import android.os.Message;
  import android.util.Log;
  import android.view.View;
  import android.view.animation.DecelerateInterpolator;
  import android.widget.ProgressBar;
  import android.widget.RelativeLayout;
  
  import java.util.ArrayList;
  import java.util.List;
  
  /**
   * Created by 林冠宏 on 2016/7/11.
   *
   * 真正的仿微信网页打开的进度条
   * 
   * 两种方式
   *     1，setLayoutParams 的形式
   *     2，动画形式(推荐)
   *
   * 下面的所有属性都可以自己采用 get set 来自定义
   *
   */
  
  public class SlowlyProgressBar {
  
      private static final int StartAnimation = 0x12;
  
      private Handler handler;
      private View view;
      private ProgressBar progressBar;
  
      /** 当前的位移距离和速度 */
      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;
      }
  
      /** 第二种 */
      public SlowlyProgressBar(ProgressBar progressBar) {
          this.progressBar = progressBar;
      }
  
      /** 善后工作，释放引用的持有，方能 gc 生效 */
      public void destroy(){
          if(progressQuery!=null){
              progressQuery.clear();
              progressQuery = null;
          }
          if(speedQuery!=null){
              speedQuery.clear();
              speedQuery = null;
          }
          view = null;
          if(handler!=null){
              handler.removeCallbacksAndMessages(null);
              handler = null;
          }
      }
  
      /** -------------------------------------------第二种方法-------------------------------------- */
      /** 在 WebViewClient onPageStarted 调用 */
      public void onProgressStart(){
          progressBar.setVisibility(View.VISIBLE);
          progressBar.setAlpha(1.0f);
      }
  
      /** 在 WebChromeClient onProgressChange 调用 */
      public void onProgressChange(
              int newProgress
      ){
          int currentProgress = progressBar.getProgress();
          if (newProgress >= 100 && !isStart) {
              /** 防止调用多次动画 */
              isStart = true;
              progressBar.setProgress(newProgress);
              /** 开启属性动画让进度条平滑消失*/
              startDismissAnimation(progressBar.getProgress());
          } else {
              /** 开启属性动画让进度条平滑递增 */
              startProgressAnimation(newProgress,currentProgress);
          }
      }
      /** -------------------------------第二种结束---------------------------- */
  
      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 是纠正误差 */
          /** 原因是：px 和 db 不是对比的，个人十分建议不乘3，采用函数适配转换，下面提供个函数 */
          progress = (record * speedTime);
          /** 纠正 */
          if(progress >= lastWidth){
              view.setLayoutParams(new RelativeLayout.LayoutParams(progress,height*3));
          }else{
              Log.d("zzzzz","hit "+progress+"---"+lastWidth);
          }
          record ++;
      }
  
      /** 下面是动画的形式 */
      /**
       * progressBar 进度缓慢递增，300ms/次
       */
      private void startProgressAnimation(int newProgress,int currentProgress) {
          ObjectAnimator animator = ObjectAnimator.ofInt(progressBar, "progress", currentProgress, newProgress);
          animator.setDuration(300);
          animator.setInterpolator(new DecelerateInterpolator()); /** 减速形式的加速器，个人喜好 */
          animator.start();
      }
  
      private void startDismissAnimation(final int progress) {
          ObjectAnimator anim = ObjectAnimator.ofFloat(progressBar, "alpha", 1.0f, 0.0f);
          anim.setDuration(1500);  // 动画时长
          anim.setInterpolator(new DecelerateInterpolator());     // 减速
  
          anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
  
              @Override
              public void onAnimationUpdate(ValueAnimator valueAnimator) {
                  float fraction = valueAnimator.getAnimatedFraction();      // 0.0f ~ 1.0f
                  int offset = 100 - progress;
                  progressBar.setProgress((int) (progress + offset * fraction));
              }
          });
  
          anim.addListener(new AnimatorListenerAdapter() {
  
              @Override
              public void onAnimationEnd(Animator animation) {
                  progressBar.setProgress(0);
                  progressBar.setVisibility(View.GONE);
                  isStart = false;
              }
          });
          anim.start();
      }
      
  }
  
  
  
  