之前写过一版android屏幕截取的文章
最近也是整理了一下截屏的内容
直接来干货,直接上代码
这段截屏包含了两个部分,第一个view是当前页面,可以直接传入activity.getWindow().getDecorView(),也可以传入你想截屏部分的layout或者任意一个view;第二个view我这里是页面上浮现出了dialog,所以要把dialog画上去,一起截屏出来。
public static void captureView(View view, View dialogView, Context context) {
// 首先写入缓存
view.setDrawingCacheEnabled(true);
view.buildDrawingCache();
//没找到可以截取状态栏的办法,如果有人知道,可以告知一下本人。上面获取到的bitmap是包含顶部状态栏的,所以需要去掉。
int statusBarHeight = StatusBar.getStatusBarHeight(context);
//virtualHight是底部虚拟按键的高度,
int virtualHight = 0;
if (ScreenUtils.hasDeviceNavigationBar(context)) {
virtualHight = ScreenUtils.getBottomBarHeight(context);
}
// 减去状态栏和底部虚拟按键的高度
Bitmap bitmap = Bitmap.createBitmap(view.getDrawingCache(), 0, statusBarHeight, view.getWidth(), view.getHeight() - statusBarHeight - virtualHight);
//如果需要同时保存打开的dialog的截图,可以这么做,如果不需要,上面的bitmap就是当前activity的截图了。
int location[] = new int[2];
view.getLocationOnScreen(location);
int location2[] = new int[2];
dialogView.getLocationOnScreen(location2);
dialogView.setDrawingCacheEnabled(true);
dialogView.buildDrawingCache();
Bitmap bitmap2 = Bitmap.createBitmap(dialogView.getDrawingCache(), 0, 0, dialogView.getWidth(), dialogView.getHeight());
Canvas canvas2 = new Canvas(bitmap);
canvas2.drawBitmap(bitmap2, location2[0] - location[0], location2[1] - location[1], new Paint());
view.destroyDrawingCache();
dialogView.destroyDrawingCache();
saveImage2DCIM(bitmap, context);
}
/**
* 保存图片到相册
*
* @param bmp
* @param context
* @return
*/
public static File saveImage2DCIM(Bitmap bmp, Context context) {
File appDir = new File(Environment.getExternalStorageDirectory(), "DCIM/Camera/");
if (!appDir.exists()) {
appDir.mkdir();
}
String fileName = System.currentTimeMillis() + ".png";
File file = new File(appDir, fileName);
try {
FileOutputStream fos = new FileOutputStream(file);
bmp.compress(Bitmap.CompressFormat.PNG, 100, fos);
fos.flush();
fos.close();
Toast.makeText(context, "已成功保存到相册", Toast.LENGTH_SHORT).show();
MediaStore.Images.Media.insertImage(context.getContentResolver(), file.getAbsolutePath(), file.getName(), null);
Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
Uri uri = Uri.fromFile(file.getAbsoluteFile());
intent.setData(uri);
context.sendBroadcast(intent);
share(context, file);
return file;
} catch (FileNotFoundException e) {
e.printStackTrace();
Toast.makeText(context, "保存失败", Toast.LENGTH_SHORT).show();
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(context, "保存失败", Toast.LENGTH_SHORT).show();
}
return null;
}
再附上分享部分的代码
/**
* 分享多张照片
*
* @param context
* @param file
*/
public static void share(Context context, File file) {
Intent share_intent = new Intent();
Uri uri;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
uri = getImageContentUri(context, file);
// uri = FileProvider.getUriForFile(context, context.getApplicationContext().getPackageName() + ".fileProvider", file);
} else {
uri = Uri.fromFile(file);
}
share_intent.setAction(Intent.ACTION_SEND);//设置分享行为
share_intent.setType("image/*");//设置分享内容的类型
share_intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
// share_intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uri);
share_intent.putExtra(Intent.EXTRA_STREAM, uri);
context.startActivity(Intent.createChooser(share_intent, "分享"));
}
还有屏幕头部状态栏和底部虚拟按键的高度相关代码
获取底部虚拟按键的时候,请记得加个底部虚拟按键是否存在的判断
/**
* 获取状态栏高度
*
* @param context context
* @return 状态栏高度
*/
public static int getStatusBarHeight(Context context) {
// 获得状态栏高度
int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
return context.getResources().getDimensionPixelSize(resourceId);
}
/**
* 获取导航栏高度(如华为底部导航栏高度)
*
* @param context
* @return
*/
public static int getBottomBarHeight(Context context) {
int resourceId = 0;
int rid = context.getResources().getIdentifier("config_showNavigationBar", "bool", "android");
if (rid != 0) {
resourceId = context.getResources().getIdentifier("navigation_bar_height", "dimen", "android");
return context.getResources().getDimensionPixelSize(resourceId);
} else
return 0;
}
/**
* 获取是否有虚拟按键
* 通过判断是否有物理返回键反向判断是否有虚拟按键
*
* @param context
* @return
*/
public static boolean hasDeviceNavigationBar(Context context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
Display display = ((Activity) context).getWindowManager().getDefaultDisplay();
Point size = new Point();
Point realSize = new Point();
display.getSize(size);
display.getRealSize(realSize);
boolean result = realSize.y != size.y;
return realSize.y != size.y;
} else {
boolean menu = ViewConfiguration.get(((Activity) context)).hasPermanentMenuKey();
boolean back = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK);
if (menu || back) {
return false;
} else {
return true;
}
}
}
最后,不要忘记声明provider,并声明存储权限
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="{applicationid}.fileProvider"
android:exported="false"
android:grantUriPermissions="true"
tools:replace="name,authorities,exported,grantUriPermissions">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths"
tools:replace="name,resource" />
</provider>