借之前的文章開發(fā)一個新的組件,用于在 app 內(nèi)愉快的使用 webview蛙吏。
比如在微信里兄一,打開微信公眾號文章的時候,這里文章的內(nèi)容的渲染都是由 webview 控件完成的鸳惯,這比在瀏覽器里打開友善多了商蕴,并且功能更強大,可以調(diào)用外部程序芝发,識別二維碼绪商,支付等等。假如我們的 app 里有動態(tài)內(nèi)容辅鲸,會經(jīng)常在服務端編輯好頁面的方式更新格郁,那么使用 webview 展示是最好不過了。
之前的那篇文章中提到過独悴,可以動態(tài)傳遞對象到含有 webview 的 activity 頁面例书,因為這個 activity 每次只會打開一個實例,為了簡化對象的傳遞刻炒,用的是單例存儲要傳遞的對象决采,代碼參考如下:
public enum WebFrameSettings {
instance;
private String url;
private HashMap<String, Object> objs;
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public HashMap<String, Object> getObjs() {
return objs;
}
public void addObject(String key, Object val) {
objs.put(key, val);
}
public void clearObjects() {
objs.clear();
}
public void removeObject(String key) {
objs.remove(key);
}
WebFrameSettings() {
url = "";
objs = new HashMap<>();
}
}
接下來創(chuàng)建一個 activity,放置 Toolbar 坟奥、ProgressBar织狐、WebView 控件。
界面布局代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="me.xuzhi.webframemodule.WebFrameActivity">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbarWebFrameModule"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:background="@color/webFrameToolbarBackgroundColor"
android:titleTextColor="@color/webFrameToolbarForcegroundColor"
app:titleTextColor="@color/webFrameToolbarForcegroundColor">
</android.support.v7.widget.Toolbar>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentStart="true">
<WebView
android:id="@+id/webViewWebFrameModule"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/progressBar"/>
<ProgressBar
android:id="@+id/progressBarWebFrameModule"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="2dp"
android:progress="50"
android:progressDrawable="@drawable/progress_bar_webframe"/>
</FrameLayout>
</LinearLayout>
為這個模塊創(chuàng)建一個主題筏勒,否則 Toolbar 右上角的三個點都是黑色的移迫。
<resources>
<style name="ModuleTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:textColorSecondary">#ffffff</item>
</style>
</resources>
為 Toolbar 設置標題和返回圖標。
toolbarWebFrameModule.setTitle(WebFrameSettings.instance.getUrl());
toolbarWebFrameModule.setNavigationIcon(R.drawable.ic_action_arrow_back);
注意 setNavigationOnClickListener 一定要在 setSupportActionBar 之后調(diào)用管行,否則不生效厨埋。
setSupportActionBar(toolbarWebFrameModule);
toolbarWebFrameModule.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (webViewWebFrameModule.canGoBack()) {
webViewWebFrameModule.goBack();
} else finish();
}
});
為 Toolbar 增加菜單。
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".MainActivity">
<item
android:id="@+id/action_close"
android:icon="@drawable/ic_action_close"
android:title="關(guān)閉"
app:showAsAction="always"/>
<item
android:id="@+id/action_refresh"
android:title="刷新"
app:showAsAction="collapseActionView"/>
<item
android:id="@+id/action_share"
android:title="分享"
app:showAsAction="collapseActionView"/>
<item
android:id="@+id/action_copylink"
android:title="復制鏈接"
app:showAsAction="collapseActionView"/>
<item
android:id="@+id/action_openWithBrowser"
android:title="在瀏覽器中打開"
app:showAsAction="collapseActionView"/>
</menu>
重寫 activity 的 onCreateOptionsMenu 方法捐顷,將 menu 添加進來荡陷。
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_webframe, menu);
return true;
}
菜單按鈕的事件:
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_close) {
finish();
} else if (id == R.id.action_copylink) {
doCopyLink();
} else if (id == R.id.action_openWithBrowser) {
doOpenWithBrowser();
} else if (id == R.id.action_refresh) {
doRefresh();
} else if (id == R.id.action_share) {
doShare();
}
return true;
}
關(guān)于復制的問題雨效,ClipboardManager 的 setText 方法已經(jīng)過時了,應該換用 setPrimaryClip 方法废赞。
private void doCopyLink() {
try {
ClipboardManager cm = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clipData = ClipData.newPlainText("link", WebFrameSettings.instance.getUrl());
cm.setPrimaryClip(clipData);
Toast.makeText(getApplicationContext(), "復制鏈接成功", Toast.LENGTH_SHORT).show();
} catch (Exception ex) {
Toast.makeText(getApplicationContext(), "復制鏈接失敗", Toast.LENGTH_SHORT).show();
}
}
如果 webview 中需要 js 調(diào)用 java 方法徽龟,可以在單例添加對應的類,webview 在執(zhí)行 loadUrl 之前會檢查是否有對象值唉地。
HashMap<String, Object> invokeObjects = WebFrameSettings.instance.getObjs();
if (invokeObjects.size() > 0) {
Iterator iter = invokeObjects.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry entry = (Map.Entry) iter.next();
String key = entry.getKey().toString();
Object val = entry.getValue();
webViewWebFrameModule.addJavascriptInterface(val, key);
}
}
webview 的 onProgressChanged 和 onPageFinished 比較讓人頭疼据悔,因為加載某個資源出錯也會觸發(fā),所以只憑兩個方法判斷頁面加載完成還是不科學耘沼,這就導致加載進度條的什么時候結(jié)束很讓人糾結(jié)极颓。
整體效果:
這個模塊我已放到 github 上,戳 https://github.com/yahch/WebFrame
也可以直接在項目引用:
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
dependencies {
compile 'com.github.yahch:WebFrame:1.1'
}
Intent intent = new Intent(MainActivity.this, WebFrameActivity.class);
WebFrameSettings.instance.setUrl("http://weibo.cn");
startActivity(intent);