Android -- 真正的 高仿微信 打開網頁的進度條效果


(本博客為原創,http://www.cnblogs.com/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

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM