WebViewClientおよび/またはWebChromeClientを使用すると、ページが読み込まれたときにリスナーを取得できますが、WebViewにコンテンツが表示される前にコンテンツが呼び出される前に呼び出されることがあります。
WebViewがコンテンツをいつ表示したかを判断するための効率的な方法は何でしょうか?
編集:(より明確にしようとしています)
WebViewでページをロードするときに、スクロールを特定の位置に設定したい。ページがロードされ、実際のコンテンツの高さが設定されるまで、スクロール位置は設定できないようです。そのため、ページのロードがいつ完了するかを判断するために、WebViewClientのonPageFinished()とWebChromeClientのonProgressChanged()の2つの異なる方法を試しました。これらの両方は、ページの読み込みが完了したときに通知します。
ただし、問題は、ページが表示される前に呼び出されることがあるため、ページに高さがなく、スクロール呼び出しが何もしないことです。
私は、ページをスクロールする準備ができたときを判断するための確実な方法を見つけようとしています。コンテンツの高さがあるとき。
ロードが完了した後にチェックループを設定して、高さがいつ利用可能かを探し続けることができると思いますが、それはかなりハックのように思えました。よりクリーンな方法があることを願っています。
PictureListenerを使用したRichardの回答 を数年間使用しましたが、これを最良のソリューションとして推奨しなくなりました。
これには2つの理由があります。
代わりに、WebViewのサブクラスを作成し、次のようにinvalidate()をオーバーライドすることをお勧めします。
@Override
public void invalidate() {
super.invalidate();
if (getContentHeight() > 0) {
// WebView has displayed some content and is scrollable.
}
}
PictureListenerメソッドを引き続き使用する場合は、PictureListenerメソッドを使用した後にPictureListenerをnullに戻すと、パフォーマンスが向上します。
編集:私が最初にこれを投稿して以来、このメソッドはAndroid API 12.で非推奨になりました。
はい-ISコンテンツの読み込みが完了したことを知るためのリスナー。WebViewがページを読み込むまでスプラッシュ画面を維持できるように、プロジェクトで作成する必要がありました。 。
.setPictureListenerと呼ばれます。
例えば:
mWebView.setPictureListener(new MyPictureListener());
//... and then later on....
class MyPictureListener implements PictureListener {
@Override
public void onNewPicture(WebView view, Picture arg1) {
// put code here that needs to run when the page has finished loading and
// a new "picture" is on the webview.
}
}
ここで提案されている解決策はせいぜいハックですが、完全にクリーンな解決策があります Android docs :
WebViewClient client = new WebViewClient() {
@Override
public void onPageFinished(WebView view, String url) {
Log.d("MYAPP", "Page loaded");
}
};
webView.setWebViewClient(client);
私はこの議論を読みましたが、私も同じ問題に直面しています。
私はよく検索しましたが、彼らが約束する解決策ではありません。
そして、非推奨の `onNewPicture`コールバックを使いたくありません。
私自身の状況では、アクティビティが開始されたときに `WebView`スクロール位置を復元するだけでよく、アクティビティタスクスタックがバックグラウンドになったとき、これがほとんどの場合だと思いますAndroid 「WebView」状態を保存して、フォアグラウンドにポップしたときに同じように表示されるようにします。バックグラウンドで削除された場合は、「onPause」などのアクティビティライフサイクルメソッドで状態を保存できます。
そのため、「WebView」を拡張して、何とか、何とか、何とかをオーバーライドする代わりに、ハンドラーとポストモデルを使用します。
private final Handler mHandler = new Handler();
// in onCreate
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
if (mWebView.getContentHeight() > 0) {
mWebView.scrollTo(0, mLastPosition);
Log.d("scrolling", "true");
mHandler.removeCallbacks(this);
} else {
mHandler.postDelayed(this, 100);
}
}
}, 100);
このコードブロックは、WebViewページを操作できるかどうかを定期的にチェックします。操作できる場合は、スクロールしてコールバックを削除します。そうでない場合はループします。私はこれをテストし、通常はそれほど長くかからないことを見つけます。
お役に立てれば!
「onSizeChanged」メソッドをオーバーライドするWebViewを拡張するカスタムビューを作成しました。 onViewChangedは、webviewがその中にすべてをロードした後に発生します。
これは、質問に対する直接的な回答ではありませんが、代わりにWebChromeClientを使用できます。私はそれをより信頼できると感じ、ロードの進行状況を表示するように構成しました。ページが完全に読み込まれる前にProgressViewを非表示にするWebViewで同じ問題が発生し、WebViewをWebViewクライアントに置き換えました。
私は次のコードを使用します
final WebView wvMax = (WebView) findViewById(R.id.webViewTnSmax);
final ProgressBar pbMax = (ProgressBar) findViewById(R.id.progressBarTnSmax);
wvMax.setWebChromeClient(new WebChromeClient() {
public void onProgressChanged(WebView view, int progress) {
pbMax.setVisibility(View.VISIBLE);
pbMax.setProgress(progress);
if (progress == 100) {
pbMax.setVisibility(View.GONE); // Make the bar disappear after URL is loaded
}
}
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
// do something
}
});
私はその古いことを知っていますが、それは助けることができます、ここでの答えは完全に機能していません、私が見つけた最高は拡張WebViewでonDrawをオーバーライドすることです
@Override
protected void onDraw(Canvas canvas) {
//do your math/stuff/magic/blackmagic/hackish here
super.onDraw(canvas);
}
すべてのフォントをスクロールダウン/アップするたびに
ほぼすべて(すべてテスト済み)がonDrawを呼び出します
私はこれを使ってSeekBarを垂直スクロールバーとして使用します
;)
nullかどうかをチェックし、無駄なメソッド呼び出しを避けるために他のいくつかを追加することが重要です
OnDrawメソッドをオーバーライドするカスタムビューを作成し、独自のリスナーを呼び出すこの問題を修正しました。これはコードです:
public class CustomWebView extends WebView{
public interface FinishedDrawListener{
void onDrawFinished(WebView view, String url);
}
private FinishedDrawListener drawListener;
public CustomWebView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
public CustomWebView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public CustomWebView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomWebView(Context context) {
super(context);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if(drawListener != null){
drawListener.onDrawFinished(this, this.getUrl());
}
}
public void setOnFinishedDrawListener(FinishedDrawListener listener){
this.drawListener = listener;
}
私はそれが最善の方法ではないと思いますが、私のアプリケーションでは機能します。
編集:このソリューションはもうお勧めしませんが、情報のためにここに残しておきます。
これが他の誰かに役立つ場合、私がこれを行うことになった方法は、WebViewをサブクラス化し、computeVeritcalScrollExtent()
メソッドをオーバーライドすることでした。
_@Override
protected int computeVerticalScrollExtent() {
// do you checking here
return super.computeVerticalScrollExtent();
}
_
これは、WebViewが垂直スクロールバーを計算するたびに呼び出されます。ただし、getContentHeight() > 0
の場所で最初に呼び出された場合は、コンテンツが初めて表示されます。
onLoadResource(WebView view, String url)
指定されたURLで指定されたリソースをWebViewがロードすることをホストアプリケーションに通知します。
目的が何であるかはまだ明確ではありませんが、試してみてください
public void doUpdateVisitedHistory (WebView view, String url, boolean isReload)
履歴に追加する前にページの読み込みが完了したと「想定」します...