我們定義這個版本爲1.0版本。
首先,因爲要製作一個瀏覽器,那麼就不能通過調用內置瀏覽器來實現網頁的瀏覽功能,但是可以使用WebView組件來進行。
在此之前,我們可以來看看兩種網頁顯示方式:
1. Intent調用內置瀏覽器
Uri uri = Uri.parse("http://www.baidu.com");
Intent launchBrowser = new Intent(Intent.ACTION_VIEW, uri);
startActivity(launchBrowser);
代碼片段10.1.1 Intent調用顯示網頁
2. WebView顯示網頁
<WebView
android:id="@+id/web_holder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
代碼片段10.1.2 WebView設置在layout佈局文件中
WebView webHolder = (WebView) this.findViewById(R.id.web_holder);
webHolder.loadUrl("http://www.baidu.com");
代碼片段10.1.3 WebView調用顯示
以上就是兩種調用方式,現在我們通過WebView來簡單的實現網頁顯示的功能。
我們先添加一個WebView給Activity,不過需要注意的是,如果想要調用本應用程序的WebView來顯示網頁,則需要重寫webViewClienet,而且在之前先要進行編碼的設置,大致如下:
package com.example.androidstudy_web;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
public class MainActivity extends Activity {
private WebView webHolder;
private WebSettings settings;
private WebViewClient client;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.webHolder = (WebView) this.findViewById(R.id.web_holder);
this.settings = this.webHolder.getSettings();
this.client = new OwnerWebView();
this.settings.setDefaultTextEncodingName("UTF-8");
this.webHolder.setWebViewClient(this.client);
this.webHolder.loadUrl("http://www.baidu.com");
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
private class OwnerWebView extends WebViewClient{
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
}
}
代碼片段10.1.4 簡單的瀏覽器
基本的功能做完了,這個瀏覽器現在能做的就是顯示一個百度頁面,而我們不能更改。那麼接下來的工作就是給它添加一個地址輸入欄了。
我們可以設置一個LinerLayout,作爲導航,裏面包括地址欄和一個按鈕,我們可以添加按鈕監聽事件,當點擊的時候進行地址載入,當然,這個地址得進行檢測:
private class ButtonClickedListener implements OnClickListener{
@Override
public void onClick(View v) {
if(v.getId()==R.id.web_url_goto){
String url = webUrlStr.getText().toString();
if(URLUtil.isNetworkUrl(url)&&URLUtil.isValidUrl(url)){
webHolder.loadUrl(url);
}else{
new AlertDialog.Builder(MainActivity.this)
.setTitle("警告")
.setMessage("不是有效的網址")
.create()
.show();
}
}
}
}
代碼片段10.1.5 按鈕事件監聽
<EditText
android:id="@+id/web_url_input"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="0.8"
android:hint="@string/webUrlHint"
android:inputType="textUri"
/>
<Button
android:id="@+id/web_url_goto"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="0.2"
android:text="@string/webUrlGoto"
/>
代碼片段10.1.6 導航欄
需要注意的是地址欄的inputType設置,因爲我們需要輸入的是一個網址,所以這裏的輸入類型需要更改爲textUri
現在基本功能已經做好,在這個基本功能的基礎上,我們可以進行一些完善。
比如:
1. 在輸入地址的情況下,具有自動提示的功能
2. 在輸入的構成中判斷地址的有效性,有效按鈕爲“進入”,無效爲“取消”
要實現這個其實還是比較簡單的,就是監聽輸入的改變情況,來驗證地址的有效性,以此判斷按鈕是否爲“進入”狀態。
實現這個需要實現TextWatcher接口:
/**
* TextWatcher自定義繼承類
* 覆蓋方法如下:
* 1. afterTextChanged
* 2. beforeTextChanged
* 3. onTextChanged
* 實現更改地址的時候進行地址合法性檢測
* */
private class WebUrlStrChangedListener implements TextWatcher{
@Override
public void afterTextChanged(Editable editable) {
}
@Override
public void beforeTextChanged(CharSequence charsequence, int i, int j,
int k) {
}
@Override
public void onTextChanged(CharSequence charsequence, int i, int j, int k) {
url = charsequence.toString();
if(!(url.startsWith("http://")||url.startsWith("https://"))){
url = "http://"+url;
}
Log.d(DEG_TAG,"onchangeText:"+url);
if(URLUtil.isNetworkUrl(url)&&URLUtil.isValidUrl(url)){
//改變按鈕的函數實現
changeStatueOfWebGoto(true);
}else{
changeStatueOfWebGoto(false);
}
}
}
代碼片段10.1.7 TextWacher實現類
3. 找不到網站的時候就以百度爲默認搜索,進行搜索
這個功能,因爲需要判斷是否能找到網站,所以我通過異常的處理來進行這個操作,當出現無法找到網頁的時候,它就會返回一個errorCode,這個errorCode的所有值都爲負數,而無法找到網頁的錯誤代號爲-2,所以判斷返回的errorCode是否等於-2,如果相等,則將輸入的內容作爲搜索關鍵字處理。
關鍵代碼:
if(errorCode==WebViewClient.ERROR_HOST_LOOKUP){
//找不到頁面,調用百度搜搜
url = "http://www.baidu.com/baidu?word=" + url;
Log.d(DEG_TAG, "errorRedirect:"+url);
webHolder.loadUrl(url);
}
代碼片段10.1.8 找不到頁面,調用百度搜索
這個監控的是通過繼承WebViewClient,然後覆蓋裏面的onReceivedError方法進行實現。
4. 按物理返回鍵返回前一個頁面,按兩次退出
在Activity中,自己默認有一個onBackPressed方法,這個方法是用來實現按物理返回鍵的方法的,其實可以通過覆蓋keydown的方法來實現,不過這個更改好些。
@Override
public void onBackPressed() {
//判斷是否可後退,是則後退,否則按兩次退出程序
if(webHolder.canGoBack()){
webHolder.goBack();
//更改其他按鈕狀態(不妨礙物理返回效果的實現)
//changeStatueOfWebToolsButton();
}else{
if(!isExit){
isExit = true;
Toast.makeText(getApplicationContext(), "再按一次退出程序",
Toast.LENGTH_SHORT).show();
handler.sendEmptyMessageDelayed(0,2000);
}else{
finish();
System.exit(0);
}
}
}
代碼片段10.1.9 實現返回效果
5. 完成加載後自動隱藏地址欄
在WebViewClient繼承類中的onPageFinished方法可以實現
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
//隱藏地址欄
webUrlLayout.setVisibility(View.GONE);
//更改其他按鈕狀態(不妨礙影藏地址欄實現)
//changeStatueOfWebToolsButton();
}
代碼片段10.1.10 實現隱藏工具欄
6. 頁面加載後向上滑動到頂部顯示地址欄,向下滑動到底部,隱藏地址欄
因爲這個設計到了手勢的運用,爲了方便的管理手勢,Android其實已經提供了一個類,能夠自動識別獲取到的手勢,這個類就是GestureDetector:
/**
* GestureDetector.OnGestureListener自定義繼承類
* 解決各種手勢的相對應策略
* 1. 向上滑動webView到頂觸發事件,顯示地址欄
* 2. 向下滑動webView觸發時間,隱藏地址欄
* */
private class GestureListener implementsGestureDetector.OnGestureListener{
@Override
public boolean onDown(MotionEvent e) {
return false;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,float velocityY) {
if(webHolder.getScrollY()==0){
//滑倒頂部
webUrlLayout.setVisibility(View.VISIBLE);
}
if(webHolder.getScrollY()>0){
//滑倒底部
webUrlLayout.setVisibility(View.GONE);
}
return true;
}
@Override
public void onLongPress(MotionEvent e) {
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX, float distanceY) {
return false;
}
@Override
public void onShowPress(MotionEvent e) {
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
return false;
}
}
代碼片段10.1.11 GestureDirector.OnGestureListener實現
已經實現了手勢識別的方法,那麼現在只需要獲取手勢,並且將獲取到的交給手勢識別類(即上述的GestureDirector)識別即可。
手勢是對於webView這個組件來說的,所以只需要這個組件添加了OnTouchListener方法即可,這個方法會獲取到手勢產生的事件:
/**
* OnTouchListener自定義繼承類
* 解決將手勢交給GestureDetector類解決
* */
private class WebViewTouchListener implements OnTouchListener{
@Override
public boolean onTouch(View v, MotionEvent event) {
if(v.getId()==R.id.web_holder){
return mGestureDetector.onTouchEvent(event);
}
return false;
}
}
代碼片段10.1.12 獲取手勢事件
註釋:mGestureDetector即爲代碼偏單10.1.11中的類的實例
7. 添加刷新功能
這個較爲簡單,只需要將當前的url地址重新加載就行:
else if(v.getId()==R.id.tools_normal_refresh){
//刷新
if(!(url.equals("")&&url.equals("http://"))){
webHolder.loadUrl(url);
}
}
代碼片段10.1.12-1 refresh功能
8. 添加進度條
爲了美觀,我並沒有採用系統的進度條,而是自己創建了一個進度條,並且在webChromeClient的onProgressChanged方法中同步進度。
/**
* WebChromeClient自定義繼承類
* 覆蓋如下方法
* 1. onProgressChanged
* 用來解決進度條顯示問題
* */
private class OwnerChromeClient extends WebChromeClient{
@Override
public void onProgressChanged(WebView view, int newProgress) {
super.onProgressChanged(view, newProgress);
//MainActivity.this.setProgress(newProgress* 100);
if(newProgress==100){
webProgressBar.setVisibility(View.GONE);
}else{
webProgressBar.setVisibility(View.VISIBLE);
webProgressBar.setProgress(newProgress);
}
}
}
代碼片段10.1.13 進度條同步
9. 設置點擊鏈接,設置地址欄地址
這個功能在頁面加載的時候,可以通過一個覆蓋函數,在webViewClient中進行操作
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
//設置地址欄地址
webUrlStr.setText(url);
webUrlLayout.setVisibility(View.GONE);
//在每次頁面加載完成後查看是否有可以回溯的歷史
changeStatueOfWebToolsButton();
}
代碼片段10.1.14 頁面加載完成後設置地址欄
10. 設置向前向後按鈕,無則灰色
因爲按鈕的不同狀態圖片也不相同,這個時候就需要使用selector標籤,如下:
<?xml version="1.0"encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"android:drawable="@drawable/next_button_keydown"></item>
<item android:state_enabled="false"android:drawable="@drawable/next_button_unavailable"></item>
<item android:drawable="@drawable/next_button_normal"></item>
</selector>
代碼片段10.1.15 按鈕的三態
註釋:state_pressed表示按鈕按下的狀態時候爲真,則顯示drawable中的資源,其他兩個也是相同;enabled可使用爲假時,進行引用等
/**
* 設置工具欄回溯歷史是否可用
* */
private void changeStatueOfWebToolsButton(){
if(webHolder.canGoBack()){
//設置可使用狀態
preButton.setEnabled(true);
}else{
//設置禁止狀態
preButton.setEnabled(false);
}
if(webHolder.canGoForward()){
//設置可使用狀態
nextButton.setEnabled(true);
}else{
//設置禁止狀態
nextButton.setEnabled(false);
}
}
代碼片段10.1.16 設置工具欄中的回溯歷史的按鈕
11. 工具欄功能實現,包括總工具窗口顯示實現,主頁返回實現
這個通過popupwindow和tabActivity結合來實現:
基本的:
private void initTab(){
this.toolsTabView = this.toolsTabInflater.inflate(R.layout.tabactivity_tools,null);
this.toolsTab = (TabHost) this.toolsTabView.findViewById(android.R.id.tabhost); //獲取tabhost
this.toolsTab.setup(); //使用findViewById()加載tabhost時在調用addTab前必須調用
this.toolsTab.addTab(this.toolsTab.newTabSpec("normal").setIndicator("常用").setContent(R.id.tools_normal));
this.toolsTab.addTab(this.toolsTab.newTabSpec("setttings").setIndicator("設置").setContent(R.id.tools_settings));
this.toolsTab.addTab(this.toolsTab.newTabSpec("tool").setIndicator("工具").setContent(R.id.tools_tool));
this.toolsTab.setCurrentTab(0); //設置默認選種標籤
}
代碼片段10.1.17 實現tab
/**
* 構造函數
* @param context Context
* @param width int
* @param height int
* */
public ToolsPopWindow(Contextcontext, int width, int height){
super(context);
this.context = context;
this.toolsTabInflater = LayoutInflater.from(this.context);
//創建標籤
this.initTab();
//設置默認選項
setWidth(width);
setHeight(height);
setContentView(toolsTab);
setOutsideTouchable(true);
setFocusable(true);
}
代碼片段10.1.8 popupWindow實現
基本的瀏覽器功能已經實現。
代碼:
PS:轉載請註明出處謝謝!