2012年8月2日木曜日

WebViewのエラー画面をカスタマイズする

チームEggの赤峰です。

さて、本日はWebViewの話です。
動的更新が発生するページなどは、WebViewを利用することで
外部に用意したWebページとして表示させることができます。

しかし、WebViewをアプリの一部として自然に表示させるにはカスタマイズが必要です
今回は、以下の2点について調整していきます。
①ページ読み込み時の表示
②ページ取得不可時のエラーページ表示
読み込み中の画面は白画面なので省略します。

ネイティブアプリに近付けるために以下の変更を行います。
①ページ読み込み時の表示
⇒ 読み込みスピナ表示
②ページ取得不可時のエラーページ表示
⇒ 通信エラー画面用View表示
では、レイアウトXMLとコードを作成します。
まずは、WebView、スピナ、エラーページViewを含むレイアウトです。
activity_webview_with_spinner.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/white" >
    <WebView
        android:id="@+id/webview_main"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:fadeScrollbars="false"
        android:fadingEdge="vertical"
        android:scrollbarAlwaysDrawVerticalTrack="true" />
    <TextView
        android:id="@+id/webview_error_page"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/white"
        android:text="ページの取得に失敗しました"
        android:textColor="@android:color/black"
        android:textSize="20dp"
        android:visibility="gone" />
    <ProgressBar
        android:id="@+id/loading_spinner"
        style="@android:style/Widget.ProgressBar.Inverse"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:indeterminate="true"
        android:visibility="gone" />
</FrameLayout>

次に、WebView表示用のアクティビティです。
WebViewActivity.java
public class WebViewActivity extends Activity {

    /** WebView */
    private WebView mWebView;
    /** スピナ */
    private View mLoadingSpinner;
    /** エラーページ */
    private View mErrorPage;

    /** ページ取得失敗判定 */
    private boolean mIsFailure = false;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_webview_with_spinner);
        mIsFailure = false;
        mLoadingSpinner = findViewById(R.id.loading_spinner);
        mWebView = (WebView) findViewById(R.id.webview_main);
        mWebView.setWebViewClient(this.mWebViewClient);
        mErrorPage= findViewById(R.id.webview_error_page);
        mWebView.post(new Runnable() {
            @Override
            public void run() {
                mWebView.getSettings().setJavaScriptEnabled(true);
                mWebView.getSettings().setJavaScriptCanOpenWindowsAutomatically(false);
                mWebView.loadUrl("http://www.google.com");
            }
        });
    }

    /** WebViewClientクラス */
    private WebViewClient mWebViewClient = new WebViewClient() {
        /**
         * @see android.webkit.WebViewClient#onPageStarted(android.webkit.WebView, java.lang.String, android.graphics.Bitmap)
         */
        @Override
        public void onPageStarted(WebView view, String url, Bitmap favicon) {
            super.onPageStarted(view, url, favicon);
            mLoadingSpinner.setVisibility(View.VISIBLE);
            mWebView.setVisibility(View.GONE);
            mErrorPage.setVisibility(View.GONE);
        }

        /**
         * @see android.webkit.WebViewClient#onPageFinished(android.webkit.WebView, java.lang.String)
         */
        @Override
        public void onPageFinished(WebView view, String url) {
            super.onPageFinished(view, url);
            if (mIsFailure) {
                mErrorPage.setVisibility(View.VISIBLE);
            } else {
                mErrorPage.setVisibility(View.GONE);
            }
            mWebView.setVisibility(View.VISIBLE);
            mLoadingSpinner.setVisibility(View.GONE);
        }

        @Override
        public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
            mIsFailure = true;
        }
    };

    /**
     * {@inheritDoc}
     */
    @Override
    public void onBackPressed() {
        // Back出来る場合、WebViewのBackを実行
        if (mWebView != null && mWebView.canGoBack()) {
            mWebView.goBack();
        } else {
            super.onBackPressed();
        }

    }

}

レイアウトXMLに定義した、WebView、スピナ、エラー画面Viewをinflateします。
各Viewの表示状態を変更するためにWebViewClientで3つのメソッドをオーバーライドします。
 ①onPageStarted…ページ読み込み時に実行
 ②onRecivedError…ページ取得エラー時に実行。
  ※エラーが発生した場合のみ②の後に③が呼ばれます。
 ③onPageFinished…読み込み完了時に実行

各処理内容を見ていきます。
①onPageStarted
スピナを表示状態にし、WebViewとエラー画面Viewは非表示にします。
public void onPageStarted(WebView view, String url, Bitmap favicon) {
    super.onPageStarted(view, url, favicon);
    mLoadingSpinner.setVisibility(View.VISIBLE);
    mWebView.setVisibility(View.GONE);
    mErrorPage.setVisibility(View.GONE);
}
②onRecivedError
エラー用のフラグをtrueにします。
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
    mIsFailure = true;
}
③onPageFinished
スピナを非表示にし、WebViewを表示状態にします。
エラーページ画面は、②のフラグの状態で可視状態を設定しています。
public void onPageFinished(WebView view, String url) {
    super.onPageFinished(view, url);
    if (mIsFailure) {
        mErrorPage.setVisibility(View.VISIBLE);
    } else {
        mErrorPage.setVisibility(View.GONE);
    }
    mWebView.setVisibility(View.VISIBLE);
    mLoadingSpinner.setVisibility(View.GONE);
}

コードは簡略化しているので再読み込みを行う場合等はカスタマイズが必要です。
WebViewのバックキー制御とスピナ―変更については次回記載します。

0 件のコメント:

コメントを投稿