webview 自定义进度条webview无法在scollview显示一闪就没

Android WebView使用基础 - 圣骑士wind - 博客园
随笔 - 369, 文章 - 8, 评论 - 434, 引用 - 0
WebView基本使用
&  是View的一个子类,可以让你在activity中显示网页。
  可以在布局文件中写入WebView:比如下面这个写了一个填满整个屏幕的WebView: 
&?xml version="1.0" encoding="utf-8"?&
xmlns:android="/apk/res/android"
android:id="@+id/webview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
  加载一个网页,使用:
WebView myWebView = (WebView) findViewById(R.id.webview);
myWebView.loadUrl();
  注意要在manifest中加上访问网络的权限:
&manifest ... &
&uses-permission android:name="android.permission.INTERNET" /&
&/manifest&
设置WebView要显示的网页
  设置WevView要显示的网页方法有很多:
  互联网页面直接用: 
myWebView.loadUrl(&http://&);
  本地文件用:
myWebView.loadUrl(&file:///android_asset/XX.html&);
  本地文件存放在:assets文件中。
  还可以直接载入html的字符串,如:
String htmlString = "&h1&Title&/h1&&p&This is HTML text&br /&&i&Formatted in italics&/i&&br /&Anothor Line&/p&";
// 载入这个html页面
myWebView.loadData(htmlString, "text/html", "utf-8");
在WebView中使用JavaScript
  如果你想要载入的页面中用了JavaScript,你必须为你的WebView使能JavaScript。
  一旦使能之后,你也可以自己创建接口在你的应用和JavaScript代码间进行交互。
使能JavaScript
  可以通过获得,然后用使能JavaScript:
WebView myWebView = (WebView) findViewById(R.id.webview);
WebSettings webSettings = myWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
  中提供了很多有用的设置。
处理页面浏览
  当用户点击了你的WebView中的一个链接,默认的行为是Android启动一个处理URL的应用,通常,默认的浏览器打开并下载目标URL。
  但是,你可以在你的WebView中覆盖这一行为,使得连接仍在你的WebView中打开。
  之后,根据在WebView中维护的网页浏览历史,你可以允许用户向前或向后浏览他们的网页。
在WebView中打开所有链接
  要打开用户点击的链接,只需要用方法向你的WebView提供一个&比如:
WebView myWebView = (WebView) findViewById(R.id.webview);
myWebView.setWebViewClient(new WebViewClient());
  此时就OK了, 就可以在你的WebView中打开链接了。
关于打开链接位置的更多控制
  如果你对在哪里打开链接需要更多的控制,你可以创建自己的类,继承&,然后覆写&方法。
  比如下面这个:
private class MyWebViewClient extends WebViewClient
public boolean shouldOverrideUrlLoading(WebView view, String url)
       if(Uri.parse(url).getHost().equals())
// This is my web site, let my WebView load
// the page
return false;
// Otherwise, the link is not for a page on my site, so launch
// another Activity that handles URLs
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(intent);
return true;
  将特定的链接用自己的WebView打开,其他链接用浏览器(intent启动了默认的处理URL的Activity)。
  定义完之后把这个类的对象传入方法即可。 
WebView myWebView = (WebView) findViewById(R.id.webview);
myWebView.setWebViewClient(new MyWebViewClient());
  实践验证:在直接设置(new WebViewClient());时验证正确,即所有链接都是在WebView中打开。
  在设置为自定义的WebViewClient子类对象时,发现链接仍然都是从默认浏览器中打开。
浏览网页历史回退
  当你的WebView覆写了URL载入的行为,它会自动地对访问过的网页积累一个历史,你可以利用&&和&方法在这个历史中前进或后退。
  比如说使用后退键进行网页后退:
* 按键响应,在WebView中查看网页时,按返回键的时候按浏览历史退回,如果不做此项处理则整个WebView返回退出
public boolean onKeyDown(int keyCode, KeyEvent event)
// Check if the key event was the Back button and if there's history
if ((keyCode == KeyEvent.KEYCODE_BACK) && myWebView.canGoBack())
// 返回键退回
myWebView.goBack();
return true;
// If it wasn't the Back key or there's no web page history, bubble up
// to the default
// system behavior (probably exit the activity)
return super.onKeyDown(keyCode, event);
  &方法在网页可以后退时返回true。
  类似的,方法可以检查是否有可以前进的历史记录。
  如果你不执行这种检查,一旦&&和&方法到达历史记录顶端,它们将什么也不做。
  如果不加这种设置,在用户按下Back键时,如果是WebView显示网页,则会将WebView作为整体返回。
  附上完整的程序:
WebView Basic
import android.annotation.SuppressL
import android.app.A
import android.content.I
import android.net.U
import android.os.B
import android.view.KeyE
import android.view.M
import android.webkit.WebS
import android.webkit.WebV
import android.webkit.WebViewC
@SuppressLint("SetJavaScriptEnabled")
public class WebActivity extends Activity
private WebView myWebView = null;
public void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_web);
// 打开网页
myWebView = (WebView) findViewById(R.id.webview);
// myWebView.loadUrl("/mengdd/");// 博客链接
myWebView.loadUrl("/");// 百度链接
// JavaScript使能(如果要加载的页面中有JS代码,则必须使能JS)
WebSettings webSettings = myWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
// 在WebView中打开链接(默认行为是使用浏览器,设置此项后都用WebView打开)
// myWebView.setWebViewClient(new WebViewClient());
// 这样设置后所有的链接都会在当前WebView中打开
// 更强的打开链接控制:自己覆写一个WebViewClient类:除了指定链接从WebView打开,其他的链接默认打开
myWebView.setWebViewClient(new MyWebViewClient());
public boolean onCreateOptionsMenu(Menu menu)
getMenuInflater().inflate(R.menu.activity_web, menu);
return true;
* 自定义的WebViewClient类,将特殊链接从WebView打开,其他链接仍然用默认浏览器打开
* @author 1
private class MyWebViewClient extends WebViewClient
public boolean shouldOverrideUrlLoading(WebView view, String url)
if (Uri.parse(url)
.getHost()
.equals("/mengdd/archive//2935811.html")
|| Uri.parse(url).getHost()
.equals("/"))
// This is my web site, let my WebView load
// the page
// 这是官网上的例子,但是我点击特定链接的时候仍然是用浏览器而不是用自己的WebView打开,加上下面这句view.loadUrl(url)仍然是用浏览器,无解,不知道哪里出了问题
// view.loadUrl(url);
return false;
// Otherwise, the link is not for a page on my site, so launch
// another Activity that handles URLs
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(intent);
return true;
* 按键响应,在WebView中查看网页时,按返回键的时候按浏览历史退回,如果不做此项处理则整个WebView返回退出
public boolean onKeyDown(int keyCode, KeyEvent event)
// Check if the key event was the Back button and if there's history
if ((keyCode == KeyEvent.KEYCODE_BACK) && myWebView.canGoBack())
// 返回键退回
myWebView.goBack();
return true;
// If it wasn't the Back key or there's no web page history, bubble up
// to the default
// system behavior (probably exit the activity)
return super.onKeyDown(keyCode, event);
  因为关于Web方面完全是个小白,所以别人向我推荐的一个学习网站:
  API Guides: &Building Web Apps in WebView
  其他学习链接:Android&webView.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY)
setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY)可使滚动条不占位
抬头部分分三行(实际应该二行)
webview.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。trackbacks-0
如有转载,请声明出处: 时之沙:&
Android WebView常见问题解决方案汇总:
就目前而言,如何应对版本的频繁更新呢,又如何灵活多变地展示我们的界面呢,这又涉及到了web app与native app之间孰优孰劣的争论. 于是乎,一种混合型的app诞生了,灵活多变的部分,如淘宝商城首页的活动页面,一集凡客诚品中我们都可以见到web 页面与native页面的混合,既利用了web app的灵活易更新,也借助了native app本身的效率.当然,就会用到webview这样的一个控件,这里,我把自己使用过程中遇到的一些问题整理下来.
首先上张图对WebView进行一个基本的回顾:
以上思维导图原文件下载地址:
然后看一下具体的问题及解决方案:
1.为WebView自定义错误显示界面:
覆写WebViewClient中的onReceivedError()方法:
protected&void&showErrorPage()&{&&
&&&&LinearLayout&webParentView&=&(LinearLayout)mWebView.getParent();&&
&&&&initErrorPage();&&
&&&&while&(webParentView.getChildCount()&&&1)&{&&
&&&&&&&&webParentView.removeViewAt(0);&&
&&&&LinearLayout.LayoutParams&lp&=&new&LinearLayout.LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT);&&
&&&&webParentView.addView(mErrorView,&0,&lp);&&
&&&&mIsErrorPage&=&&&
protected&void&hideErrorPage()&{&&
&&&&LinearLayout&webParentView&=&(LinearLayout)mWebView.getParent();&&
&&&&mIsErrorPage&=&&&
&&&&while&(webParentView.getChildCount()&&&1)&{&&
&&&&&&&&webParentView.removeViewAt(0);&&
&&&protected&void&initErrorPage()&{&&
&&&&if&(mErrorView&==&null)&{&&
&&&&&&&&mErrorView&=&View.inflate(this,&R.layout.online_error,&null);&&
&&&&&&&&Button&button&=&(Button)mErrorView.findViewById(R.id.online_error_btn_retry);&&
&&&&&&&&button.setOnClickListener(new&OnClickListener()&{&&
&&&&&&&&&&&&public&void&onClick(View&v)&{&&
&&&&&&&&&&&&&&&&mWebView.reload();&&
&&&&&&&&&&&&}&&
&&&&&&&&});&&
&&&&&&&&mErrorView.setOnClickListener(null);&&
@Override&&
public&void&onReceivedError(WebView&view,&int&errorCode,&String&description,&String&failingUrl)&{&&
&span&style="white-space:pre"&&&&&&&&&&&&&&&&&&&&/span&&&
&span&style="white-space:pre"&&&&&&&&&&&&/span&mErrorView.setVisibility(View.VISIBLE);&&
&span&style="white-space:pre"&&&&&&&&&&&&/span&super.onReceivedError(view,&errorCode,&description,&failingUrl);&&
}&&&&&&&&&&
2.WebView cookies清理:
CookieSyncManager.createInstance(this);&&&
CookieSyncManager.getInstance().startSync();&&&
CookieManager.getInstance().removeSessionCookie();&&&
3.清理cache 和历史记录:
webView.clearCache(true);&&&
webView.clearHistory();&&
4.判断WebView是否已经滚动到页面底端:
getScrollY()方法返回的是当前可见区域的顶端距整个页面顶端的距离,也就是当前内容滚动的距离.&&&
getHeight()或者getBottom()方法都返回当前WebView&这个容器的高度&&&
getContentHeight&返回的是整个html&的高度,但并不等同于当前整个页面的高度,因为WebView&有缩放功能,&所以当前整个页面的高度实际上应该是原始html&的高度再乘上缩放比例.&因此,更正后的结果,准确的判断方法应该是:&&&
if(WebView.getContentHeight*WebView.getScale()&==&(webview.getHeight()+WebView.getScrollY())){&
5.URL拦截:
Android WebView是拦截不到页面内的fragment跳转的。但是url跳转的话,又会引起页面刷新,H5页面的体验又下降了。只能给WebView注入JS方法了。
&6.处理WebView中的非超链接请求(如Ajax请求):&
&有时候需要加上请求头,但是非超链接的请求,没有办法再shouldOverrinding中拦截并用webView.loadUrl(String url,HashMap headers)方法添加请求头
& 目前用了一个临时的办法解决:
首先需要在url中加特殊标记/协议, 如在onWebViewResource方法中拦截对应的请求,然后将要添加的请求头,以get形式拼接到url末尾
在shouldInterceptRequest()方法中,可以拦截到所有的网页中资源请求,比如加载JS,图片以及Ajax请求等等
@SuppressLint("NewApi")&&
@Override&&
public&WebResourceResponse&shouldInterceptRequest(WebView&view,String&url)&{&&
&&&&String&ajaxUrl&=&&&
&&&&if&(url.contains("req=ajax"))&{&&
&&&&&&&ajaxUrl&+=&"&imei="&+&&&
&&&&return&super.shouldInterceptRequest(view,&ajaxUrl);&&
7.在页面中先显示图片:
@Override&&
public&void&onLoadResource(WebView&view,&String&url)&{&&
&&mEventListener.onWebViewEvent(CustomWebView.this,&OnWebViewEventListener.EVENT_ON_LOAD_RESOURCE,&url);&&
&&&&if&(url.indexOf(".jpg")&&&0)&{&&
&&&&&hideProgress();&
&&&&&mEventListener.onWebViewEvent(CustomWebView.this,&OnWebViewEventListener.EVENT_ON_HIDE_PROGRESS,&view.getUrl());&&
&&&&super.onLoadResource(view,&url);&&
&8.屏蔽掉长按事件 因为webview长按时将会调用系统的复制控件:&& &&&
mWebView.setOnLongClickListener(new&OnLongClickListener()&{&&
&&&&&&&&&&&&
&&&&&&&&&&@Override&&
&&&&&&&&&&public&boolean&onLongClick(View&v)&{&&
&&&&&&&&&&&&&&return&&&
&&&&&&&&&&}&&
&&&&&&});&&
9.在WebView加入 flash支持:
String&temp&=&"&html&&body&bgcolor=\""&+&"black"&&
&&&&&&&&&&&&&&&&+&"\"&&&br/&&embed&src=\""&+&url&+&"\"&width=\""&+&"100%"&&
&&&&&&&&&&&&&&&&+&"\"&height=\""&+&"90%"&+&"\"&scale=\""&+&"noscale"&&
&&&&&&&&&&&&&&&&+&"\"&type=\""&+&"application/x-shockwave-flash"&&
&&&&&&&&&&&&&&&&+&"\"&&&/embed&&/body&&/html&";&&
String&mimeType&=&"text/html";&&
String&encoding&=&"utf-8";&&
web.loadDataWithBaseURL("null",&temp,&mimeType,&encoding,&"");&&
10.WebView保留缩放功能但隐藏缩放控件:
mWebView.getSettings().setSupportZoom(true);&&
&&&&&&&&mWebView.getSettings().setBuiltInZoomControls(true);&&
&&&&&&&&if&(DeviceUtils.hasHoneycomb())&&
&&&&&&&&&&&&&&mWebView.getSettings().setDisplayZoomControls(false);&&
注意:setDisplayZoomControls是在Android 3.0中新增的API.
这些是目前我整理出来的一些注意事项和问题解决方案,也欢迎大家多提一些关于webview的问题,如果有合适的解决方案,我会直接更新到这篇文章.
8月份更新:
11.WebView 在Android4.4的手机上onPageFinished()回调会多调用一次(具体原因待追查)
需要尽量避免在onPageFinished()中做业务操作,否则会导致重复调用,还有可能会引起逻辑上的错误.
12.需要通过获取Web页中的title用来设置自己界面中的title及相关问题:
需要给WebView设置 WebChromeClient,并在onReceiveTitle()回调中获取
WebChromeClient&webChromeClient&=&new&WebChromeClient()&{&&&&
&&&&&&&&&&&&@Override&&&&
&&&&&&&&&&&&public&void&onReceivedTitle(WebView&view,&String&title)&{&&&&
&&&&&&&&&&&&&&&&super.onReceivedTitle(view,&title);&&&&
&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&txtTitle.setText(title);&&&&
&&&&&&&&&&&&}&&&&
&&&&&&&&};&&&&
但是发现在小米3的手机上,当通过webview.goBack()回退的时候,并没有触发onReceiveTitle(),这样会导致标题仍然是之前子页面的标题,没有切换回来.
这里可以分两种情况去处理:
(1) 可以确定webview中子页面只有二级页面,没有更深的层次,这里只需要判断当前页面是否为初始的主页面,可以goBack的话,只要将标题设置回来即可.
(2)webview中可能有多级页面或者以后可能增加多级页面,这种情况处理起来要复杂一些:
&&& 因为正常顺序加载的情况onReceiveTitle是一定会触发的,所以就需要自己来维护webview& loading的一个url栈及url与title的映射关系
&& 那么就需要一个ArrayList来保持加载过的url,一个HashMap保存url及对应的title.
&& 正常顺序加载时,将url和对应的title保存起来,webview回退时,移除当前url并取出将要回退到的web 页的url,找到对应的title进行设置即可.
这里还要说一点,当加载出错的时候,比如无网络,这时onReceiveTitle中获取的标题为 找不到该网页,因此建议当触发onReceiveError时,不要使用获取到的title.
13.WebView因addJavaScriptInterface()引起的安全问题.
&&& 这个问题主要是因为会有恶意的js代码注入,尤其是在已经获取root权限的手机上,一些恶意程序可能会利用该漏洞安装或者卸载应用.
关于详细的情况可以参考下面这篇文章:
还有一个开源项目可以参考:&, 该项目利用onJsPrompt() 替代了addJavaScriptInterface(),(解决方案类似上述参考的博客)同时增加了异步回调,
很好地解决了webview &js注入的安全问题.
10月份更新:
14.WebView页面中播放了音频,退出Activity后音频仍然在播放
需要在Activity的onDestory()中调用
webView.destroy();&&
但是直接调用可能会引起如下错误:
10-10&15:01:11.402:&E/ViewRootImpl(7502):&sendUserActionEvent()&mView&==&null&&
10-10&15:01:26.818:&E/webview(7502):&java.lang.Throwable:&Error:&WebView.destroy()&called&while&still&attached!&&
10-10&15:01:26.818:&E/webview(7502):&&&&at&android.webkit.WebViewClassic.destroy(WebViewClassic.java:4142)&&
10-10&15:01:26.818:&E/webview(7502):&&&&at&android.webkit.WebView.destroy(WebView.java:707)&&
10-10&15:01:26.818:&E/webview(7502):&&&&at&com.didi.taxi.ui.webview.OperatingWebViewActivity.onDestroy(OperatingWebViewActivity.java:236)&&
10-10&15:01:26.818:&E/webview(7502):&&&&at&android.app.Activity.performDestroy(Activity.java:5543)&&
10-10&15:01:26.818:&E/webview(7502):&&&&at&android.app.Instrumentation.callActivityOnDestroy(Instrumentation.java:1134)&&
10-10&15:01:26.818:&E/webview(7502):&&&&at&android.app.ActivityThread.performDestroyActivity(ActivityThread.java:3619)&&
10-10&15:01:26.818:&E/webview(7502):&&&&at&android.app.ActivityThread.handleDestroyActivity(ActivityThread.java:3654)&&
10-10&15:01:26.818:&E/webview(7502):&&&&at&android.app.ActivityThread.access$1300(ActivityThread.java:159)&&
10-10&15:01:26.818:&E/webview(7502):&&&&at&android.app.ActivityThread$H.handleMessage(ActivityThread.java:1369)&&
10-10&15:01:26.818:&E/webview(7502):&&&&at&android.os.Handler.dispatchMessage(Handler.java:99)&&
10-10&15:01:26.818:&E/webview(7502):&&&&at&android.os.Looper.loop(Looper.java:137)&&
10-10&15:01:26.818:&E/webview(7502):&&&&at&android.app.ActivityThread.main(ActivityThread.java:5419)&&
10-10&15:01:26.818:&E/webview(7502):&&&&at&java.lang.reflect.Method.invokeNative(Native&Method)&&
10-10&15:01:26.818:&E/webview(7502):&&&&at&java.lang.reflect.Method.invoke(Method.java:525)&&
10-10&15:01:26.818:&E/webview(7502):&&&&at&com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1187)&&
10-10&15:01:26.818:&E/webview(7502):&&&&at&com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)&&
10-10&15:01:26.818:&E/webview(7502):&&&&at&dalvik.system.NativeStart.main(Native&Method)&&
如上所示,webview调用destory时,webview仍绑定在Activity上.这是由于自定义webview构建时传入了该Activity的context对象,因此需要先从父容器中移除webview,然后再销毁webview:
rootLayout.removeView(webView); &
阅读(...) 评论()小新专栏 的BLOG
用户名:小新专栏
文章数:88
评论数:46
访问量:624299
注册日期:
阅读量:24883
阅读量:262022
阅读量:999548
阅读量:149518
51CTO推荐博文
/questions//android-webview-empty-white-space-at-the-bottom-after-scaling-to-the-device-wi本文出自 “” 博客,请务必保留此出处
了这篇文章
类别:┆阅读(0)┆评论(0)

我要回帖

更多关于 webview 自定义协议 的文章

 

随机推荐