Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發 >> 關於android開發 >> [android]Android中圖形圖片及處理相關Api的小總結

[android]Android中圖形圖片及處理相關Api的小總結

編輯:關於android開發

[android]Android中圖形圖片及處理相關Api的小總結


開發應用中圖片的使用是必不可少的,Android系統提供了豐富的圖片支持功能。我們除了可以使Drawable資源庫,還可以使用Bitmap、Picture類去創建圖片,也可以使用Canvas、Paint、Path類等去繪制我們滿意的圖片。在自定義控件時,這些API使用尤為常見。因此,小編覺得有必要簡單的做個小總結。

那就先從Bitmap和BitmapFactory開始吧

 

Bitmap和BitmapFactory

 

BitmapFactory

Bitmap代表一張位圖。BitmapDrawable中封裝的圖片就是一個Bitmap對象。

可以調用BitmapDrawable的構造器將一個Bitmap對象封裝成為一個BitmapDrawable對象,方法如下:

BitmapDrawable drawable = new BitmapDrawable(bitmap);

如果想要獲取BitmapDrawable中封裝的Bitmap對象,可以采用如下方法:

Bitmap bitmap = drawable.getBitmap();

BitmapFactory中提供了多個方法來解析、創建Bitmap的對象:
decodeByteArray(byte[] data, int offset, int length) :將制定字節數組從offset字節開始length長度的字節解析成Bitmap對象。

decodeFile(String pathName) :將指定路徑下的文件解析成Bitmap對象。

decodeFileDescriptor(FileDescriptor fd) :將FileDescriptor對應文件中解析,創建Bitmap對象。

decodeResource(Resources res, int id) :將給定的資源ID解析成Bitmap對象。

decodeStream(InputStream is) 將指定的字節流解析成Bitmap對象。

另外,需要注意的是Android為Bitmap提供了兩種方法判斷它是否已經回收,以及強制Bitmap回收自己。分別為Boolean isRecycled() 和void recycle()方法

 

Canvas

 

  Canvas, 我們稱之為“畫布“,主要適用於繪制View的。 Canvas中提供了大量繪制圖形的方法:

 

繪制扇形

drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint): 第一個參數RectF對象,指定扇形的區域;二個參數是起始角度;第三個參數是旋轉角度,順時針旋轉;第四個參數是是否填充,true為填充,false為不填充,也就是為一條弧線;第五個參數是繪制圖形的畫筆對象Paint。

RectF:通過RectF(float left, float top, float right, float bottom)構造器創建RectF對象。

Paint:是繪制所有圖形所用到的一個畫筆,我們在稍後講解。

drawArc(float left, float top, float right, float bottom, float startAngle, float sweepAngle, boolean useCenter, Paint paint) :這個是將扇形區域左,上,右,下邊的坐標直接輸入,而不是通過RectF對象。其他參數同上。

繪制圓形:

drawCircle(float cx, float cy, float radius, Paint paint): 第一、二個參數是指圓形的x, y坐標; 第三個參數是半徑; 第四個參數是畫筆Paint對象。

繪制直線:

drawLine(float startX, float startY, float stopX, float stopY, Paint paint) :兩點確定一條直線,第一、二參數是起始點的坐標;第三、四參數是結束點的坐標;第五個參數畫筆Paint對象。

drawLines(float[] pts, Paint paint) :多個點確定一條直線,第一個參數是點的數組;第二個參數是畫筆Paint對象。

drawLines(float[] pts, int offset, int count, Paint paint)

繪制橢圓

drawOval(float left, float top, float right, float bottom, Paint paint):前四個參數是橢圓的左,上,右,下邊的坐標,第五個是畫筆Paint對象。

drawOval(RectF oval, Paint paint):第一個參數是RectF對象, 第二個參數是畫筆Paint對象。

繪制矩形:

drawRect(RectF rect, Paint paint) :第一個參數是RectF對象, 第二個參數是畫筆Paint對象。

繪制點:

drawPoint(float x, float y, Paint paint) :第一、二個參數點的坐標,第三個參數為Paint對象。

渲染文本:

drawText(String text, float x, floaty, Paint paint)

drawText(CharSequence text, int start, int end, float x, float y, Paint paint)

drawText(char[] text, int index, int count, float x, float y, Paint paint)

drawText(String text, int start, int end, float x, float y, Paint paint)

Canvas中還給我們提供了很多繪制其他圖形的方法,這裡我們不在一一列舉。我們來看一下Paint”畫筆“。

Paint:

  Paint是用於繪制的畫筆,Canvas就像是我們的畫紙,我們需要筆才可以完成一整幅圖。Paint中為我們提供了很多設置的方法(我們這裡只列舉常用的方法):

setARGB(int a, int r, int g, int b) :設置 Paint對象顏色,參數一為alpha透明值

setAlpha(int a) :設置alpha不透明度,范圍為0~255

setAntiAlias(boolean aa) :是否抗鋸齒,這個一般是都要設置的。

setColor(int color) :設置顏色,這裡Android內部定義的有Color類包含了一些常見顏色定義

setTextScaleX(float scaleX) :設置文本縮放倍數,1.0f為原始

setTextSize(float textSize) :設置字體大小

setUnderlineText(booleanunderlineText) :設置下劃線

setStrokeCap(Paint.Cap cap) :當畫筆樣式為STROKE或FILL_OR_STROKE時,設置筆刷的圖形樣式,如圓形樣式 Cap.ROUND,或方形樣式Cap.SQUARE

setSrokeJoin(Paint.Join join) :設置繪制時各圖形的結合方式,如平滑效果等

Path

Path, 軌跡,路徑。Path可以沿著多個點繪制一條路徑, 在Canvas中可以根據Path繪制不同的圖形。

我們在使用Path繪制路徑,一般要使用到以下幾個方法:

moveTo(float x, float y): 移動到(x, y)坐標點。繪制路徑時,路徑的第一個點一般我們通過moveTo()來決定,否則默認為(0, 0)點。
lineTo(float x, float y): 從當前點繪制直線到(x, y)點。這個與moveTo()不同,moveTo()是指跳轉到(x, y)點,而不繪制連線。
close(): 將路徑封閉。舉例來說,我們繪制一個三角形,三角形的三個點是(0, 0,),(100, 0),(0, 100)我們使用lineTo將(0, 0,),(100, 0)連接,(100, 0),(0, 100)連接,這樣還差(0, 0,),(0, 100)之間的連線,這時我們可以直接調用close()方法,這樣就會直接將圖形封閉構成三角形。
quadTo(float x1, float y1, float x2, float y2): 繪制貝塞爾曲線,貝塞爾曲線是由三個點控制的:起始點,終止點,控制點。在該方法中,前兩個參數是控制點的坐標,後兩個參數是終止點坐標。
  
  Path中我們可以通過點來繪制路徑也可以通過addXXX()方法來繪制,Path中給我們提供了很多這樣的方法來添加不同的路徑:

方法 用途 addArc(RectF oval, float startAngle, float sweepAngle) 添加圓弧軌跡 addCircle(float x, float y, float radius, Path.Direction dir) 添加圓形軌跡 addOval(float left, float top, float right, float bottom, Path.Direction dir) 添加橢圓軌跡 addRect(float left, float top, float right, float bottom, Path.Direction dir) 添加矩形軌跡 addRoundRect(float left, float top, float right, float bottom, float rx, float ry, Path.Direction dir) 添加橢圓角矩形軌跡 下面主要通過兩個簡單的小例子加深對知識點的理解。當然,在文章開始我們已經提到這些Api在自定義控件中比較常見,下面也涉及到一些自定義View方面的知識。(~!~如果時間希望能夠系統的學習下自定義View以及ViewGroup方面的知識以及寫一篇這方面的總結)

自定義時鐘的Demo主要用到了Canvas以及Paint方面的知識,來看看代碼吧:

 

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}
主活動中僅僅加載了一個布局。

 

 



    
在布局文件中放置我們自定義View,比較簡單不需要太多介紹。

 

 

public class MyView  extends View{
        private int width;//設置高
        private int height;//設置高
        private Paint mPaintLine;//定義一個繪制直線的畫筆
        private Paint mPaintSecondLine;//定義一個繪制直線的畫筆
        private Paint mPaintInterCircle;//定義一個繪制圓的畫筆
        private Paint mPaintOutSideCircle;//定義一個繪制圓的畫筆
        private Paint mPaintText;//定義一個繪制文字的畫筆
        private Calendar mCalendar;//創建一個時間類
        private static final int NEED_INVALIDATE = 0X6666;

    public MyView(Context context) {
        super(context);
    }

    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);
        //初始化畫直線的畫筆
        mPaintLine = new Paint();
        mPaintLine.setAntiAlias(true);//消除鋸齒
        mPaintLine.setColor(Color.GRAY);//設置畫筆顏色
        mPaintLine.setStyle(Paint.Style.STROKE);//設置為空心
        mPaintLine.setStrokeWidth(10);//設置寬度// 初始化秒針的畫筆
        mPaintSecondLine = new Paint();
        mPaintSecondLine.setAntiAlias(true);//消除鋸齒
        mPaintSecondLine.setColor(Color.GRAY);//設置畫筆顏色
        mPaintSecondLine.setStyle(Paint.Style.STROKE);//設置為空心
        mPaintSecondLine.setStrokeWidth(7);//設置寬度//初始化內圓的畫筆
        mPaintInterCircle = new Paint();
        mPaintInterCircle.setAntiAlias(true);//消除鋸齒
        mPaintInterCircle.setColor(Color.BLACK);
        mPaintInterCircle.setStyle(Paint.Style.STROKE);//設置為空心
        mPaintInterCircle.setStrokeWidth(5);
        //初始化外圓的畫筆
        mPaintOutSideCircle = new Paint();
        mPaintOutSideCircle.setAntiAlias(true);//消除鋸齒
        mPaintOutSideCircle.setColor(Color.BLACK);
        mPaintOutSideCircle.setStyle(Paint.Style.STROKE);//設置為空心
        mPaintOutSideCircle.setStrokeWidth(10);

        //繪制文字的畫筆
        mPaintText = new Paint();
        mPaintText.setAntiAlias(true);//消除鋸齒
        mPaintText.setColor(Color.GRAY);
        mPaintText.setStyle(Paint.Style.STROKE);//設置為空心
        mPaintText.setTextAlign(Paint.Align.CENTER);
        mPaintText.setTextSize(40);
        mPaintText.setStrokeWidth(6);

        //初始化日歷
        mCalendar = Calendar.getInstance();
        //發送一個消息給UI主線程
        Handler handler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                switch (msg.what) {
                    case NEED_INVALIDATE:
                        //跟新時間
                        mCalendar = Calendar.getInstance();
                        invalidate();
                        sendEmptyMessageDelayed(NEED_INVALIDATE, 1000);
                        break;
                }

            }
        };
        handler.sendEmptyMessageDelayed(NEED_INVALIDATE, 2000);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        width = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
        height = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
        setMeasuredDimension(width, height);//設置寬和高
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // 主線程自動調用
        canvas.drawCircle(width / 2, height / 2, 300, mPaintInterCircle);
        canvas.drawCircle(width / 2, height / 2, 320, mPaintOutSideCircle);
        for (int i = 1; i <= 12; i++) {
            canvas.save();//保存當前狀態
            canvas.rotate(360 / 12 * i, width / 2, height / 2);//根據點width/2,height/2旋轉
            canvas.drawLine(width / 2, height / 2 - 300, width / 2, height / 2 - 270, mPaintLine);
            canvas.drawText( + i, width / 2, height / 2 - 240, mPaintText);
            canvas.restore();//回到save()方法保存的狀態
        }

        //繪制分針
        int minute=  mCalendar.get(Calendar.MINUTE);
        float minuteDegree = minute / 60f * 360;
        canvas.save();
        canvas.rotate(minuteDegree, width / 2, height / 2);
        canvas.drawLine(width / 2, height / 2 - 200, width / 2, height / 2 + 40, mPaintLine);
        canvas.restore();
        //繪制時針
        int hour=  mCalendar.get(Calendar.HOUR);
        float hourDegree = (hour * 60 + minute);//(12f*60)*360;
        canvas.save();
        canvas.rotate(hourDegree, width / 2, height / 2);
        canvas.drawLine(width / 2, height / 2 - 170, width / 2, height / 2 + 30, mPaintLine);
        canvas.restore();
        //繪制秒針
        int second =  mCalendar.get(Calendar.SECOND);
        float secondDegree = second * 6;//一秒是6度。
        canvas.save();
        canvas.rotate(secondDegree, width / 2, height / 2);
        canvas.drawLine(width / 2, height / 2 - 220, width / 2, height / 2 + 50, mPaintSecondLine);
        canvas.restore();
    }
}
onDraw是UI主線程不斷調用重繪界面的,因此我們需要使用到Handler,通過發送一個消息給Handler對象,讓Handler對象在每一秒重繪一次MyView控件。這裡重繪不能調用onDraw()方法額,而要調用的是invalidate()方法,invalidate()方法中調用了onDraw()方法。

 

下面馬上來看看效果吧:

\

采用雙緩沖實現畫圖板用到了以上提到的各類知識,主要原理是:當程序需要在指定View上進行繪制時,程序並不直接繪制到該View組建上,而是先繪制到內存中的一個Bitmap圖片上,等內存中的Bitmap繪制好之後,再一次性將Bitmap繪制到View上面,還是直接看代碼吧:

 

public class MainActivity extends AppCompatActivity {

    DrawView drawView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        LinearLayout line = new LinearLayout(this);
        DisplayMetrics displayMetrics = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getRealMetrics(displayMetrics);
        drawView = new DrawView(this, displayMetrics.widthPixels,displayMetrics.heightPixels);
        line.addView(drawView);
        setContentView(line);
    }
}
主活動中主要獲取了穿件的寬和高,同是創建DrawView,讓DrawView的寬和高保持與該Activity相同。來看看DrawView中的代碼:

 

 

public class DrawView extends View{
    float prex;
    float prey;
    private Path path;
    public Paint paint = null;
    Bitmap CacheBitmap = null;
    Canvas CacheCanvas = null;
    public DrawView(Context context, int widthPixels, int heightPixels) {
        super(context);
        CacheBitmap = Bitmap.createBitmap(widthPixels,heightPixels,Bitmap.Config.ARGB_8888);
        CacheCanvas = new Canvas();
        path = new Path();
        CacheCanvas.setBitmap(CacheBitmap);
        paint = new Paint(Paint.DITHER_FLAG);
        paint.setColor(Color.RED);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(5);
        paint.setAntiAlias(true);
        paint.setDither(true);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float x = event.getX();
        float y = event.getY();
        switch (event.getAction())
        {
            case MotionEvent.ACTION_DOWN:
                path.moveTo(x,y);
                prex = x;
                prey = y;
                break;
            case MotionEvent.ACTION_MOVE:
                path.quadTo(prex, prey, x, y);
                prex = x;
                prey = y;
                break;
            case MotionEvent.ACTION_UP:
                CacheCanvas.drawPath(path,paint);
                path.reset();
                break;
        }
        invalidate();
        return true;
    }

    @Override
    public void onDraw(Canvas canvas) {
        Paint bmPaint = new Paint();
        canvas.drawBitmap(CacheBitmap,0,0,bmPaint);
        canvas.drawPath(path,paint);
    }
}
為了讓view繪制的圖形發生改變,需要程序記住一些狀態數據:采用變量或者采用事件監聽器,在監聽器中修改這些數據。不管使用哪種方式,每次VIew組件上的圖形狀態發生改變時都應該通知View組件重新調用OnDraw()方法重繪該控件,通知可以調用invalidate()。

 

運行結果如下:

\


 

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved