问题
I want to snapshot the WebView after the WebView is loaded. However, the returned bitmap is always null because the render hasn't loaded completed even though I use onPageFinished
.
I search on Internet and people suggest to use WebView.PictureListener
, but this function is deprecated in API 12.
Some codes
public class MainActivity extends Activity {
private WebView mButterflyWebView;
/**
* Gets html content from the assets folder.
*/
private String getHtmlFromAsset() {
InputStream is;
StringBuilder builder = new StringBuilder();
String htmlString = null;
try {
is = getAssets().open(getString(R.string.butterfly_html));
if (is != null) {
BufferedReader reader = new BufferedReader(
new InputStreamReader(is));
String line;
while ((line = reader.readLine()) != null) {
builder.append(line);
}
htmlString = builder.toString();
}
} catch (IOException e) {
e.printStackTrace();
}
return htmlString;
}
/**
* Initializes views, controls...
*/
private void init() {
mButterflyWebView = (WebView) findViewById(R.id.butterfly_webview);
mButterflyWebView.setWebChromeClient(new WebChromeClient() {
public void onProgressChanged(WebView view, int newProgress) {
if (newProgress == 100){
if (capturePictureWebView() != null){
saveBitmapToFile(capturePictureWebView());
}
}
}
});
}
/**
* Loads html page with the content.
*/
private void loadHtmlPage() {
String htmlString = getHtmlFromAsset();
if (htmlString != null)
mButterflyWebView.loadDataWithBaseURL(
"file:///android_asset/images/", htmlString, "text/html",
"UTF-8", null);
else
Toast.makeText(this, R.string.no_such_page, Toast.LENGTH_LONG)
.show();
}
/**
* Called when the activity is first created.
*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
init();
loadHtmlPage();
}
private Bitmap capturePictureWebView() {
mButterflyWebView.measure(MeasureSpec.makeMeasureSpec(
MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED),
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
mButterflyWebView.layout(0, 0, mButterflyWebView.getMeasuredWidth(),
mButterflyWebView.getMeasuredHeight());
mButterflyWebView.setDrawingCacheEnabled(true);
mButterflyWebView.buildDrawingCache();
if (mButterflyWebView.getMeasuredWidth() == 0 || mButterflyWebView.getMeasuredHeight() == 0){
return null;
}
Bitmap bm = Bitmap.createBitmap(720, 1280, Bitmap.Config.ARGB_8888);
System.out.println("width=" + mButterflyWebView.getMeasuredWidth());
System.out.println("height=" + mButterflyWebView.getMeasuredHeight());
Canvas bigcanvas = new Canvas(bm);
// bigcanvas.scale(720/mButterflyWebView.getMeasuredWidth(), 1280/mButterflyWebView.getMeasuredHeight());
Paint paint = new Paint();
int iHeight = bm.getHeight();
bigcanvas.drawBitmap(bm, 0, iHeight, paint);
mButterflyWebView.draw(bigcanvas);
return bm;
}
private void saveBitmapToFile(Bitmap bitmap) {
try {
FileOutputStream out = new FileOutputStream("/storage/sdcard0/a.png");
bitmap.compress(Bitmap.CompressFormat.PNG, 90, out);
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
回答1:
You should try to use a WebChromeClient
and implement onProgressChanged
:
http://developer.android.com/reference/android/webkit/WebChromeClient.html#onProgressChanged(android.webkit.WebView, int)
mButterflyWebView.setWebChromeClient(new WebChromeClient() {
@Override
public void onProgressChanged(WebView view, int progress) {
if (progress == 100) {
// do screenshot
}
}
});
EDIT : to check if onPageStarted is loaded more than once :
mButterflyWebView.setWebViewClient(new WebViewClient() {
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
Log.d("WebView", "onPageStarted " + url);
}
@Override
public void onPageFinished(WebView view, String url) {
Log.d("WebView", "onPageFinished " + url);
}
});
回答2:
The best way to detect if a page has rendered is to use the onPageCommitVisible callback, available from API 23. onPageLoadFinished
is not suitable, since it's delivered too soon (when the HTML is processed, but not yet rendered).
webview.setWebViewClient(new WebViewClient() {
@Override
public void onPageCommitVisible (WebView view,
String url)
}
}
回答3:
You can do it like this, in your WebView:
@Override
public void invalidate() {
super.invalidate();
if (getContentHeight() > 0) {
// WebView has displayed some content and is scrollable.
}
}
Thanks to: https://stackoverflow.com/a/14678910/1310343
回答4:
Finally I got the very detailed for this problem. This explains why it always returns null bitmap.
Every change in my app are triggered by a user action so I came up with a modified version that only trigger invalidate() after a touchEvent
Thank for all your help.
Android WebView renders blank/white, view doesn't update on css changes or HTML changes, animations are choppy
回答5:
The renderer will not finish rendering when the OnPageFinshed method is called or the progress reaches 100% so both methods don't guarantee you that the view was completely rendered.
But you can figure out from OnLoadResource method what has been already rendered and what is still rendering. And this method gets called several times.
@Override
public void onLoadResource(WebView view, String url) {
super.onLoadResource(view, url);
// Log and see all the urls and know exactly what is being rendered and visible. If you wanna know when the entire page is completely rendered, find the last url from log and check it with if clause and implement your logic there.
if (url.contains("assets/loginpage/img/ui/forms/")) {
// loginpage is rendered and visible now.
// your logic here.
}
}
回答6:
private class CfdWebViewClient extends WebViewClient {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
Log.v(TAG, "shouldOverrideUrlLoading: " + url);;
return true;
}
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
Log.v(TAG, "onPageFinished: " + url);
// do something
}
}
来源:https://stackoverflow.com/questions/21000566/android-webview-detect-when-rendering-is-finished