Android Webview 和 ScrollView 冲突和 WebView 使用总结
rlbx7836
7年前
<h3>前言:</h3> <p>今天review项目中的代码想起来之前修改一个有关Webview和ScrollView冲突的bug:</p> <ul> <li>1.因为Webview和ScrollView都用滑动事件,导致webview很难被滑动,即使被滑动了一点也非常不顺畅</li> <li>2.解决滑动冲突问题后发现,如果webview嵌套的html中含有轮播图等还是有问题。</li> </ul> <p style="text-align:center"><img src="https://simg.open-open.com/show/6581bd3d2c018bc93caa5fee48e4973e.gif"></p> <h3>解决方案:</h3> <p>其实这两个问题属于同一类的问题,都是Webview和ScrollView滑动时产生的冲突</p> <p>解决方法很简单:</p> <pre> <code class="language-java">public class ScrollWebView extends WebView{ private float startx; private float starty; private float offsetx; private float offsety; public ScrollWebView(Context context) { super(context); } public ScrollWebView(Context context, AttributeSet attrs) { super(context, attrs); } public ScrollWebView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: getParent().requestDisallowInterceptTouchEvent(true); startx = event.getX(); starty = event.getY(); Log.e("MotionEvent", "webview按下"); break; case MotionEvent.ACTION_MOVE: Log.e("MotionEvent", "webview滑动"); offsetx = Math.abs(event.getX() - startx); offsety = Math.abs(event.getY() - starty); if (offsetx > offsety) { getParent().requestDisallowInterceptTouchEvent(true); Log.e("MotionEvent", "屏蔽了父控件"); } else { getParent().requestDisallowInterceptTouchEvent(false); Log.e("MotionEvent", "事件传递给父控件"); } break; default: break; } return super.onTouchEvent(event); } }</code></pre> <p>自定义一个WebView,重写onTouchEvent方法。判断当手指横向滑动的偏移量(offsetx)大于纵向滑动的偏移量(offsety)时屏蔽父控件的滑动。</p> <p>解决方法很简单,只要我们在遇到问题的时候多多思考,弄清楚错误的原因,有针对性的研究,绝大数的问题都是可以解决的。</p> <h2>webview使用总结</h2> <p>本来写到这里就想结束了,但是发现写的东西太少了,估计会被骂,既然写的是webview,索性就把我对webview的使用总结整理一下。</p> <h3>数据加载</h3> <ul> <li>加载本地资源 <pre> <code class="language-java">webView.loadUrl("file:///android_asset/text.html");</code></pre> </li> <li>加载网络资源 <pre> <code class="language-java">webView.loadUrl("www.xxx.com/text.html");</code></pre> </li> <li>添加请求头信息 <pre> <code class="language-java">Map<String,String> map=new HashMap<String,String>(); map.put("User-Agent","Android"); webView.loadUrl("www.xxx.com/text.html",map);</code></pre> </li> <li>直接加载html代码片段 <pre> <code class="language-java">String html = "数据"; webView.loadDataWithBaseURL(null,html, "text/html", "utf-8",null);</code></pre> </li> </ul> <h3>支持JavaScript</h3> <ul> <li>设置支持JavaScript <pre> <code class="language-java">WebSettings webSettings = webView.getSettings(); webSettings.setJavaScriptEnabled(true);//设置支持javascript webView.addJavascriptInterface(new JavaScriptInterface(), "tyk");//添加一个对象, 让JS可以访问该对象的方法, 该对象中可以调用JS中的方法 </code></pre> </li> </ul> <ul> <li> <p>JavaScriptInterface 接口定义</p> <pre> <code class="language-java">private final class JavaScriptInterface { //JavaScript调用此方法拨打电话 public void call(String phone) { //startActivity(new Intent(Intent.ACTION_CALL, Uri.parse("tel:" + phone))); Toast.makeText(MainActivity.this, phone, Toast.LENGTH_LONG).show(); } //Html调用此方法传递数据 public void showcontacts() { String json = "[{\"name\":\"tyk\", \"amount\":\"9999999\", \"phone\":\"1831041486.\"}]"; // 调用JS中的方法 webView.loadUrl("javascript:show('" + json + "')"); } }</code></pre> </li> </ul> <h3>WebViewClient</h3> <ul> <li> <p>主要辅助WebView处理各种通知、请求事件</p> <pre> <code class="language-java">onLoadResource//加载资源时响应 onPageStart//在加载页面时响应 onPageFinish//在加载页面结束时响应 onReceiveError//在加载出错时响应 onReceivedHttpAuthRequest//获取返回信息授权请求</code></pre> </li> <li> <p>要实现WebView中链接在WebView内部跳转</p> <pre> <code class="language-java">webView.setWebViewClient(new WebViewClient() { public boolean shouldOverrideUrlLoading(WebView view, String url) { view.loadUrl(url); return true; } });</code></pre> </li> </ul> <h3>WebChromeClient</h3> <ul> <li> <p>主要辅助WebView处理Javascript的对话框,网站图标,网站title,加载进度等</p> <pre> <code class="language-java"> onCloseWindow//关闭WebView onCreateWindow() //触发创建一个新的窗口 onJsAlert //触发弹出一个对话框 onJsPrompt //触发弹出一个提示 onJsConfirm//触发弹出确认提示 onProgressChanged //加载进度 onReceivedIcon //获取网页icon onReceivedTitle//获取网页title</code></pre> </li> <li> <p>加载进度获取title</p> <pre> <code class="language-java">webView.setWebChromeClient(new WebChromeClient() { @Override public void onProgressChanged(WebView view, int newProgress) { if (newProgress == 100) { //网页加载完成 } else { //网页加载中 } } });</code></pre> </li> </ul> <h3>WebView 缓存控制</h3> <pre> <code class="language-java">LOAD_CACHE_ONLY//不使用网络,只读取本地缓存数据 LOAD_DEFAULT//根据cache-control决定是否从网络上取数据。 LOAD_CACHE_NORMAL//API level 17中已经废弃, 从API level 11开始作用同LOAD_DEFAULT模式 LOAD_NO_CACHE//不使用缓存,只从网络获取数据. LOAD_CACHE_ELSE_NETWORK//只要本地有,无论是否过期,或者no-cache,都使用缓存中的数据。</code></pre> <p>一般都是根据网络来判断缓存使用情况</p> <pre> <code class="language-java">//加载缓存形式 if (CommonUtils.getNetWorkStatus(context)){//判断网络是否可用 // 根据cache-control决定是否从网络上取数据。 websettings.setCacheMode(WebSettings.LOAD_NO_CACHE); }else{ // 只要本地有,无论是否过期,或者no-cache,都使用缓存中的数据。 websettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); }</code></pre> <h3>页面返回</h3> <ul> <li> <p>我们有时需要实现回退到上一目录</p> <pre> <code class="language-java">@Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { if (webView.canGoBack()) { webView.goBack();//返回上一浏览页面 return true; } else { finish();//关闭Activity } } return super.onKeyDown(keyCode, event); }</code></pre> </li> </ul> <h3>其他设置</h3> <pre> <code class="language-java">WebSettings webSettings = webView.getSettings(); //支持缩放 webSettings.setSupportZoom(true); //支持内容重新布局 webSettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN); //多窗口 webSettings.supportMultipleWindows(); //当webview调用requestFocus时为webview设置节点 webSettings.setNeedInitialFocus(true); //设置支持缩放 webSettings.setBuiltInZoomControls(true); //支持通过JS打开新窗口 webSettings.setJavaScriptCanOpenWindowsAutomatically(true); //支持自动加载图片 webSettings.setLoadsImagesAutomatically(true); //提高渲染的优先级 websettings.setRenderPriority(WebSettings.RenderPriority.HIGH); // 开启H5(APPCache)缓存功能 websettings.setAppCacheEnabled(true); // 开启 DOM storage 功能 websettings.setDomStorageEnabled(true); // 应用可以有数据库 websettings.setDatabaseEnabled(true); // 可以读取文件缓存(manifest生效) websettings.setAllowFileAccess(true);</code></pre> <p> </p> <p>来自:https://juejin.im/post/58f714ac570c35005651a347</p> <p> </p>