学习感受
WebView 网页视图在 Android APP 中也是用的非常多,比如微信、QQ、淘宝、bilibili 等等这些非常受欢迎的应用都有使用到这个组件。
同时,WebView 是可以调用里面的 Javascript 代码。JavaScript 代码也能够调用的 Android 中相关的代码,这就相当于是混合开发。混合开发的案例也非常多,比如我们的常用的淘宝,它就是使用了混合开发的方式了。
本日志仅仅是记录了 WebView 的一些基本的使用,深入学习这种混合的开发方式,这里不过多赘述。
实例
创建 WebView
创建 WebView 非常简单,只需创建组件即可,同时需要设置id
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<WebView
android:id="@+id/web_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
加载网页
加载网页分别有两种不同的加载方式,一个是加载本地的网页,另一个是加载远程的网页。
本地加载
在加载本地网页之前,需要创建一个 asset 的文件夹。因为只有 asset 文件夹下的文件不会被编译进去,比如我们之前在 res/drawable 文件夹中放入的这些图片都是会进行一个编译。调用图片的方式,也不是用路径来进行一个编译,而是使用这种 @drawablw/xxxx
这种方式来获取图片的。
正确的创建的 asset 文件夹的步骤如下。
新建
直接 Finish
创建完成之后,可以随便写一个 html 代码,放到这个 asset 文件夹下。这里用的是我之前写的一个网页进行测试
加载网页的方法用的是 onLoad 方法,固定的部分是 file:///android_asset/ ,后面的部分就可以指定的网页的。
package top.bestguo.androidlayout;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.webkit.WebView;
public class WebViewActivity extends AppCompatActivity {
private WebView webView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_web_view);
progressBar = (ProgressBar) findViewById(R.id.progress);
webView = (WebView) findViewById(R.id.web_view);
// 允许 javascript
webView.getSettings().setJavaScriptEnabled(true);
// 加载本地的 html 文件
webView.loadUrl("file:///android_asset/index.html");
}
运行效果如下:
远程加载
远程加载只需要一个 http 或者 https 协议的地址就可以了。不过,在加载远程的一个网址时,需要允许 javascript 网页才能够正常的运行成功。不允许将加载不出来。
启用 javascript 的方法为 setJavaScriptEnabled
,设置为 true 允许,false 为禁止。
这里以我的个人网站为例子
package top.bestguo.androidlayout;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.webkit.WebView;
public class WebViewActivity extends AppCompatActivity {
private WebView webView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_web_view);
progressBar = (ProgressBar) findViewById(R.id.progress);
webView = (WebView) findViewById(R.id.web_view);
// 允许 javascript
webView.getSettings().setJavaScriptEnabled(true);
// 加载本地的 html 文件
// webView.loadUrl("file:///android_asset/index.html");
webView.loadUrl("https://www.bestguo.top");
}
运行效果如下
进入新页面
我们在浏览网页的时候,需要点击超链接来进入新的页面,但是我们在点击时。出现了以下的效果
就是需要我们选择一个外置的浏览器来访问新的页面,这样的体验其实并不好。
因此,解决这种方法需要用到 setWebViewClient
这个方法,它的参数是 WebViewClient
以及被它所继承的子类,重写其中的方法。这个方法就是 shouldOverrideUrlLoading
。
实现的代码如下
package top.bestguo.androidlayout;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.webkit.WebResourceRequest;
import android.webkit.WebView;
import android.webkit.WebViewClient;
public class WebViewActivity extends AppCompatActivity {
private WebView webView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_web_view);
progressBar = (ProgressBar) findViewById(R.id.progress);
webView = (WebView) findViewById(R.id.web_view);
// 允许 javascript
webView.getSettings().setJavaScriptEnabled(true);
// 加载本地的 html 文件
// webView.loadUrl("file:///android_asset/index.html");
webView.loadUrl("https://www.bestguo.top");
webView.setWebViewClient(new MyWebViewClient());
}
private class MyWebViewClient extends WebViewClient {
// 如果要设置成不用新浏览器打开
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
view.loadUrl(request.getUrl().toString());
return true;
}
}
}
建立了一个内部类,类名为 MyWebViewClient,需要继承自 WebViewClient 类。重写其 shouldOverrideUrlLoading 方法,将当前的 webview 中的 url 进行一个重新的加载,这样一来就不会直接提示使用外置浏览器了。
调用 setWebViewClient 方法是,传入的是自己创建的内部类对象就行了 webView.setWebViewClient(new MyWebViewClient());
效果如下
返回
但是,我们进入到这个页面再返回,又出现了一个问题,请看下图。
很容易发现,它并没有后退到上一个页面,而是直接退出了。所以这个时候,我们需要对按键进行一个判断。判断方法也非常简单,就是按下的是否为返回键并且能够后退到上一个页面。条件成立则执行返回到上一个页面,条件不成立则直接退出。
同时网页的前进与后退,也有 6 种方法可以选择
- webview.canGoBack() 能否后退到上一个页面
- webview.goBack() 后退到上一个页面
- webview.canGoForward() 前进到下一个页面
- webview.goForward() 前进到下一个页面
- webview.canGoBackOrForward(int steps) 能否后退或者前景到第几个页面,后退为负值,前进为正值
- webview.GoBackOrForward(int steps) 后退或者前景到第几个页面,后退为负值,前进为正值
在 WebViewActivity 中重写 onKeyDown 方法,重新判端,按下返回键的操作。
/**
* 设置返回值,防止直接返回
* @param keyCode
* @param event
* @return
*/
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
// 如果按下了返回键,并且能够返回到上一级目录
if(keyCode == KeyEvent.KEYCODE_BACK && webView.canGoBack()) {
// 可以返回到上一级的目录
webView.goBack();
return true;
}
// 退出
return super.onKeyDown(keyCode, event);
}
运行效果如下
其它高级设置
以上问题解决了,我们可以获取进度条来显示网页加载的情况,以及设置标题,将原来的 AndroidLayout 标题进行一个替换。
要做到这种效果,还是要写一个类,类名为 MyWebChromeClient ,该类需要继承自 WebChromeClient,重写它的两个方法就能够实现以上的功能了。
重写的两个方法,分别如下:
- onProgressChanged 加载进度,创建一个 ProgressBar 这个组件就可以去实现
- onReceivedTitle 得到的标题,直接使用父类的 setTitle 方法,对标题进行设置
在此之前,先添加一个进度条的组件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!-- 进度条 -->
<ProgressBar
style="@android:style/Widget.ProgressBar.Horizontal"
android:id="@+id/progress"
android:layout_width="match_parent"
android:layout_height="3dp"
android:max="100"/>
<WebView
android:id="@+id/web_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
对应的Java代码
package top.bestguo.androidlayout;
import android.graphics.Bitmap;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.webkit.WebChromeClient;
import android.webkit.WebResourceRequest;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.ProgressBar;
public class WebViewActivity extends AppCompatActivity {
private WebView webView;
// 声明了一个进度条组件
private ProgressBar progressBar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_web_view);
progressBar = (ProgressBar) findViewById(R.id.progress);
webView = (WebView) findViewById(R.id.web_view);
// 允许 javascript
webView.getSettings().setJavaScriptEnabled(true);
// 加载本地的 html 文件
// webView.loadUrl("file:///android_asset/index.html");
webView.loadUrl("https://www.bestguo.top");
webView.setWebViewClient(new MyWebViewClient());
webView.setWebChromeClient(new MyWebChromeClient());
}
......
// 新建了一个内部类,继承自 webchromeclient 类
private class MyWebChromeClient extends WebChromeClient {
@Override
public void onProgressChanged(WebView view, int newProgress) {
super.onProgressChanged(view, newProgress);
// 设置进度的状态
progressBar.setProgress(newProgress);
Log.d("loading", newProgress + "");
}
@Override
public void onReceivedTitle(WebView view, String title) {
super.onReceivedTitle(view, title);
setTitle(title);
}
}
......
}
运行效果如下
后记
项目的代码都在 AndroidStudy 的 github 仓库中。
KeyEvent 对应的事件,请参考 https://www.cnblogs.com/hujingnb/p/10282238.html
请勿发布违反中国大陆地区法律的言论,请勿人身攻击、谩骂、侮辱和煽动式的语言。