admin 管理员组文章数量: 1184232
一、截图原理
Android中每一个页面都是一个Activity,通过Window对象实现页面的显示,每个Window对象实际上都是PhoneWindow的实例,当我们在Activity页面点击屏幕的时候,会触发点击事件,这个事件会一层层分发到处理它的view上,大致会经过这些view:
privatevoidtakeScreenshot(){synchronized(mScreenshotLock){if(mScreenshotConnection !=null){return;}ComponentName cn =newComponentName("com.android.systemui","com.android.systemui.screenshot.TakeScreenshotService");Intent intent =newIntent();
intent.setComponent(cn);ServiceConnection conn =newServiceConnection(){@OverridepublicvoidonServiceConnected(ComponentName name,IBinder service){synchronized(mScreenshotLock){if(mScreenshotConnection !=this){return;}Messenger messenger =newMessenger(service);Message msg =Message.obtain(null,1);finalServiceConnection myConn =this;Handler h =newHandler(mHandler.getLooper()){@OverridepublicvoidhandleMessage(Message msg){synchronized(mScreenshotLock){if(mScreenshotConnection == myConn){
mContext.unbindService(mScreenshotConnection);
mScreenshotConnection =null;
mHandler.removeCallbacks(mScreenshotTimeout);}}}};
msg.replyTo =newMessenger(h);
msg.arg1 = msg.arg2 =0;if(mStatusBar !=null&& mStatusBar.isVisibleLw())
msg.arg1 =1;if(mNavigationBar !=null&& mNavigationBar.isVisibleLw())
msg.arg2 =1;try{
messenger.send(msg);}catch(RemoteException e){}}}@OverridepublicvoidonServiceDisconnected(ComponentName name){}};if(mContext.bindServiceAsUser(
intent, conn,Context.BIND_AUTO_CREATE,UserHandle.CURRENT)){
mScreenshotConnection = conn;
mHandler.postDelayed(mScreenshotTimeout,10000);}}}这里通过反射机制调用了TakeScreenshotService的bindServiceAsUser方法,创建TakeScreenshotService服务,再通过其内部的SurfaceControl.screenshot 生成 bitmap,生成图片成功会给系统发送通知。
系统截图的大致流程就是这样,在里面截图原理大致就是:获取需要截屏的区域的宽高,创建一个画布,然后区域内的内容绘制在画布上,最后生成bitmap图片。
二、实现方式
Android 截图主要为四种:View 截图、WebView 截图、屏幕截图、系统截图和 adb 截图。后两种截图不常用,不详细展开。
1. View截图
可以截取到View不可见的部分,生成长图,状态栏和导航栏无法截到
funscreenshotView(view: ViewGroup):Bitmap?{var h =0var bitmap:Bitmap?=nullfor(i in0 until view.childCount){
h += view.getChildAt(i).height
view.getChildAt(i).setBackgroundColor(Color.parseColor("#6CC287"))}
bitmap = Bitmap.createBitmap(view.width, h, Bitmap.Config.RGB_565)val canvas =Canvas(bitmap)
view.draw(canvas)//重新赋色for(i in0 until view.childCount){
view.getChildAt(i).setBackgroundDrawable(null)}return bitmap
}2. WebView截图
WebView 作为一种特殊的控件,不能像其他系统 View 或者截屏的方式来截图,有特定的Api
// 1.capturePicture方法废弃// 2.getScale方法废弃// 3.getDrawingCache方法privatestaticbyte[]screenshotWebView(){Bitmap bitmap = webView.getDrawingCache();byte[] drawByte =getBitmapByte(bmp);return drawByte;}// 4.draw方法privatestaticbyte[]screenshotWebView(){// webView.setDrawingCacheEnabled(true); 设置缓存Bitmap bitmap =Bitmap.createBitmap(webView.getWidth(), webView.getHeight(),Bitmap.Config.ARGB_8888);Canvas canvas =newCanvas(bitmap);
webView.draw(canvas);
webView.destroyDrawingCache();byte[] drawByte =getBitmapByte(bitmap);return drawByte;}可能会截取不到 cavans 元素,原因是开启了硬件加速(关闭硬件加速可能导致页面异常),可在 AndroidManifest.xml 中设置:
android:hardwareAccelerated="false"
截长图的话需要配置:
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.LOLLIPOP){WebView.enableSlowWholeDocumentDraw();}setContentView(R.layout.webview);3. 屏幕截图
截取应用当前屏幕的图片:
/**
* 获取当前屏幕截图,包含状态栏
*
* @param activity activity
* @return Bitmap
*/publicstaticBitmapcaptureWithStatusBar(Activity activity){View view = activity.getWindow().getDecorView();
view.setDrawingCacheEnabled(true);
view.buildDrawingCache();Bitmap bmp = view.getDrawingCache();int width =getScreenWidth(activity);int height =getScreenHeight(activity);Bitmap ret =Bitmap.createBitmap(bmp,0,0, width, height);
view.destroyDrawingCache();return ret;}/**
* 获取当前屏幕截图,不包含状态栏
*
* @param activity activity
* @return Bitmap
*/publicstaticBitmapcaptureWithoutStatusBar(Activity activity){View view = activity.getWindow().getDecorView();
view.setDrawingCacheEnabled(true);
view.buildDrawingCache();Bitmap bmp = view.getDrawingCache();int statusBarHeight =getStatusBarHeight(activity);int width =getScreenWidth(activity);int height =getScreenHeight(activity);Bitmap ret =Bitmap.createBitmap(bmp,0, statusBarHeight, width, height - statusBarHeight);
view.destroyDrawingCache();return ret;}/**
* 得到屏幕的高
*
* @param context
* @return
*/publicstaticintgetScreenHeight(Context context){WindowManager wm =(WindowManager) context.getSystemService(Context.WINDOW_SERVICE);int height = wm.getDefaultDisplay().getHeight();return height;}/**
* 得到屏幕的宽
*
* @param context
* @return
*/publicstaticintgetScreenWidth(Context context){WindowManager wm =(WindowManager) context.getSystemService(Context.WINDOW_SERVICE);int width = wm.getDefaultDisplay().getWidth();return width;}/**
* 获取状态栏高度
*
* @param context 上下文
* @return 状态栏高度
*/publicstaticintgetStatusBarHeight(Context context){int result =0;int resourceId = context.getResources().getIdentifier("status_bar_height","dimen","android");if(resourceId >0){
result = context.getResources().getDimensionPixelSize(resourceId);}return result;}三、格式转换方法
下面列出了一些常用的转换方法:
// Bitmap 转 Base64privatestaticStringgetBitmapString(Bitmap bitmap){String result =null;ByteArrayOutputStream out =null;try{if(bitmap !=null){
out =newByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG,100, out);
out.flush();
out.close();
byte[] bitmapBytes = out.toByteArray();
result =Base64.encodeToString(bitmapBytes,Base64.DEFAULT);}}catch(IOException e){
e.printStackTrace();}finally{try{if(out !=null){
out.flush();
out.close();}}catch(IOException e){
e.printStackTrace();}}return result;}
// Bitmap 转 Byteprivatestaticbyte[]getBitmapByte(Bitmap bitmap){ByteArrayOutputStream out =newByteArrayOutputStream();// 转换类型,压缩质量,字节流资源
bitmap.compress(Bitmap.CompressFormat.PNG,100, out);try{
out.flush();
out.close();}catch(IOException e){
e.printStackTrace();}return out.toByteArray();}// Drawable 转 BitmappublicstaticBitmaptoBitmap(Drawable drawable){if(drawable instanceofBitmapDrawable){return((BitmapDrawable) drawable).getBitmap();}elseif(drawable instanceofColorDrawable){//colorBitmap bitmap =Bitmap.createBitmap(32,32,Bitmap.Config.ARGB_8888);Canvas canvas =newCanvas(bitmap);
canvas.drawColor(((ColorDrawable) drawable).getColor());return bitmap;}elseif(drawable instanceofNinePatchDrawable){//.9.pngBitmap bitmap =Bitmap.createBitmap(drawable.getIntrinsicWidth(),
drawable.getIntrinsicHeight(),Bitmap.Config.ARGB_8888);Canvas canvas =newCanvas(bitmap);
drawable.setBounds(0,0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
drawable.draw(canvas);return bitmap;}returnnull;}版权声明:本文标题:【Android】多种方式实现截图(屏幕截图、View截图、长图)_android 截屏 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.roclinux.cn/p/1774349120a3570710.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论