WebView+SmartRefreshLayout实现下拉刷新

如何给WebView添加下拉刷新

1,需求:

SmartRefreshLayout + WebView进行下拉刷新
PS:之前产品说要给所有的H5页面添加下拉刷新,表示有事件冲突,而且不能捕获H5页面是否已经滑动到顶部,有小伙伴提出使用js实现,这种方式不喜欢,扩展性太差了!!!

2,实现方案

想破了头,终于让我逮到了:腾讯X5浏览器安卓版本添加了下拉头!!!
别说了,赶紧写代码!!!

3,代码实现:

如何监听是否H5是否滑动到顶部?

首先添加监听:

setWebViewCallbackClient(new X5WebCallbackClient());

class X5WebCallbackClient implements WebViewCallbackClient {

       private float yStart = 0f;
       /**
        * 处理上滑到头的时候也会触发滑动到头的回调的问题
        */
       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);
       }

   }

下拉头怎么办?自己写一个?觉得太麻烦,为什么有搞好的下拉控件不用呢?


      //这个是自定义的webView,
          

  

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;

/**
* 对内核的webView再次封装
*/
public class X5WebView extends WebView {
  private static boolean isSmallWebViewDisplayed = false;
  private Map 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 用于网页去头尾
      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 的窗口转移
               */
              @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);
              }

              /**
               * 对应js 的通知弹框 ,可以用来实现js 和 android之间的通信
               */
              @Override
              public boolean onJsPrompt(WebView arg0, String arg1, String arg2, String arg3, JsPromptResult arg4) {
                  // 在这里可以判定js传过来的数据,用于调起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(5);
      }

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

  /**
   * 当webchromeClient收到 web的prompt请求后进行拦截判断,用于调起本地android方法
   *
   * @param methodName 方法名称
   * @param blockName  区块名称
   * @return true :调用成功 ; false :调用失败
   */
  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;
      }
  }

  /**
   * 判定当前的prompt消息是否为用于调用native方法的消息
   *
   * @param msg 消息名称
   * @return true 属于prompt消息方法的调用
   */
  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 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;
      /**
       * 处理上滑到头的时候也会触发滑动到头的回调的问题
       */
      private boolean isOverScroll = false;

      @Override
      public void invalidate() {
      }

      @Override
      public boolean onTouchEvent(MotionEvent event, View view) {
          switch (event.getAction()) {
              //这个地方做什么呢?这里之所以加这些事件的处理,是因为在H5上滑滑动到头的时候也会调、
              //用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);

  }


}

接下来实现回调:里面的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;
     }

 };

对了,别忘了执行刷新:

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) {
    /////////在这个我们可以知道网页已经开始加载了,停止刷新就行了
        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;
    }
}

你可能感兴趣的:(WebView+SmartRefreshLayout实现下拉刷新)