前言
根據Gcssloop所學習的自定義View整理與筆記。
準備
** 禁用GPU硬件加速**
- 在AndroidManifest.xml文件為application標簽添加如下的屬性即可為整個應用程序開啟/關閉硬件加速:
<application android:hardwareAccelerated="false" ...>
- 在Activity 標簽下使用 hardwareAccelerated 屬性開啟或關閉硬件加速:
<activity android:hardwareAccelerated="false" />
- 在Window 層級使用如下代碼開啟硬件加速:(Window層級不支持關閉硬件加速)
getWindow().setFlags(
WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
- View 級別如下關閉硬件加速:(view 層級上不支持開啟硬件加速)
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
或者使用android:layerType=”software”來關閉硬件加速
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:paddingLeft="2dp"
android:layerType="software"
android:paddingRight="2dp" >
一、drawPicture:錄制Canvas中繪制的內容
** 使用Picture前請關閉硬件加速,以免引起不必要的問題!**
詳情請進入這里->Android的硬件加速及可能導致的問題
首先,了解一下Picture的方法吧~
public int getWidth ()//獲取寬度
public int getHeight ()//獲取高度
public Canvas beginRecording (int width, int height)//開始錄制 (返回一個Canvas,在Canvas中所有的繪制都會存儲在Picture中)
public void endRecording ()//結束錄制
public void draw (Canvas canvas)//將Picture中內容繪制到Canvas中
現在開始使用啦?(?*)
- 第一步:使用Picture錄制內容
//錄制內容
private void recording() {
Canvas canvas = picture.beginRecording(500, 500);
canvas.translate(250, 250);
canvas.drawCircle(0, 0, 100, paint);
picture.endRecording();
}
- 第二步:將錄制的內容顯示出來(三種方式)
- 使用Picture提供的draw方法繪制。
// 將Picture中的內容繪制在Canvas上,一般不使用
picture.draw(canvas);
效果圖為:
- 使用Canvas提供的drawPicture方法繪制,會縮放。
public void drawPicture (Picture picture)
public void drawPicture (Picture picture, Rect dst)
public void drawPicture (Picture picture, RectF dst)
舉個栗子:
paint.setColor(Color.RED);
canvas.drawRect(0, 0, 100, 200, paint);
paint.setColor(Color.BLACK);
canvas.drawPicture(picture, new RectF(0, 0, 100, 200));
效果圖為:
**繪制的內容根據選區進行了縮放**
- 將Picture包裝成為PictureDrawable,使用PictureDrawable的draw方法繪制,不會縮放。
paint.setColor(Color.RED);
canvas.drawRect(0, 0, 250, picture.getHeight(), paint);
paint.setColor(Color.BLACK);
// 包裝成為Drawable
PictureDrawable drawable = new PictureDrawable(picture);
// 設置繪制區域 -- 注意此處所繪制的實際內容不會縮放
drawable.setBounds(0, 0, 250, picture.getHeight());
// 繪制
drawable.draw(canvas);
效果圖:
此處setBounds是設置在畫布上的繪制區域,并非根據該區域進行縮放,也不是剪裁Picture,每次都從Picture的左上角開始繪制
ps:三種方法的主要區別:
是否對Canvas有影響: 1有影響;2,3不影響
此處指繪制完成后是否會影響Canvas的狀態(Matrix clip等)
可操作性強弱: 1可操作性較弱;2,3可操作性較強
此處的可操作性可以簡單理解為對繪制結果可控程度。
接下來上代碼嘍
二、drawBitmap
看到bitmap有點怕怕的,哈哈,內存泄漏的大麻煩啊,GcsSloop簡單的講解了一下,那我也跟著簡單的學一下講一下吧,嘿嘿
1.第一步:通過BitmapFactory從不同位置獲取Bitmap
//資源文件(drawable/mipmap/raw)中獲取
Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(),R.raw.bitmap);
//資源文件(assets)
Bitmap bitmap=null;
try {
InputStream is = mContext.getAssets().open("bitmap.png");
bitmap = BitmapFactory.decodeStream(is);
is.close();
} catch (IOException e) {
e.printStackTrace();
}
//內存卡文件
Bitmap bitmap = BitmapFactory.decodeFile("/sdcard/bitmap.png");
//網絡文件
Bitmap bitmap = BitmapFactory.decodeStream(is);
is.close();
2.第二步:繪制Bitmap
- 第一種
/** * Draw the bitmap using the specified matrix. *
* @param bitmap The bitmap to draw
* @param matrix The matrix used to transform the bitmap when it is drawn
* @param paint May be null. The paint used to draw the bitmap
*/
public void drawBitmap(@NonNull Bitmap bitmap, @NonNull Matrix matrix, @Nullable Paint paint) {
nativeDrawBitmapMatrix(mNativeCanvasWrapper, bitmap, matrix.ni(),
paint != null ? paint.getNativeInstance() : 0);
}
demo:
canvas.drawBitmap(bitmap,new Matrix(),new Paint());
2.第二種
/**
* @param bitmap The bitmap to be drawn
* @param left The position of the left side of the bitmap being drawn
* @param top The position of the top side of the bitmap being drawn
* @param paint The paint used to draw the bitmap (may be null)
*/
public void drawBitmap(@NonNull Bitmap bitmap, float left, float top, @Nullable Paint paint) {
throwIfCannotDraw(bitmap);
native_drawBitmap(mNativeCanvasWrapper, bitmap, left, top,
paint != null ? paint.getNativeInstance() : 0, mDensity, mScreenDensity, bitmap.mDensity);
}
**left、top:此處指定的是與坐標原點的距離,并非是與屏幕頂部和左側的距離, 雖然默認狀態下兩者是重合的,但是也請注意分別兩者的不同。
**
demo:
canvas.drawBitmap(bitmap,200,200,new Paint());
3.第三種
/*
@param bitmap The bitmap to be drawn
* @param src May be null. The subset of the bitmap to be drawn
* @param dst The rectangle that the bitmap will be scaled/translated to fit into
* @param paint May be null. The paint used to draw the bitmap
*/
public void drawBitmap(@NonNull Bitmap bitmap, @Nullable Rect src, @NonNull Rect dst, @Nullable Paint paint);
demo:
// 將畫布坐標系移動到畫布中央
canvas.translate(200, 200);
// 指定圖片繪制區域(左上角的四分之一)
Rect src = new Rect(0, 0, bitmap.getWidth() / 2, bitmap.getHeight() / 2);
// 指定圖片在屏幕上顯示的區域
Rect dst = new Rect(0, 0, 100, 200);
// 繪制圖片
canvas.drawBitmap(bitmap, src, dst, null);
效果