WebView+SmartRefreshLayout實(shí)現(xiàn)下拉刷新

如何給WebView添加下拉刷新

1,需求:

SmartRefreshLayout + WebView進(jìn)行下拉刷新
PS:之前產(chǎn)品說要給所有的H5頁面添加下拉刷新,表示有事件沖突,而且不能捕獲H5頁面是否已經(jīng)滑動到頂部,有小伙伴提出使用js實(shí)現(xiàn),這種方式不喜歡,擴(kuò)展性太差了?。。?/p>

2,實(shí)現(xiàn)方案

想破了頭,終于讓我逮到了:騰訊X5瀏覽器安卓版本添加了下拉頭?。?!
別說了,趕緊寫代碼!!!

3,代碼實(shí)現(xiàn):

如何監(jiān)聽是否H5是否滑動到頂部?

首先添加監(jiān)聽:

setWebViewCallbackClient(new X5WebCallbackClient());

class X5WebCallbackClient implements WebViewCallbackClient {

       private float yStart = 0f;
       /**
        * 處理上滑到頭的時候也會觸發(fā)滑動到頭的回調(diào)的問題
        */
       private boolean isOverScroll = false;

       @Override
       public void invalidate() {
       }

       @Override
       public boolean onTouchEvent(MotionEvent event, View view) {
           return super_onTouchEvent(event);
       }

       @TargetApi(Build.VERSION_CODES.GINGERBREAD)
       @Override
       public boolean overScrollBy(int deltaX, int deltaY, int scrollX,
                                   int scrollY, int scrollRangeX, int scrollRangeY,
                                   int maxOverScrollX, int maxOverScrollY,
                                   boolean isTouchEvent, View view) {
           Log.e("0705", "overScrollBy Y:" + scrollY + "X:" + scrollRangeY);
           //這里就是滑動到頭了?。?!
           return super_overScrollBy(deltaX, deltaY, scrollX, scrollY,
                   scrollRangeX, scrollRangeY, maxOverScrollX, maxOverScrollY,
                   isTouchEvent);
       }

       @Override
       public void computeScroll(View view) {
           super_computeScroll();
       }

       @TargetApi(Build.VERSION_CODES.GINGERBREAD)
       @Override
       public void onOverScrolled(int scrollX, int scrollY, boolean clampedX,
                                  boolean clampedY, View view) {
           Log.e("0706", "overScrollBy Y:" + scrollY + "X:" + clampedY);
           super_onOverScrolled(scrollX, scrollY, clampedX, clampedY);
       }

       @Override
       public void onScrollChanged(int l, int t, int oldl, int oldt, View view) {
           Log.e("0707", l + ">>>" + t + ">>>" + oldl + ">>>" + oldt);
           super_onScrollChanged(l, t, oldl, oldt);
       }

       @Override
       public boolean dispatchTouchEvent(MotionEvent ev, View view) {
           return super_dispatchTouchEvent(ev);
       }

       @Override
       public boolean onInterceptTouchEvent(MotionEvent ev, View view) {
           return super_onInterceptTouchEvent(ev);
       }

   }

下拉頭怎么辦?自己寫一個?覺得太麻煩,為什么有搞好的下拉控件不用呢?

<com.scwang.smartrefresh.layout.SmartRefreshLayout
      android:id="@+id/refreshView"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      app:srlEnableLoadMore="false">
      //這個是自定義的webView,
          <XXXX.X5WebView
              android:id="@+id/wv_webview"
              android:layout_width="fill_parent"
              android:layout_height="fill_parent" />

  </com.scwang.smartrefresh.layout.SmartRefreshLayout>

webView的代碼貼出來:

package XXXXX.web;

import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Build;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.jumei.lib.storage.shareperfrence.JmSharePrefrence;
import com.jumei.lib.util.http.HTTP;
import com.tencent.smtt.export.external.interfaces.HttpAuthHandler;
import com.tencent.smtt.export.external.interfaces.JsPromptResult;
import com.tencent.smtt.export.external.interfaces.JsResult;
import com.tencent.smtt.sdk.WebSettings;
import com.tencent.smtt.sdk.WebView;
import com.tencent.smtt.sdk.WebViewCallbackClient;
import com.tencent.smtt.sdk.WebViewClient;

import java.util.HashMap;
import java.util.Map;

/**
* 對內(nèi)核的webView再次封裝
*/
public class X5WebView extends WebView {
  private static boolean isSmallWebViewDisplayed = false;
  private Map<String, Object> mJsBridges;
  private X5WebViewClient client;
  private X5WebChromeClient chromeClient;
  private OnScrollCallback scrollCallback;

  public void setScrollCallback(OnScrollCallback scrollCallback) {
      this.scrollCallback = scrollCallback;
  }

  /**
   * 初始化
   */
  @SuppressLint("SetJavaScriptEnabled")
  public X5WebView(Context context, AttributeSet attr) {
      super(context, attr);
      // 配置X5webview的事件處理
      initView(context);
  }

  private void initView(Context context) {
      initClient();
      this.setWebViewClient(client);
      this.setWebChromeClient(chromeClient);
      initWebViewSettings();
  }

  public X5WebView(Context context) {
      super(context);
      initView(context);
  }

  public X5WebView(Context context, AttributeSet attr, int style) {
      super(context, attr, style, false);
      initView(context);
  }

  /**
   * 配置屬性
   */
  @SuppressLint({"JavascriptInterface", "SetJavaScriptEnabled"})
  private void initWebViewSettings() {
      WebSettings webSetting = this.getSettings();
      webSetting.setJavaScriptEnabled(true);
      webSetting.setJavaScriptCanOpenWindowsAutomatically(true);
      webSetting.setAllowFileAccess(true);
      webSetting.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NARROW_COLUMNS);
      webSetting.setSupportZoom(true);
      webSetting.setUseWideViewPort(true);
      // 修改userAgent 用于網(wǎng)頁去頭尾
      String userAgent = webSetting.getUserAgentString();
      webSetting.setUserAgentString(userAgent);
      webSetting.setLoadWithOverviewMode(true);
      webSetting.setAppCacheEnabled(true);
      webSetting.setDatabaseEnabled(true);
      webSetting.setDomStorageEnabled(true);
      webSetting.setGeolocationEnabled(true);
      webSetting.setAppCacheMaxSize(Long.MAX_VALUE);
      webSetting.setPluginState(WebSettings.PluginState.ON_DEMAND);
      webSetting.setRenderPriority(WebSettings.RenderPriority.HIGH);
      webSetting.setCacheMode(WebSettings.LOAD_NO_CACHE);
      webSetting.setAllowFileAccessFromFileURLs(true);
      webSetting.setAppCacheEnabled(false);
      WebView.setWebContentsDebuggingEnabled(true);
      setWebViewCallbackClient(new X5WebCallbackClient());
      addJavascriptInterface(new X5SimpleJavaScriptFunction() {
      }, "JavaScriptInterface");

  }

  private void initClient() {
      if (getContext() instanceof Activity) {
          client = new X5WebViewClient((Activity) getContext()) {

              @Override
              public void onReceivedHttpAuthRequest(WebView webview,
                                                    HttpAuthHandler httpAuthHandlerhost, String host,
                                                    String realm) {
                  boolean flag = httpAuthHandlerhost.useHttpAuthUsernamePassword();
              }
          };
          chromeClient = new X5WebChromeClient((Activity) getContext()) {

              @Override
              public boolean onJsConfirm(WebView arg0, String arg1, String arg2, JsResult arg3) {
                  return super.onJsConfirm(arg0, arg1, arg2, arg3);
              }

              /**
               * webview 的窗口轉(zhuǎn)移
               */
              @Override
              public boolean onCreateWindow(WebView arg0, boolean arg1, boolean arg2, Message msg) {
                  // TODO Auto-generated method stub
                  if (X5WebView.isSmallWebViewDisplayed == true) {
                      WebViewTransport webViewTransport = (WebViewTransport) msg.obj;
                      WebView webView = new WebView(X5WebView.this.getContext()) {

                          @Override
                          protected void onDraw(Canvas canvas) {
                              super.onDraw(canvas);
                              Paint paint = new Paint();
                              paint.setColor(Color.GREEN);
                              paint.setTextSize(15);
                              canvas.drawText("新建窗口", 10, 10, paint);
                          }

                          ;
                      };
                      webView.setWebViewClient(new WebViewClient() {
                          @Override
                          public boolean shouldOverrideUrlLoading(WebView arg0, String arg1) {
                              arg0.loadUrl(arg1);
                              return true;
                          }

                          ;
                      });
                      webViewTransport.setWebView(webView);
                      msg.sendToTarget();
                  }
                  return true;
              }

              @Override
              public boolean onJsAlert(WebView arg0, String arg1, String arg2, JsResult arg3) {
                  /*
                    這里寫入你自定義的window alert
                   */
                  Log.i("cdelweb", "setX5webview = null");
                  return super.onJsAlert(null, "", "", arg3);
              }

              /**
               * 對應(yīng)js 的通知彈框 ,可以用來實(shí)現(xiàn)js 和 android之間的通信
               */
              @Override
              public boolean onJsPrompt(WebView arg0, String arg1, String arg2, String arg3, JsPromptResult arg4) {
                  // 在這里可以判定js傳過來的數(shù)據(jù),用于調(diào)起android native 方法
                  if (X5WebView.this.isMsgPrompt(arg1)) {
                      if (X5WebView.this.onJsPrompt(arg2, arg3)) {
                          return true;
                      } else {
                          return false;
                      }
                  }
                  return super.onJsPrompt(arg0, arg1, arg2, arg3, arg4);
              }

              @Override
              public void onReceivedTitle(WebView arg0, final String arg1) {
                  super.onReceivedTitle(arg0, arg1);
                  Log.i("cdelweb", "webpage title is " + arg1);

              }


          };
      }
  }


  /**
   * 一般不用這個,它的作用是在webview上面再次繪制控件
   *
   * @param canvas
   * @param child
   * @param drawingTime
   * @return
   */
  @Override
  protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
      boolean ret = super.drawChild(canvas, child, drawingTime);
      canvas.save();
      return ret;
  }

  /**
   * 是否允許小窗
   *
   * @param enabled
   */

  public static void setSmallWebViewEnabled(boolean enabled) {
      isSmallWebViewDisplayed = enabled;
  }

  /**
   * js橋接
   *
   * @param jsBridgeBundle
   */
  public void addJavascriptBridge(X5SecurityJsBridgeBundle jsBridgeBundle) {
      if (this.mJsBridges == null) {
          this.mJsBridges = new HashMap<String, Object>(5);
      }

      if (jsBridgeBundle != null) {
          String tag = X5SecurityJsBridgeBundle.BLOCK + jsBridgeBundle.getJsBlockName() + "-"
                  + X5SecurityJsBridgeBundle.METHOD + jsBridgeBundle.getMethodName();
          this.mJsBridges.put(tag, jsBridgeBundle);
      }
  }

  /**
   * 當(dāng)webchromeClient收到 web的prompt請求后進(jìn)行攔截判斷,用于調(diào)起本地android方法
   *
   * @param methodName 方法名稱
   * @param blockName  區(qū)塊名稱
   * @return true :調(diào)用成功 ; false :調(diào)用失敗
   */
  private boolean onJsPrompt(String methodName, String blockName) {
      String tag = X5SecurityJsBridgeBundle.BLOCK + blockName + "-" + X5SecurityJsBridgeBundle.METHOD + methodName;

      if (this.mJsBridges != null && this.mJsBridges.containsKey(tag)) {
          ((X5SecurityJsBridgeBundle) this.mJsBridges.get(tag)).onCallMethod();
          return true;
      } else {
          return false;
      }
  }

  /**
   * 判定當(dāng)前的prompt消息是否為用于調(diào)用native方法的消息
   *
   * @param msg 消息名稱
   * @return true 屬于prompt消息方法的調(diào)用
   */
  private boolean isMsgPrompt(String msg) {
      if (msg != null && msg.startsWith(X5SecurityJsBridgeBundle.PROMPT_START_OFFSET)) {
          return true;
      } else {
          return false;
      }
  }


  @Override
  public final void loadUrl(String s) {
      if (!s.startsWith("javascript")) {
          Map<String, String> map = new HashMap<>();
          map.put(JmSharePrefrence.SMDEVICENAME, JmSharePrefrence.getInstance().getSmdevicename());
          map.put(JmSharePrefrence.SMDEVICEID, JmSharePrefrence.getInstance().getSmdeviceid());
          map.put(JmSharePrefrence.SMVERSION, JmSharePrefrence.getInstance().getVersion());
          super.loadUrl(s, map);
      } else {
          super.loadUrl(s);
      }


  }

  public void setX5WebViewCallBack(X5WebViewCallBack callBack) {
      if (callBack == null) {
          return;
      }
      if (client != null) {
          client.setCallBack(callBack);
      }


      if (chromeClient != null) {
          chromeClient.setCallBack(callBack);
      }
  }

  class X5WebCallbackClient implements WebViewCallbackClient {

      private float yStart = 0f;
      /**
       * 處理上滑到頭的時候也會觸發(fā)滑動到頭的回調(diào)的問題
       */
      private boolean isOverScroll = false;

      @Override
      public void invalidate() {
      }

      @Override
      public boolean onTouchEvent(MotionEvent event, View view) {
          switch (event.getAction()) {
              //這個地方做什么呢?這里之所以加這些事件的處理,是因?yàn)樵贖5上滑滑動到頭的時候也會調(diào)、
              //用overScrollBy,所以不光要判斷方向,還要在webView滑動的時候去掉下拉刷新控件的事件
              case MotionEvent.ACTION_DOWN:
                  yStart = event.getY();
                  break;
              case MotionEvent.ACTION_UP:
                  float yEnd = event.getY();
                  if (yEnd <= yStart) {
                      isOverScroll = true;
                  } else {
                      isOverScroll = false;
                  }
                  if (Math.abs(yEnd - yStart) > 20f && scrollCallback != null) {
                      scrollCallback.onFinishRefresh();
                  }
                  break;
              default:
                  break;
          }
          return super_onTouchEvent(event);
      }

      @TargetApi(Build.VERSION_CODES.GINGERBREAD)
      @Override
      public boolean overScrollBy(int deltaX, int deltaY, int scrollX,
                                  int scrollY, int scrollRangeX, int scrollRangeY,
                                  int maxOverScrollX, int maxOverScrollY,
                                  boolean isTouchEvent, View view) {
          Log.e("0705", "overScrollBy Y:" + scrollY + "X:" + scrollRangeY);
          if (scrollCallback != null && !isOverScroll) {
              scrollCallback.onRefresh();
          }
          return super_overScrollBy(deltaX, deltaY, scrollX, scrollY,
                  scrollRangeX, scrollRangeY, maxOverScrollX, maxOverScrollY,
                  isTouchEvent);
      }

      @Override
      public void computeScroll(View view) {
          super_computeScroll();
      }

      @TargetApi(Build.VERSION_CODES.GINGERBREAD)
      @Override
      public void onOverScrolled(int scrollX, int scrollY, boolean clampedX,
                                 boolean clampedY, View view) {
          Log.e("0706", "overScrollBy Y:" + scrollY + "X:" + clampedY);
          super_onOverScrolled(scrollX, scrollY, clampedX, clampedY);
      }

      @Override
      public void onScrollChanged(int l, int t, int oldl, int oldt, View view) {
          Log.e("0707", l + ">>>" + t + ">>>" + oldl + ">>>" + oldt);
          super_onScrollChanged(l, t, oldl, oldt);
      }

      @Override
      public boolean dispatchTouchEvent(MotionEvent ev, View view) {
          return super_dispatchTouchEvent(ev);
      }

      @Override
      public boolean onInterceptTouchEvent(MotionEvent ev, View view) {
          return super_onInterceptTouchEvent(ev);
      }

  };

  public interface OnScrollCallback {

      void onRefresh();


      void onFinishRefresh();

      boolean isTouched(MotionEvent event);

  }


}

接下來實(shí)現(xiàn)回調(diào):里面的rootView = SmartRefreshLayout

private X5WebView.OnScrollCallback scrollCallback = new X5WebView.OnScrollCallback() {
     @Override
     public void onRefresh() {
         if (rootView != null && !rootView.isEnabled()) {
             rootView.setEnabled(true);
             rootView.setEnableRefresh(true);
         }
         if (webViewCallBack != null) {
             webViewCallBack.onOverScrolled(true);
         }
     }

     @Override
     public void onFinishRefresh() {
         if (rootView != null) {
             rootView.finishRefresh();
             rootView.setEnabled(false);
             rootView.setEnableRefresh(false);
         }
     }

     @Override
     public boolean isTouched(MotionEvent event) {
         if (rootView != null) {
             if (RefreshUtil.isRefresh(rootView)) {
                 return false;
             }
         }
         return true;
     }

 };

對了,別忘了執(zhí)行刷新:

rootView.setOnRefreshListener(refreshLayout1 -> {
         x5WebView.reload();

     });

最后還有一個問題,怎么停止刷新?

package XXXXt.web;

import android.app.Activity;
import android.text.TextUtils;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;

import com.tencent.smtt.sdk.WebChromeClient;
import com.tencent.smtt.sdk.WebView;


/**
 * Created by GongPeng on 2017/5/27.
 * use of
 */

public class X5WebChromeClient extends WebChromeClient {

    private static final String TAG = X5WebChromeClient.class.getName();
    private Activity mContext;
    private X5WebViewCallBack mCallBack;
    private X5WebLoadCallback  webLoadCallback;

    public X5WebChromeClient(Activity mContext) {
        this.mContext = mContext;
    }

    private String titleStr;

    private TextView tvTitle;

    private ProgressBar mPageLoadingProgressBar;

    public void setmPageLoadingProgressBar(ProgressBar mPageLoadingProgressBar) {
        this.mPageLoadingProgressBar = mPageLoadingProgressBar;
    }

    public void setTitleStr(String titleStr) {
        this.titleStr = titleStr;
    }

    public void setTvTitle(TextView tvTitle) {
        this.tvTitle = tvTitle;
    }

    @Override
    public void onReceivedTitle(WebView view, String title) {
        if (TextUtils.isEmpty(titleStr)) {
            String titleTemp;
            if (TextUtils.isEmpty(title)) {
                titleTemp = "";
            } else if (title.length() > 16) {
                titleTemp = title.substring(0, 15);
            } else {
                titleTemp = title;
            }
            setTitleName(titleTemp);
            if (mCallBack != null) {
                try {
                    mCallBack.onReceivedTitle(titleTemp);
                } catch (Exception e) {
                    if (e != null) {
                    }
                }
            }
        } else {
            setTitleName(titleStr);
        }

    }


    @Override
    public void onProgressChanged(WebView view, int newProgress) {
    /////////在這個我們可以知道網(wǎng)頁已經(jīng)開始加載了,停止刷新就行了
        if (webLoadCallback != null){
            webLoadCallback.onStartLoad();
        }
        if (mCallBack != null) {
            try {
                mCallBack.onProgressChanged(newProgress);
            } catch (Exception e) {
                if (e != null) {
                }
            }

        }
        if (mPageLoadingProgressBar == null) {
            return;
        }
        mPageLoadingProgressBar.setProgress(newProgress);
        if (mPageLoadingProgressBar != null && newProgress != 100) {
            mPageLoadingProgressBar.setVisibility(View.VISIBLE);
        } else if (mPageLoadingProgressBar != null) {
            mPageLoadingProgressBar.setVisibility(View.GONE);
        }
    }

    private void setTitleName(String name) {
        if (tvTitle != null) {
            tvTitle.setText(name);
        }
    }

    public void setCallBack(X5WebViewCallBack callBack) {
        mCallBack = callBack;
    }

    public void setWebLoadCallback(X5WebLoadCallback webLoadCallback) {
        this.webLoadCallback = webLoadCallback;
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 蟬是一種有耐心的動物。據(jù)說他們在地下呆上十來個月才有短短一兩個月,羽化成蟬。鳴唱片段時光,然后交配,將下一代產(chǎn)入濕...
    娜小野閱讀 380評論 0 1
  • 離高考還有365天,我現(xiàn)在可以做什么?
    攸寧er閱讀 217評論 0 2
  • 我們在現(xiàn)實(shí)中,看到很多牛人,能夠一直堅(jiān)持做一件事情,讓普通大眾無法啟及。是什么力量在驅(qū)動著他們?是興趣、愛好?還是...
    耐撕的公牛閱讀 2,053評論 0 4
  • 避開四個宿敵儲存葡萄酒-進(jìn)口紅酒批發(fā) 最初始的葡萄酒窖其實(shí)是窟窿,法語中代表酒窖的單詞“Cave”即源于此??吡?..
    爵士鋼鐵俠閱讀 215評論 0 0
  • 親愛的V: 這是給你第13封信,今早上出門前,你的情緒有點(diǎn)爆燥,我猜你是覺得沒有把英語課文給背出來,還是覺得時間太...
    一黍花園閱讀 286評論 0 1