網(wǎng)站首頁(yè) 編程語(yǔ)言 正文
Android?View轉(zhuǎn)換為Bitmap實(shí)現(xiàn)應(yīng)用內(nèi)截屏功能_Android
作者:艾陽(yáng)Blog ? 更新時(shí)間: 2022-11-05 編程語(yǔ)言前言
安卓設(shè)備一般都自帶截圖功能,但是用戶體驗(yàn)有不好之處。就是會(huì)連帶著狀態(tài)欄??、??、時(shí)間日期、其他不必要頁(yè)面中信息,等等與用戶想截屏的內(nèi)容不符的信息也會(huì)被保存下來。通常,截圖后用戶會(huì)再次裁剪一次才能想把真正需求分享出去。
因此,咱們技術(shù)研發(fā)會(huì)遇到針對(duì)性的會(huì)做一些應(yīng)用內(nèi)的截屏功能。
一、getDrawingCache
getDrawingCache()是其中一種截圖手段,使用方便,主要針對(duì)應(yīng)用內(nèi)截圖。
1、創(chuàng)建View
fun getShareView() : View {
val shareView: View =
LayoutInflater.from(context).inflate(R.layout.share_layout, null)
//內(nèi)容...
return shareView
}
注意:一般大家實(shí)現(xiàn)思路都是點(diǎn)擊事件里進(jìn)行創(chuàng)建View繪制,很可能會(huì)遇到網(wǎng)絡(luò)圖片還未加載完的情況。因此,建議做延遲處理,或在點(diǎn)擊前前置創(chuàng)建好。
2、測(cè)試和繪制
public static void layoutView(View v, int width, int height) {
v.layout(0, 0, width, height);
int measuredWidth = View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY);
int measuredHeight = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY);
v.measure(measuredWidth, measuredHeight);
v.layout(0, 0, v.getMeasuredWidth(), v.getMeasuredHeight());
}
如果不走這個(gè)方法,bitmap轉(zhuǎn)換時(shí)會(huì)沒有視圖(黑屏情況)。
調(diào)用方法:
// 設(shè)置視圖的dp寬高
layoutView(share_view, dp2px(210), dp2px(180));
public static int dp2px(float dp) {
float scale = Resources.getSystem().getDisplayMetrics().density;
return (int) (dp * scale + 0.5f);
}
3、轉(zhuǎn)換Bitmap
public static Bitmap getCacheBitmapFromView(View view) {
final boolean drawingCacheEnabled = true;
view.setDrawingCacheEnabled(drawingCacheEnabled);
//設(shè)置背景色 //view.setBackgroundColor(CommonUtils.getContext().getResources().getColor(R.color.half_white));
view.buildDrawingCache(drawingCacheEnabled);
final Bitmap drawingCache = view.getDrawingCache();
Bitmap bitmap;
if (drawingCache != null) {
bitmap = Bitmap.createBitmap(drawingCache);
view.setDrawingCacheEnabled(false);
} else {
bitmap = null;
}
return bitmap;
}
二、黑屏問題
一般情況下,上面的代碼能夠正常實(shí)現(xiàn)效果。但有時(shí)候,生成Bitmap會(huì)出現(xiàn)問題(Bitmap全黑色)。主要原因是drawingCache的值大于系統(tǒng)給定的值。我們可以看一下buildDrawingCache()方法中的一段代碼:
//所要cache的view繪制的寬度和高度
if (width <= 0 || height <= 0 ||
//計(jì)算的是當(dāng)前所需要的drawingCache 大小
(width * height * (opaque && !translucentWindow ? 2 : 4) >
//得到的是系統(tǒng)所提供的最大的DrawingCache的值
ViewConfiguration.get(mContext).getScaledMaximumDrawingCacheSize())) {
destroyDrawingCache();
return;
}
當(dāng)所需要的drawingCache > 系統(tǒng)所提供的最大DrawingCache值時(shí),生成Bitmap就會(huì)出現(xiàn)問題,此時(shí)獲取的Bitmap就為null。
所以在只需要修改所需的cache值就可以解決問題了。于是我們引入第二種方法:
解決方案:
public static Bitmap convertViewToBitmap(View view){
view.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
view.buildDrawingCache();
Bitmap bitmap = view.getDrawingCache();
return bitmap;
}
view 使用 "getMeasuredWidth()"、 "getMeasuredHeight()"方法計(jì)算長(zhǎng)寬。此時(shí),Bitmap就能正確獲取了。
三、源碼分析
public void buildDrawingCache() {
buildDrawingCache(false);
}
public Bitmap getDrawingCache() {
return getDrawingCache(false);
}
public Bitmap getDrawingCache(boolean autoScale) {
if ((mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING) {
return null;
}
if ((mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED) {
buildDrawingCache(autoScale);
}
return autoScale ? mDrawingCache : mUnscaledDrawingCache;
}
public void buildDrawingCache(boolean autoScale) {
if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 || (autoScale ?
mDrawingCache == null : mUnscaledDrawingCache == null)) {
if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
Trace.traceBegin(Trace.TRACE_TAG_VIEW,
"buildDrawingCache/SW Layer for " + getClass().getSimpleName());
}
try {
buildDrawingCacheImpl(autoScale);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
}
private void buildDrawingCacheImpl(boolean autoScale) {
mCachingFailed = false;
int width = mRight - mLeft;
int height = mBottom - mTop;
final AttachInfo attachInfo = mAttachInfo;
final boolean scalingRequired = attachInfo != null && attachInfo.mScalingRequired;
if (autoScale && scalingRequired) {
width = (int) ((width * attachInfo.mApplicationScale) + 0.5f);
height = (int) ((height * attachInfo.mApplicationScale) + 0.5f);
}
final int drawingCacheBackgroundColor = mDrawingCacheBackgroundColor;
final boolean opaque = drawingCacheBackgroundColor != 0 || isOpaque();
final boolean use32BitCache = attachInfo != null && attachInfo.mUse32BitDrawingCache;
final long projectedBitmapSize = width * height * (opaque && !use32BitCache ? 2 : 4);
final long drawingCacheSize =
ViewConfiguration.get(mContext).getScaledMaximumDrawingCacheSize();
if (width <= 0 || height <= 0 || projectedBitmapSize > drawingCacheSize) {
if (width > 0 && height > 0) {
Log.w(VIEW_LOG_TAG, getClass().getSimpleName() + " not displayed because it is"
+ " too large to fit into a software layer (or drawing cache), needs "
+ projectedBitmapSize + " bytes, only "
+ drawingCacheSize + " available");
}
destroyDrawingCache();
mCachingFailed = true;
return;
}
..檢測(cè)drawingCache原有數(shù)據(jù)操作..
try {
bitmap = Bitmap.createBitmap(mResources.getDisplayMetrics(),
width, height, quality);
bitmap.setDensity(getResources().getDisplayMetrics().densityDpi);
if (autoScale) {
mDrawingCache = bitmap;
} else {
mUnscaledDrawingCache = bitmap;
}
if (opaque && use32BitCache) bitmap.setHasAlpha(false);
} catch (OutOfMemoryError e) {
// If there is not enough memory to create the bitmap cache, just
// ignore the issue as bitmap caches are not required to draw the
// view hierarchy
if (autoScale) {
mDrawingCache = null;
} else {
mUnscaledDrawingCache = null;
}
mCachingFailed = true;
return;
}
..執(zhí)行Bitmap寫入autoScale ? mDrawingCache : mUnscaledDrawingCache操作..
}
從以上源碼中,可以看到getDrawingcache = null的條件共有四個(gè):
1、(mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING為true
2、沒有設(shè)置setDrawingCacheEnabled(true)
3、width <= 0 || height <= 0 || projectedBitmapSize > drawingCacheSize為true
4、OutOfMemory
除了第一個(gè)條件,其他的都是buildDrawingCache執(zhí)行時(shí)才會(huì)觸發(fā)。下面來分析下條件三。既然子布局可以正常顯示,那么一定是滿足width>0和height>0的, drawingCacheSize肯定是一個(gè)固定值,就是當(dāng)前設(shè)備系統(tǒng)所允許的最大繪制緩存值。projectedBitmapSize的計(jì)算方式為width * height * (opaque && !use32BitCache ? 2 : 4),顧名思義,就是當(dāng)前計(jì)劃緩存的圖片大小,(opaque && !use32BitCache ? 2 : 4)不可能為0,也不可能是導(dǎo)致計(jì)劃緩存值變大的主因,width就是屏幕的寬,這個(gè)沒有變動(dòng)的條件,那么可以肯定就是height出現(xiàn)了異常,對(duì)于視圖高度的計(jì)算,android源碼表示如下:
@ViewDebug.ExportedProperty(category = "layout")
public final int getHeight() {
return mBottom - mTop;
}
一個(gè)View的高度getHeight()就是底-高,其中mBottom指的是視圖自身的底邊到父視圖頂邊的距離,mTop指的是視圖自身的頂邊到父視圖頂邊的距離。
四、View轉(zhuǎn)Canvas轉(zhuǎn)Bitmap
Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
view.measure(View.MeasureSpec.makeMeasureSpec(view.getWidth(), View.MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(view.getHeight(), View.MeasureSpec.EXACTLY));
view.layout((int) view.getX(), (int) view.getY(), (int) view.getX() + view.getMeasuredWidth(), (int) view.getY() + view.getMeasuredHeight());
view.draw(canvas);
return bitmap;
原文鏈接:https://blog.csdn.net/csdn_aiyang/article/details/126766336
相關(guān)推薦
- 2022-07-04 C#中File靜態(tài)類對(duì)文件的讀取寫入_C#教程
- 2023-06-21 python?import?引用上上上級(jí)包的三種方法_python
- 2022-03-28 Python中三種條件語(yǔ)句示例介紹_python
- 2022-08-27 關(guān)于pygame自定義窗口創(chuàng)建及相關(guān)操作指南_python
- 2022-07-03 canvas文字居中;canvas畫布文字右對(duì)齊;canvas畫布文字左對(duì)齊;canvas文字自動(dòng)換
- 2022-12-07 【Chrome】瀏覽器控制臺(tái)設(shè)置成中文
- 2022-03-15 window.navigator.hid Cannot read properties of und
- 2022-12-27 一文帶你了解Go語(yǔ)言標(biāo)準(zhǔn)庫(kù)strings的常用函數(shù)和方法_Golang
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡(jiǎn)單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支