Android Canvas和Bitmap結(jié)合繪圖詳解流程
Rect/RectF
存儲(chǔ)四個(gè)值的矩形類:左側(cè)、頂部、右側(cè)和底部。可用于直接在畫布上繪制或僅用于存儲(chǔ)要繪制的對(duì)象的大小。Rect和RectF類之間的區(qū)別在于 RectF 存儲(chǔ)浮點(diǎn)值,而Rect類存儲(chǔ)整數(shù)。
private static Bitmap createDrawableBitmap(Drawable drawable) {
int width = drawable.getIntrinsicWidth();
int height = drawable.getIntrinsicHeight();
if (width <= 0 || height <= 0) {
return null;
}
float scale = Math.min(1.0f, ((float) MAX_IMAGE_SIZE) / ((float) (width * height)));
if ((drawable instanceof BitmapDrawable) && scale == 1.0f) {
return ((BitmapDrawable) drawable).getBitmap();
}
int bitmapWidth = (int) (((float) width) * scale);
int bitmapHeight = (int) (((float) height) * scale);
Bitmap bitmap = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
Rect existingBounds = drawable.getBounds();
int left = existingBounds.left;
int top = existingBounds.top;
int right = existingBounds.right;
int bottom = existingBounds.bottom;
drawable.setBounds(0, 0, bitmapWidth, bitmapHeight);
drawable.draw(canvas);
drawable.setBounds(left, top, right, bottom);
return bitmap;
}
Matrix
一個(gè)3 x 3的矩陣,用于存儲(chǔ)可用于轉(zhuǎn)換畫布的信息。矩陣可以存儲(chǔ)以下類型的變換信息:縮放、傾斜、旋轉(zhuǎn)、平移。而每種變換方式都對(duì)應(yīng)著三種方法:set方法將用新值替換當(dāng)前的Matrix,不管之前Matrix的值是什么。pre和post 方法將在當(dāng)前Matrix包含的任何內(nèi)容之前或之后應(yīng)用新的轉(zhuǎn)換。
Matrix m = new Matrix(); m.setRotate(90); m.setScale(3f,1f); m.setTranslate(200, 200);
只有平移,旋轉(zhuǎn)值和縮放值被重置
Matrix m = new Matrix(); m.preScale(3f,1f); m.preTranslate(200f, 100f); m.postScale(0.5f, 1f); m.postTranslate(100f, 0f);
先進(jìn)行平移(200f, 100f),然后進(jìn)行縮放(3f, 1f),然后進(jìn)行縮放(0.5f, 1f),最后進(jìn)行平移(100f, 0f)
Matrix m = new Matrix(); m.postTranslate(200f, 0f); m.preScale(0.5f, 1f); m.setScale(1f, 1f); m.postScale(5f, 1f); m.preTranslate(200f, 100f);
先進(jìn)行平移(200f, 100f),然后進(jìn)行縮放(1f, 1f),最后進(jìn)行縮放(5f, 1f)。因?yàn)橛昧藄et方法所以平移(200f, 0f)和縮放(0.5f, 1f)被覆蓋,不起作用
假如先進(jìn)行平移(x, y),再進(jìn)行縮放(sx, sy),那么看到的平移效果等同于(x*sx, y*sy),因?yàn)榭s放是將整個(gè)畫布或者坐標(biāo)系進(jìn)行縮放的
Canvas
Canvas相當(dāng)于Android的畫布,可以把畫布想象成一塊內(nèi)存空間,也就是一個(gè)Bitmap。Canvas的API提供一整套在這個(gè)Bitmap上進(jìn)行繪圖的操作方法。
- drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint)
使用指定的矩陣?yán)L制位圖,繪制的時(shí)候會(huì)使用矩陣進(jìn)行變換,矩陣和畫筆可以傳入空值
- drawBitmap (Bitmap bitmap, Rect src, Rect dst, Paint paint)
將傳入的源圖bitmap指定的矩形區(qū)域src繪制到目標(biāo)矩形區(qū)域dst中,如果矩形區(qū)域src傳入空值,則表示繪制整個(gè)源圖到目標(biāo)矩形區(qū)域dst中,繪制的時(shí)候源圖或子集自動(dòng)縮放/平移以填充目標(biāo)矩形。如果繪制對(duì)應(yīng)的畫筆通過(guò)方法setMaskFilter指定了超出原始位圖寬/高的掩碼過(guò)濾器(如BlurMaskFilter),則會(huì)位圖將繼續(xù)被繪制,就像在具有CLAMP模式的著色器中一樣。因此,原始寬/高之外的顏色將是復(fù)制的邊緣顏色。因?yàn)樵淳匦螀^(qū)域src對(duì)應(yīng)的坐標(biāo)空間是相對(duì)于源圖的,而目標(biāo)矩形區(qū)域dst對(duì)應(yīng)的坐標(biāo)空間是繪制視圖對(duì)應(yīng)的坐標(biāo)空間,因此要控制好對(duì)應(yīng)的縮放因子。
- drawBitmap (Bitmap bitmap, Rect src, RectF dst, Paint paint)
矩陣示例:
Bitmap background = Bitmap.createBitmap((int)width, (int)height, Config.ARGB_8888); float originalWidth = originalImage.getWidth(); float originalHeight = originalImage.getHeight(); Canvas canvas = new Canvas(background); float scale = width / originalWidth; float xTranslation = 0.0f; float yTranslation = (height - originalHeight * scale) / 2.0f; Matrix transformation = new Matrix(); transformation.postTranslate(xTranslation, yTranslation); transformation.preScale(scale, scale); Paint paint = new Paint(); paint.setFilterBitmap(true); canvas.drawBitmap(originalImage, transformation, paint);
矩形區(qū)域示例:
public Bitmap cropCircle(Bitmap bitmap) {
Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),
bitmap.getHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(output);
final int color = 0xff424242;
final Paint paint = new Paint();
final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(color);
canvas.drawCircle(bitmap.getWidth() / 2, bitmap.getHeight() / 2,
bitmap.getWidth()/2, paint);
paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
canvas.drawBitmap(bitmap, rect, rect, paint);
return output;
}
Bitmap
位圖,點(diǎn)陣圖,可以理解為int[] buffer,用來(lái)存儲(chǔ)每個(gè)像素點(diǎn)的容器。
- Bitmap.createBitmap(int width, int height, Bitmap.Config config)
- Bitmap.createBitmap(Bitmap src)
- Bitmap.createBitmap(Bitmap source, int x, int y, int width, int height)
- Bitmap.createBitmap(Bitmap source, int x, int y, int width, int height,Matrix m, boolean filter)
- BitmapFactory.decodeByteArray(byte[] data, int offset, int length, BitmapFactory.Options opts)
- BitmapFactory.decodeFile(String pathName, Options opts)
- BitmapFactory.decodeStream(InputStream is, Rect outPadding,Options opts)
createBitmap生成示例:
public Bitmap transform(Bitmap source) {
int size = Math.min(source.getWidth(), source.getHeight());
int x = (source.getWidth() - size) / 2;
int y = (source.getHeight() - size) / 2;
Bitmap squaredBitmap = Bitmap.createBitmap(source, x, y, size, size);
if (squaredBitmap != source) {
source.recycle();
}
Bitmap bitmap = Bitmap.createBitmap(size, size, source.getConfig());
Canvas canvas = new Canvas(bitmap);
Paint avatarPaint = new Paint();
BitmapShader shader = new BitmapShader(squaredBitmap, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP);
avatarPaint.setShader(shader);
Paint outlinePaint = new Paint();
outlinePaint.setColor(Color.WHITE);
outlinePaint.setStyle(Paint.Style.STROKE);
outlinePaint.setStrokeWidth(STROKE_WIDTH);
outlinePaint.setAntiAlias(true);
float r = size / 2f;
canvas.drawCircle(r, r, r, avatarPaint);
canvas.drawCircle(r, r, r - STROKE_WIDTH / 2, outlinePaint);
squaredBitmap.recycle();
return bitmap;
}
BitmapFactory生成示例:
private static Bitmap decodeSampledBitmapFromUrl(String url, int reqWidth, int reqHeight) throws IOException {
// First decode with inJustDecodeBounds=true to check dimensions
final Options options = new Options();
options.inJustDecodeBounds = true;
InputStream stream = fetchStream(url);
BitmapFactory.decodeStream(stream, null, options);
stream.close();
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
stream = fetchStream(url);
Bitmap bitmap = BitmapFactory.decodeStream(stream, null, options);
stream.close();
return bitmap;
}
private static InputStream fetchStream(String urlString) throws IllegalStateException, IOException {
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpGet request = new HttpGet(urlString);
HttpResponse response = httpClient.execute(request);
return response.getEntity().getContent();
}
private static int calculateInSampleSize(Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
// Calculate ratios of height and width to requested height and width
final int heightRatio = Math.round((float) height / (float) reqHeight);
final int widthRatio = Math.round((float) width / (float) reqWidth);
// Choose the smallest ratio as inSampleSize value, this will guarantee
// a final image with both dimensions larger than or equal to the
// requested height and width.
inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
}
return inSampleSize;
}
注意:通過(guò)Bitmap.createBitmap生成的Bitmap對(duì)象是可變對(duì)象,可以向Bitmap上繪制內(nèi)容,而通過(guò)BitmapFactory生成的Bitmap對(duì)象必須指定BitmapFactory.Options.inMutable = true,否則就是不可變對(duì)象,不能向上面繪制內(nèi)容。
感謝大家的支持,如有錯(cuò)誤請(qǐng)指正,如需轉(zhuǎn)載請(qǐng)標(biāo)明原文出處!
到此這篇關(guān)于Android Canvas和Bitmap結(jié)合繪圖詳解流程的文章就介紹到這了,更多相關(guān)Android 繪圖內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android實(shí)現(xiàn)粒子中心擴(kuò)散動(dòng)畫效果
粒子動(dòng)畫效果相比其他動(dòng)畫來(lái)說(shuō)是非常復(fù)雜了的,主要涉及三個(gè)方面,粒子初始化、粒子位移、粒子回收等問(wèn)題,本篇將實(shí)現(xiàn)兩種動(dòng)畫效果,代碼基本相同,只是旋轉(zhuǎn)速度不一樣,需要的朋友可以參考下2024-02-02
Android編程實(shí)現(xiàn)獲取新浪天氣預(yù)報(bào)數(shù)據(jù)的方法
這篇文章主要介紹了Android編程實(shí)現(xiàn)獲取新浪天氣預(yù)報(bào)數(shù)據(jù)的方法,涉及Android基于新浪接口的調(diào)用及數(shù)據(jù)處理技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-11-11
Flutter listview如何實(shí)現(xiàn)下拉刷新上拉加載更多功能
這篇文章主要給大家介紹了關(guān)于Flutter listview如何實(shí)現(xiàn)下拉刷新上拉加載更多功能的相關(guān)資料,對(duì)于新聞列表數(shù)據(jù)的更新和加載更多是必不可少的,而實(shí)現(xiàn)下拉刷新與上劃加載更多的方式有很多種,需要的朋友可以參考下2021-08-08
android實(shí)現(xiàn)給未簽名的apk簽名方法
下面小編就為大家?guī)?lái)一篇android實(shí)現(xiàn)給未簽名的apk簽名方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-12-12
android開發(fā)教程之實(shí)現(xiàn)toast工具類
這篇文章主要介紹了android開發(fā)中需要的toast工具類,需要的朋友可以參考下2014-05-05
android實(shí)現(xiàn)簡(jiǎn)易登錄注冊(cè)界面及邏輯設(shè)計(jì)
這篇文章主要為大家詳細(xì)介紹了android實(shí)現(xiàn)簡(jiǎn)易登錄注冊(cè)界面及邏輯設(shè)計(jì),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-06-06
android 震動(dòng)和提示音的實(shí)現(xiàn)代碼
這篇文章主要介紹了android 震動(dòng)和提示音的實(shí)現(xiàn)代碼,代碼簡(jiǎn)單易懂,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-12-12
ExpandableListView實(shí)現(xiàn)二級(jí)列表購(gòu)物車
這篇文章主要為大家詳細(xì)介紹了ExpandableListView實(shí)現(xiàn)二級(jí)列表購(gòu)物車,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-11-11

