自定義View-第五步:繪制圖片

前言

根據Gcssloop所學習的自定義View整理與筆記。

準備

** 禁用GPU硬件加速**

  1. 在AndroidManifest.xml文件為application標簽添加如下的屬性即可為整個應用程序開啟/關閉硬件加速:
<application android:hardwareAccelerated="false" ...>
  1. 在Activity 標簽下使用 hardwareAccelerated 屬性開啟或關閉硬件加速:
<activity android:hardwareAccelerated="false" />  
  1. 在Window 層級使用如下代碼開啟硬件加速:(Window層級不支持關閉硬件加速)
getWindow().setFlags(  
WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,  
WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED); 
  1. 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中

現在開始使用啦?(?*)

  1. 第一步:使用Picture錄制內容
//錄制內容
private void recording() {
    Canvas canvas = picture.beginRecording(500, 500);
    canvas.translate(250, 250);
    canvas.drawCircle(0, 0, 100, paint);
    picture.endRecording();
}
  • 第二步:將錄制的內容顯示出來(三種方式)
    1. 使用Picture提供的draw方法繪制。
// 將Picture中的內容繪制在Canvas上,一般不使用 
       picture.draw(canvas);

效果圖為:


  1. 使用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));

效果圖為:


**繪制的內容根據選區進行了縮放**
  1. 將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

  1. 第一種
/** * 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);
效果
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容