1. 概述
该方法是通过View的方式获取当前activity的屏幕截图,并不是frameBuffer的方式,所以有一定的局限性。但是这种方法相对简单,容易理解。
2. 使用方法
- 对activity进行截图 12345678910111213141516171819202122232425262728293031323334353637/*** Activity screenCap** @param activity* @return*/public static Bitmap activityShot(Activity activity) {/*获取windows中最顶层的view*/View view = activity.getWindow().getDecorView();//允许当前窗口保存缓存信息view.setDrawingCacheEnabled(true);view.buildDrawingCache();//获取状态栏高度Rect rect = new Rect();view.getWindowVisibleDisplayFrame(rect);int statusBarHeight = rect.top;WindowManager windowManager = activity.getWindowManager();//获取屏幕宽和高DisplayMetrics outMetrics = new DisplayMetrics();windowManager.getDefaultDisplay().getMetrics(outMetrics);int width = outMetrics.widthPixels;int height = outMetrics.heightPixels;//去掉状态栏Bitmap bitmap = Bitmap.createBitmap(view.getDrawingCache(), 0, statusBarHeight, width,height-statusBarHeight);//销毁缓存信息view.destroyDrawingCache();view.setDrawingCacheEnabled(false);return bitmap;}
可以将得到的bitmap格式图片保存到本地,也可以用于其他用途。下面是将bitmap保存到本地的方法。
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465private static final String SCREENSHOTS_DIR_NAME = "screenShots";private static final String SCREENSHOT_FILE_NAME_TEMPLATE = "Screenshot%s.jpg";private static final String SCREENSHOT_FILE_PATH_TEMPLATE = "%s/%s/%s";/*** 存储到sdcard** @param bmp* @return*/public static String saveToSD(Bitmap bmp) {//判断sd卡是否存在if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {//文件名long systemTime = System.currentTimeMillis();String imageDate = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date(systemTime));String mFileName = String.format(SCREENSHOT_FILE_NAME_TEMPLATE, imageDate);File dir = new File(SCREENSHOTS_DIR_NAME);//判断文件是否存在,不存在则创建if (!dir.exists()) {dir.mkdirs();}//文件全名String mstrRootPath = Environment.getExternalStorageDirectory().toString();String mFilePath = String.format(SCREENSHOT_FILE_PATH_TEMPLATE, mstrRootPath,SCREENSHOTS_DIR_NAME, mFileName);Log.i(TAG, "file path:" + mFilePath);File file = new File(mFilePath);if (!file.exists()) {try {file.createNewFile();} catch (IOException e) {e.printStackTrace();}}Log.i(TAG, "file path:" + file.getAbsolutePath());FileOutputStream fos = null;try {fos = new FileOutputStream(file);if (fos != null) {//第一参数是图片格式,第二参数是图片质量,第三参数是输出流bmp.compress(Bitmap.CompressFormat.PNG, 100, fos);fos.flush();}} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {if (fos != null) {try {fos.close();} catch (IOException e) {e.printStackTrace();}}}return mFilePath;}return null;}注意在AndroidManifest.xml中注册写入的权限
1<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
3. 截图时遇到的坑
在程序中使用上面的方法进行应用内截图,结果出现了下面的错误提示:
马上要提交了出现这种坑,内心马上凌乱了。Google后发现,这个错误是由于使用这个方法造成的:
这是Bitmap.createBitmap(Bitmap source, int x, int y, int width, int height)
方法的介绍:
该方法返回的是source的子集,所以就要求:
- x + width <= source.width
- y + height <= source.height
由于我的程序中是直接使用的屏幕宽度,所以出现了上面的错误。说道屏幕宽度,就引出了我下面的资料查找。
4. Android 获取获取屏幕高度、标题高度、状态栏高度
该图片出自Android完美获取状态栏高度、标题栏高度、编辑区域高度的获取
- 最大的草绿色区域是屏幕区域
- 次大的红色区域是应用界面区域
- 最小的紫色区域是View绘制区域
- 屏幕顶端和应用界面顶端之间的部分为状态栏
- 应用界面顶端与view绘制区域顶端之间的部分为标题栏
1. 下面介绍一些获取屏幕参数的方法
1.View 获取屏幕参数值的方法:
方法 | 影响区域 | 说明 |
---|---|---|
onSizeChanged(int w,int h,int oldw,int oldh) | view绘制区域 | 当前view屏幕宽高发生变化时调用,传递view的宽高,其中高度不包括标题高度 |
getWidth() | view绘制区域 | 返回view的宽度 |
getHeight() | view绘制区域 | 返回view的高度,不包括标题在内 |
getWindowVisibleDisplayFrame(Rect outRect) | 应用界面区域 | 返回宽度和View的宽度相等,高度=view的高度 + 标题的高度 |
getDrawingRect(Rect outRect) | view绘制区域 | 返回绘制区域的区域值,宽度和高度都和view的相等 |
2.Canvas对象获取画布宽高,由view的draw函数传递canvas对象,也是在view中创建
方法 | 影响区域 | 说明 |
---|---|---|
canvas.getWidth() | 屏幕区域 | 返回画布的宽度,即屏幕的宽度 |
canvas.getHeight() | 屏幕区域 | 返回画布的高度,即屏幕的高度 |
3.Display对象获取屏幕宽高
通过Activity的getWindowManager.getDefaultDisplay()
方法可以获取到display
对象
方法 | 影响区域 | 说明 |
---|---|---|
display.getWidth() | 屏幕区域 | 返回界面的宽度,即屏幕的宽度 |
display.getHeight() | 屏幕区域 | 返回界面的高度,即屏幕的高度 |
2. 状态栏高度的测量
1.方法一:通过系统尺寸资源获取
状态栏高度定义在Android系统尺寸资源中status_bar_height
,但这并不是公开可直接使用的,例如像通常使用系统资源那样android.R.dimen.status_bar_height
。但是系统给我们提供了一个Resource
类,通过这个类可以获取资源文件,借此可以获取到status_bar_height:
|
|
2.方法二:通过R类的反射
|
|
3.方法三:利用应用区域Top属性
|
|
注意:
如果单单获取statusBar高度而不获取titleBar高度时,这种方法并不推荐大家使用,因为这种方法依赖于WMS(窗口管理服务的回调)。正是因为窗口回调机制,所以在Activity初始化时执行此方法得到的高度是0。这个方法推荐在回调方法onWindowFocusChanged()
中执行,才能得到预期结果。
3. 标题栏高度的测量
正如上面介绍的,应用界面顶端与view绘制区域顶端之间的部分为标题栏。所以自然会想到两种测量标题栏高度的方法:一个是使用Top-Top
,另一个就是使用高度-高度
。先介绍一下获取各区域宽高的代码:
1. 方法一:Top-Top
2. 方法二:高度- 高度
|
|
4. 注意事项
不管你是否设置全屏模式,或是不显示标题栏,在使用获取状态栏高度方法1和获取状态栏高度方法2都会测量到状态栏的高度,理解原理就不难解释——系统资源属性是固定的、真实的,不管你是否隐瞒(隐藏或者显示),它都在那里;
是若使用获取状态栏高度方法3,以及获取标题栏高度方法1和获取标题栏高度方法2,都是依赖于WMS,是在界面构建后根据View获取的,所以显示了就有高度,不显示自然没高度了。
[参考文献]