生成长图的两种方法
一、第一种
public static String webViewShots(WebView webView) {
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
ToastUtil.showShort("aaaaabbbbaaaa");
Looper.loop();
}
}).start();
// WebView 生成长图,也就是超过一屏的图片,代码中的 longImage 就是最后生成的长图
webView.measure(View.MeasureSpec.makeMeasureSpec(View.MeasureSpec.UNSPECIFIED,
View.MeasureSpec.UNSPECIFIED),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
webView.layout(0, 0, webView.getMeasuredWidth(), webView.getMeasuredHeight());
webView.setDrawingCacheEnabled(true);
webView.buildDrawingCache();
Bitmap longImage = Bitmap.createBitmap(webView.getMeasuredWidth(), webView.getMeasuredHeight(),
Bitmap.Config.ARGB_8888);
// 画布的宽高和 WebView 的网页保持一致
Canvas canvas = new Canvas(longImage);
canvas.getMaximumBitmapHeight();
Paint paint = new Paint();
canvas.drawBitmap(longImage, 0, webView.getMeasuredHeight(), paint);
webView.draw(canvas);
String path = null;
try {
// 获取内置SD卡路径
String sdCardPath = Environment.getExternalStorageDirectory().getPath();
// 图片文件路径
String imageName = "wcd_webView_screenshot_" + System.currentTimeMillis() + ".png";
String filePath = sdCardPath + File.separator + "wcd";
path = filePath + File.separator + imageName;
File file = new File(filePath);
if (!file.exists()) {
boolean mkdirs = file.mkdirs();
if (!mkdirs) {
return null;
}
}
FileOutputStream fos = new FileOutputStream(new File(filePath, imageName));
//压缩bitmap到输出流中
longImage.compress(CompressFormat.PNG, 100, fos);
fos.close();
longImage.recycle();
} catch (Exception e) {
Log.e(TAG, e.getMessage());
}
return path;
}
二、第二种
public static String getSnapshot(WebView webView) {
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
ToastUtil.showShort("aaaaabbbbaaaa");
Looper.loop();
}
}).start();
String fileName = null;
Picture picture = webView.capturePicture();
int width = picture.getWidth();
int height = picture.getHeight();
if (width > 0 && height > 0) {
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
picture.draw(canvas);
try {
fileName = Environment.getExternalStorageDirectory().getPath()+"/webview_capture1.jpg";
FileOutputStream fos = new FileOutputStream(fileName);
//压缩bitmap到输出流中
bitmap.compress(Bitmap.CompressFormat.JPEG, 70, fos);
fos.close();
bitmap.recycle();
} catch (Exception e) {
Log.e(TAG, e.getMessage());
}
}
return fileName;
}
截屏是耗时操作所以用到Callable
public Callable<Bitmap> getViewBitmapThree() {
final Picture picture = webView.capturePicture();
final int width = picture.getWidth();
final int height = picture.getHeight();
return new Callable<Bitmap>() {
@Override
public Bitmap call() throws Exception {
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
picture.draw(canvas);
return bitmap;
}
};
}
runnable和Callable的区别
两者最大的不同点是:实现Callable接口的任务线程能返回执行结果;而实现Runnable接口的任务线程不能返回结果;
Callable接口的call()方法允许抛出异常;而Runnable接口的run()方法的异常只能在内部消化,不能继续上抛;
耗时的时候要弹框dialog(先弹加载框再弹截屏框)
private void getDateBitmap(){
final Callable<Bitmap> captureCallable = mWebViewWrapper.getViewBitmapThree();
Observable.fromCallable(captureCallable)
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.map(new Function<Bitmap, String>() {
private String fileName;
@Override
public String apply(@NonNull Bitmap bitmap) throws Exception {
try {
fileName = Environment.getExternalStorageDirectory().getPath()+"/webview_capture1.jpg";
FileOutputStream fos = new FileOutputStream(fileName);
//压缩bitmap到输出流中
bitmap.compress(Bitmap.CompressFormat.JPEG, 70, fos);
fos.close();
bitmap.recycle();
} catch (Exception e) {
Log.e(TAG, e.getMessage());
}
return fileName;
}
})
.doOnSubscribe(new Consumer<Disposable>() {
@Override
public void accept(Disposable disposable) throws Exception {
showLoading(true);
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new DisposableObserver<String>() {
@Override
protected void onStart() {
}
@Override
public void onNext(@NonNull String file) {
if (!TextUtils.isEmpty(file)) {
ScreenDialog screenDialog = ScreenDialog.newInstance(context, file);
screenDialog.show(getSupportFragmentManager(), TAG, true);
}
}
@Override
public void onComplete() {
showLoading(false);
}
@Override
public void onError(@NonNull Throwable e) {
}
});
}
完全仿微博(先弹出加载的默认图片,默认图片上面有加载中的dialog,加载中的dialog消失,默认图片变成截屏的图片)
- 点击事件先弹框
ScreenTwoDialog screenDialog1 = ScreenTwoDialog.newInstance(context,mWebViewWrapper);
screenDialog1.show(getSupportFragmentManager(), TAG, true);
- rxjava请求截屏带进度框dialog
private void getDateBitmap(){
final Callable<Bitmap> captureCallable = webViewWrapperTwo.getViewBitmapThree();
Observable.fromCallable(captureCallable)
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.map(new Function<Bitmap, String>() {
private String fileName;
@Override
public String apply(@NonNull Bitmap bitmap) throws Exception {
try {
fileName = Environment.getExternalStorageDirectory().getPath()+"/webview_capture1.jpg";
FileOutputStream fos = new FileOutputStream(fileName);
//压缩bitmap到输出流中
bitmap.compress(Bitmap.CompressFormat.JPEG, 70, fos);
fos.close();
bitmap.recycle();
} catch (Exception e) {
Log.e(TAG, e.getMessage());
}
return fileName;
}
})
.doOnSubscribe(new Consumer<Disposable>() {
@Override
public void accept(Disposable disposable) throws Exception {
if (dialog==null) {
dialog = LoadingWcdDialog.newInstance();
}
dialog.show(getFragmentManager(), dialog.getClass().getName(),true);
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new DisposableObserver<String>() {
@Override
protected void onStart() {
}
@Override
public void onNext(@NonNull String file) {
iv_screen.setImage(ImageSource.uri(file));
}
@Override
public void onComplete() {
dialog.show(getFragmentManager(),dialog.getClass().getName(),false);
}
@Override
public void onError(@NonNull Throwable e) {
}
});
}
注意事项
- 仿微博的xml里面imageview要添加默认图片
- 关闭弹框的时候webview页面会卡住,重写刷新H5页面webView.reload();