Android 根據View生成圖片簡易參考
一、分類
開發中,我們有時候需要根據View生成圖片。
本文根據不同情況的View生成圖片進行了一些示例,分類如下
第一種,普通View生成圖片(view已經渲染載入到介面上)
第二種,無中生有,通過java程式碼建立的或者inflate建立
第三種,WebView 生成圖片
第四種,ScrollView 生成圖片
第五種,ListView 生成圖片
第六種,RecyclerView 生成圖片
還是圖來的直接
核心程式碼
public class SimpleUtils {
/**
* 將 Bitmap 儲存到SD卡
* @param context
* @param mybitmap
* @param name
* @return
*/
public static boolean saveBitmapToSdCard(Context context, Bitmap mybitmap, String name){
boolean result = false;
//建立點陣圖儲存目錄
String path = Environment.getExternalStorageDirectory() + "/1000ttt/";
File sd = new File(path);
if (!sd.exists()){
sd.mkdir();
}
File file = new File(path+name+".jpg");
FileOutputStream fileOutputStream = null;
if (!file.exists()){
try {
// 判斷SD卡是否存在,並且是否具有讀寫許可權
if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
fileOutputStream = new FileOutputStream(file);
mybitmap.compress(Bitmap.CompressFormat.JPEG,100,fileOutputStream);
fileOutputStream.flush();
fileOutputStream.close();
//update gallery
Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
Uri uri = Uri.fromFile(file);
intent.setData(uri);
context.sendBroadcast(intent);
Toast.makeText(context, "儲存成功", Toast.LENGTH_SHORT).show();
result = true;
}
else{
Toast.makeText(context, "不能讀取到SD卡", Toast.LENGTH_SHORT).show();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
return result;
}
/**
* 手動測量擺放View
* 對於手動 inflate 或者其他方式程式碼生成載入的View進行測量,避免該View無尺寸
* @param v
* @param width
* @param height
*/
public static void layoutView(View v, int width, int height) {
// validate view.width and view.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);
// validate view.measurewidth and view.measureheight
v.measure(measuredWidth, measuredHeight);
v.layout(0, 0, v.getMeasuredWidth(), v.getMeasuredHeight());
}
public static int px2dip(Context context, float pxValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (pxValue / scale + 0.5f);
}
/**
* 獲取一個 View 的快取檢視
* (前提是這個View已經渲染完成顯示在頁面上)
* @param view
* @return
*/
public static Bitmap getCacheBitmapFromView(View view) {
final boolean drawingCacheEnabled = true;
view.setDrawingCacheEnabled(drawingCacheEnabled);
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;
}
/**
* 對ScrollView進行截圖
* @param scrollView
* @return
*/
public static Bitmap shotScrollView(ScrollView scrollView) {
int h = 0;
Bitmap bitmap = null;
for (int i = 0; i < scrollView.getChildCount(); i++) {
h += scrollView.getChildAt(i).getHeight();
scrollView.getChildAt(i).setBackgroundColor(Color.parseColor("#ffffff"));
}
bitmap = Bitmap.createBitmap(scrollView.getWidth(), h, Bitmap.Config.RGB_565);
final Canvas canvas = new Canvas(bitmap);
scrollView.draw(canvas);
return bitmap;
}
/**
* 對ListView進行截圖
* http://stackoverflow.com/questions/12742343/android-get-screenshot-of-all-listview-items
*/
public static Bitmap shotListView(ListView listview) {
ListAdapter adapter = listview.getAdapter();
int itemscount = adapter.getCount();
int allitemsheight = 0;
List<Bitmap> bmps = new ArrayList<Bitmap>();
for (int i = 0; i < itemscount; i++) {
View childView = adapter.getView(i, null, listview);
childView.measure(
View.MeasureSpec.makeMeasureSpec(listview.getWidth(), View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
childView.layout(0, 0, childView.getMeasuredWidth(), childView.getMeasuredHeight());
childView.setDrawingCacheEnabled(true);
childView.buildDrawingCache();
bmps.add(childView.getDrawingCache());
allitemsheight += childView.getMeasuredHeight();
}
Bitmap bigbitmap =
Bitmap.createBitmap(listview.getMeasuredWidth(), allitemsheight, Bitmap.Config.ARGB_8888);
Canvas bigcanvas = new Canvas(bigbitmap);
Paint paint = new Paint();
int iHeight = 0;
for (int i = 0; i < bmps.size(); i++) {
Bitmap bmp = bmps.get(i);
bigcanvas.drawBitmap(bmp, 0, iHeight, paint);
iHeight += bmp.getHeight();
bmp.recycle();
bmp = null;
}
return bigbitmap;
}
/**
* 對RecyclerView進行截圖
* https://gist.github.com/PrashamTrivedi/809d2541776c8c141d9a
*/
public static Bitmap shotRecyclerView(RecyclerView view) {
RecyclerView.Adapter adapter = view.getAdapter();
Bitmap bigBitmap = null;
if (adapter != null) {
int size = adapter.getItemCount();
int height = 0;
Paint paint = new Paint();
int iHeight = 0;
final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
// Use 1/8th of the available memory for this memory cache.
final int cacheSize = maxMemory / 8;
LruCache<String, Bitmap> bitmaCache = new LruCache<>(cacheSize);
for (int i = 0; i < size; i++) {
RecyclerView.ViewHolder holder = adapter.createViewHolder(view, adapter.getItemViewType(i));
adapter.onBindViewHolder(holder, i);
holder.itemView.measure(
View.MeasureSpec.makeMeasureSpec(view.getWidth(), View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
holder.itemView.layout(0, 0, holder.itemView.getMeasuredWidth(),
holder.itemView.getMeasuredHeight());
holder.itemView.setDrawingCacheEnabled(true);
holder.itemView.buildDrawingCache();
Bitmap drawingCache = holder.itemView.getDrawingCache();
if (drawingCache != null) {
bitmaCache.put(String.valueOf(i), drawingCache);
}
height += holder.itemView.getMeasuredHeight();
}
bigBitmap = Bitmap.createBitmap(view.getMeasuredWidth(), height, Bitmap.Config.ARGB_8888);
Canvas bigCanvas = new Canvas(bigBitmap);
Drawable lBackground = view.getBackground();
if (lBackground instanceof ColorDrawable) {
ColorDrawable lColorDrawable = (ColorDrawable) lBackground;
int lColor = lColorDrawable.getColor();
bigCanvas.drawColor(lColor);
}
for (int i = 0; i < size; i++) {
Bitmap bitmap = bitmaCache.get(String.valueOf(i));
bigCanvas.drawBitmap(bitmap, 0f, iHeight, paint);
iHeight += bitmap.getHeight();
bitmap.recycle();
}
}
return bigBitmap;
}
}
核心程式碼都在上面了,下面開始分析。
二、普通View
普通View,在本文中就是已經繪製到介面的View。
如上,點選擷取View,並且我們會生成圖片顯示儲存到sd卡
普通View生成圖片參考程式碼
/**
* 獲取一個 View 的快取檢視
* (前提是這個View已經渲染完成顯示在頁面上)
* @param view
* @return
*/
public static Bitmap getCacheBitmapFromView(View view) {
final boolean drawingCacheEnabled = true;
view.setDrawingCacheEnabled(drawingCacheEnabled);
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;
}
.
.
.
至於儲存Bitmap到sd卡操作,雖然常見一些,程式碼還是附在頂部工具類了。
三、程式碼載入但是未顯示在介面的View
有一些View,我們是通過程式碼載入出來的,但是沒有載入介面上,我們也可以對這種View生成圖片。
什麼?既然沒有顯示在介面上,那還要載入來幹嘛?
此言差矣,用處還是有的,YY即可。
如圖,按下截圖按鈕,我們做的主要邏輯如下:
// 本View是inflate載入而來,不是Activity的xml本身的
View view = getLayoutInflater().inflate(R.layout.item_group,null);
ImageView mtv = (ImageView) view.findViewById(R.id.mIv);
ViewGroup.LayoutParams upPartLayoutParams = mtv.getLayoutParams();
int upPartMeasureHeight = View.MeasureSpec.makeMeasureSpec(upPartLayoutParams.height, View.MeasureSpec.EXACTLY);
mtv.setImageDrawable(getResources().getDrawable(R.drawable.ccc));
// 沒有顯示到介面上的view本身無大小可言,所以我們要手動指定一下
SimpleUtils.layoutView(mtv,upPartMeasureHeight,upPartMeasureHeight);
// View生成截圖
Bitmap cacheBitmapFromView = SimpleUtils.getCacheBitmapFromView(mtv);
mIvResult.setImageBitmap(cacheBitmapFromView);
// 儲存bitmap到sd卡
SimpleUtils.saveBitmapToSdCard(StyleTwoActivity.this,cacheBitmapFromView,"styleTwo");
.
.
.
程式碼中,我們看到,我們按下截圖,inflate載入一個簡單佈局檔案
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="200px"
android:layout_height="200px"
>
<ImageView
android:id="@+id/mIv"
android:layout_width="200px"
android:layout_height="200px"
android:background="#623512"
android:text="哇阿斯達撒大聲地哈哈哈就是這樣的按到"
android:textColor="#ffffff"
android:textSize="20sp"
/>
</LinearLayout>
我們看到,裡面就是一個ImagView,我們待會就是要給這個ImageView 設定一張圖片,然後對這個View進行生成圖片,但是注意,這個ImageView從始至終都是沒有顯示在介面上的。
這個ImageView並沒有載入到佈局。我們想直接呼叫正常View的生成圖片方法,但是如果這樣會生成圖片失敗。
因為剛剛inflate的View是沒有經過measure和layout的,沒有大小,所有我們需要指定一下大小。
所以我們呼叫layoutView方法指定大小
/**
* 手動測量擺放View
* 對於手動 inflate 或者其他方式程式碼生成載入的View進行測量,避免該View無尺寸
* @param v
* @param width
* @param height
*/
public static void layoutView(View v, int width, int height) {
// validate view.width and view.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);
// validate view.measurewidth and view.measureheight
v.measure(measuredWidth, measuredHeight);
v.layout(0, 0, v.getMeasuredWidth(), v.getMeasuredHeight());
}
public static int px2dip(Context context, float pxValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (pxValue / scale + 0.5f);
}
有了大小,就可以生成圖片了。
四、WebView、ScrollView、ListView和RecyclerView
其實在開篇的工具類都已經介紹了,就不一一說了。直接把demo的程式碼一下就差不多了。
四.1、WebView 生成圖片
@RuntimePermissions
public class WebShotActivity extends BaseActivity {
private WebView mWeb;
private ImageView mIvResult;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_web);
mWeb = (WebView) findViewById(R.id.mWeb);
mIvResult = (ImageView) findViewById(R.id.mIvResult);
mWeb.setDrawingCacheEnabled(true);
//支援javascript
mWeb.getSettings().setJavaScriptEnabled(true);
mWeb.getSettings().setUseWideViewPort(true);
mWeb.getSettings().setLoadWithOverviewMode(true);
//支援頁面縮放
//webView.getSettings().setBuiltInZoomControls(true);
//提升渲染優先順序
//webView.getSettings().setRenderPriority(WebSettings.RenderPriority.HIGH);
//不載入網路中的圖片資源
//webView.getSettings().setBlockNetworkImage(true);
//HTML5 Cache
//*mWeb.getSettings().setDomStorageEnabled(true);
mWeb.getSettings().setAllowFileAccess(true);
mWeb.getSettings().setAppCacheEnabled(true);
//優先從本地cache中載入,其次才是從網路中載入,即使內容已經過期*//*
mWeb.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
mWeb.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return super.shouldOverrideUrlLoading(view, url);
}
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
}
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
}
@Override
public boolean shouldOverrideKeyEvent(WebView view, KeyEvent event) {
//Android TV中可以在這裡返回true,按鍵交由onKeyDown方法處理
return super.shouldOverrideKeyEvent(view, event);
}
@Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
super.onReceivedError(view, errorCode, description, failingUrl);
}
});
mWeb.setWebChromeClient(new WebChromeClient() {
@Override
public void onProgressChanged(WebView view, int newProgress) {
super.onProgressChanged(view, newProgress);
}
@Override
public void onReceivedTitle(WebView view, String title) {
super.onReceivedTitle(view, title);
}
});
mWeb.loadUrl("https://m.baidu.com/?from=844b&vit=fps");
findViewById(R.id.mTvShot).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
WebShotActivityPermissionsDispatcher.storageNeedWithCheck(WebShotActivity.this);
}
});
}
@NeedsPermission({Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE})
void storageNeed() {
int viewWidth = mWeb.getMeasuredWidth();
int viewHeight = mWeb.getMeasuredHeight();
if (viewWidth > 0 && viewHeight > 0) {
Bitmap b = Bitmap.createBitmap(viewWidth, viewHeight, Bitmap.Config.RGB_565);
Canvas cvs = new Canvas(b);
mWeb.draw(cvs);
mIvResult.setImageBitmap(b);
SimpleUtils.saveBitmapToSdCard(WebShotActivity.this,b,"styleWeb");
}
}
@OnShowRationale({Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE})
void storageRationale(final PermissionRequest request) {
showRationaleDialog("儲存許可權是本程式必不可少的許可權,請開啟",request);
}
@OnPermissionDenied({Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE})
void storageDenied() {
openAppSetting("您拒絕了儲存許可權,請授權");
}
@OnNeverAskAgain({Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE})
void storageAsk() {
openAppSetting("您拒絕了儲存許可權,請授權");
}
}
程式碼稍微長了一下,是因為做了儲存許可權檢查和一些WebView的配置,我們該忽略的忽略,核心就是傳入WebView生成圖片那麼一句而已。
.
.
.
四.2、ScrollView 生成圖片
public class StyleScrollView extends BaseActivity {
private ImageView mIvRet;
private ScrollView mScrollView;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_scroll);
mIvRet = (ImageView) findViewById(R.id.mIvRet);
mScrollView = (ScrollView) findViewById(R.id.mScrollView);
findViewById(R.id.mTvShot).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Bitmap bitmap = SimpleUtils.shotScrollView(mScrollView);
mIvRet.setImageBitmap(bitmap);
}
});
}
}
四.3、ListView 生成圖片
public class StyleLvActivity extends BaseActivity {
private ListView mLv;
private ImageView mIvRet;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_lv);
mLv = (ListView) findViewById(R.id.mLv);
mLv.setAdapter(new MyAdapter());
mIvRet = (ImageView) findViewById(R.id.mIvRet);
findViewById(R.id.mTvShot).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Bitmap bitmap = SimpleUtils.shotListView(mLv);
mIvRet.setImageBitmap(bitmap);
}
});
}
class MyAdapter extends BaseAdapter{
@Override
public int getCount() {
return 10;
}
@Override
public Object getItem(int i) {
return null;
}
@Override
public long getItemId(int i) {
return 0;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
// 簡答粗暴了一些,只是為演示
View vi = getLayoutInflater().inflate(R.layout.item_lv,null);
TextView textView = (TextView) vi.findViewById(R.id.mTv);
textView.setText(i+"");
return vi;
}
}
}
.
.
.
四.4、RecyclerView 生成圖片
public class StyleRecyclerView extends BaseActivity {
private RecyclerView mRecycler;
private ImageView mIvRet;
private List<DataBean> mDatas;
private TestAdapter mAdapter;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_rv);
initData();
mRecycler = (RecyclerView) findViewById(R.id.mRecycler);
mRecycler.setLayoutManager(new LinearLayoutManager(this));
mRecycler.setAdapter(mAdapter = new TestAdapter());
mIvRet = (ImageView) findViewById(R.id.mIvRet);
findViewById(R.id.mTvShot).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Bitmap bitmap = SimpleUtils.shotRecyclerView(mRecycler);
mIvRet.setImageBitmap(bitmap);
}
});
}
private void initData()
{
mDatas = new ArrayList<DataBean>();
DataBean dataBean = null;
for (int i = 0; i < 6; i++)
{
dataBean = new DataBean();
dataBean.title = "標題 "+i;
dataBean.desc = "描述一下 "+i;
mDatas.add(dataBean);
}
}
class TestAdapter extends RecyclerView.Adapter<TestAdapter.MyViewHolder>{
// 孩子數
@Override
public int getItemCount() {
return mDatas.size();
}
// 建立檢視
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
MyViewHolder myViewHolder = new MyViewHolder(LayoutInflater.from(StyleRecyclerView.this)
.inflate(R.layout.item_rv,parent, false));
return myViewHolder;
}
// 繫結檢視檢視 以前getView的事情 關鍵方法
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
DataBean dataBean = mDatas.get(position);
holder.mTvTitle.setText(dataBean.title);
holder.mTvDesc.setText(dataBean.desc);
}
// 必須實現的Holder
class MyViewHolder extends RecyclerView.ViewHolder
{
TextView mTvTitle;
TextView mTvDesc;
public MyViewHolder(View itemView) {
super(itemView);
mTvTitle = (TextView) itemView.findViewById(R.id.mTvTitle);
mTvDesc = (TextView) itemView.findViewById(R.id.mTvDesc);
}
}
}
}
如上,這麼一些型別就介紹完了。
本篇完。
參考
【Android】獲取View的截圖
Android滾動截圖,ScrollView截圖,Listview截圖,Recyclerview截圖
相關文章
- 機器學習根據文字生成圖片教程(附python程式碼)機器學習Python
- 微信小程式根據本地快取圖片路徑,生成縮圖的方法微信小程式快取
- Android截圖和指定View生成截圖分享AndroidView
- android非同步生成圖片Android非同步
- iOS根據圖片比例計算顯示大小iOS
- Android生成圖片並放入相簿Android
- (IOS)根據bundle中的檔名讀取圖片iOS
- 根據api檔案生成程式碼API
- Python 根據id生成唯一碼Python
- 根據URL地址生成二維碼
- 堆糖網爬蟲(根據關鍵字下載圖片)爬蟲
- 根據URL引數返回不同大小的圖片這種方式消耗大不大,還是直接提前生成不同尺寸的圖片好?
- 短視訊app搭建,利用javaWeb生成一張簡易驗證碼圖片APPJavaWeb
- 給圖片加水印的簡易方法
- 如何設定圖片高度固定,寬度可以根據比例縮放
- PyQtGraph繪圖參考QT繪圖
- Android自定義View之圖片外形特效——輕鬆實現圓角和圓形圖片AndroidView特效
- git參考手冊--文字說明+git速查命令表(圖片)Git
- spring boot itextPdf根據模板生成pdf檔案Spring Boot
- 基於long pull實現簡易的訊息系統參考
- C# .NET 根據Url連結儲存Image圖片到本地磁碟C#
- opencv-python簡易文件(一)圖片基本操作OpenCVPython
- JAVA期末簡答題參考Java
- OpenAPI Generator,根據Swagger/OpenAPI生成程式碼的工具APISwagger
- 根據使用者編號生成邀請碼
- PHP根據資料表自動生成CURD操作PHP
- mybatis根據表逆向自動化生成程式碼MyBatis
- EF3.1 根據資料庫生成程式碼資料庫
- 根據常用漢字生成雜亂的句子 --- javaJava
- pyecharts生成圖片Echarts
- Flutter 生成圖片Flutter
- 一個很簡短的 JS 生成器入門和用法參考JS
- 微服務 架構圖 參考微服務架構
- 阿里技術參考圖冊阿里
- Java 根據模板生成 PDF 檔案 以及 excel 檔案JavaExcel
- AI應用之根據行業標準生成PRD文件AI行業
- 根據MediatR的Contract Messages自動生成Minimal WebApi介面WebAPI
- 根據Golang定義的介面生成proto檔案Golang
- Android圖片突出Android