Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 圖標放大縮小移動,加標注點,並帶點擊效果的實現

圖標放大縮小移動,加標注點,並帶點擊效果的實現

編輯:關於Android編程

第一:了解三個類
Canvas,在英語中,這個單詞的意思是帆布。在Android中,則把Canvas當做畫布,只要我們借助設置好的畫筆(Paint類)就可以在畫布上繪制我們想要的任何東西;另外它也是顯示位圖(Bitmap類)的核心類。隨用戶的喜好,Canvas還可設置一些關於畫布的屬性,比如,畫布的顏色、尺寸等。Canvas提供了如下一些方法:
一種就是使用普通View的canvas畫圖,還有一種就是使用專門的SurfaceView的canvas來畫圖。兩種的主要是區別就是可以在SurfaceView中定義一個專門的線程來完成畫圖工作,應用程序不需要等待View的刷圖,提高性能。前面一種適合處理量比較小,幀率比較小的動畫,比如說象棋游戲之類的;而後一種主要用在游戲,高品質動畫方面的畫圖。
1、將會以顏色ARBG填充整個控件的Canvas背景
mCanvas.drawARGB(122, 10, 159, 163) ;
2、將會以顏色ARBG填充整個控件的Canvas背景
mCanvas.drawColor(Color.BLUE) ;
3、繪制顏色,但是要制定一個mode
mCanvas.drawColor(Color.BLUE, Mode.SCREEN) ;
4、畫背景,跟2等效
mCanvas.drawPaint(mPaint) ;
5、畫一個點
mCanvas.drawPoint(23, 23, mPaint) ;
6、畫很多點這裡的float[] 表示{x0,y0,x1,y1,x2,y2,x3,y3…..}
mCanvas.drawPoints(new float[]{10,11,10,12,10,13,10,14,10,15,10,16}, mPaint) ;
7、畫線
mCanvas.drawLine(…) ;
8、畫長方形 Rect 和RectF的區別?
精度不一樣,Rect是使用int類型作為數值,RectF是使用float類型作為數值
Rect r = new Rect(10,10,50,50) ;
mCanvas.drawRect(r, mPaint) ;
RectF rf = new RectF(10,10,50,50) ;
mCanvas.drawRect(rf, mPaint) ;
mCanvas.drawRect(10, 10, 50, 50, mPaint) ;
9、畫橢圓 初始化RectF的參數是(left,top,right,bottom)
RectF rf = new RectF(100,100 ,200 ,250) ;
mCanvas.drawOval(rf, mPaint) ;
10、畫圓 (圓心x0,圓心y0,半徑,paint)
mCanvas.drawCircle(100, 100, 50, mPaint) ;
11、畫圓弧 RectF對象表明內切矩形的(left,top,right,bottom)
RectF rf = new RectF(100 ,100 ,200 ,200) ;
參數(rf,startAngle ,angle ,sweepAngle ,paint) sweepAngle表明是否顯示圓弧三角形 angle畫多少度
mCanvas.drawArc(rf, 60, 30, true, mPaint) ;
12、繪制圓角矩形 RectF是矩形的(left,top,right,bottom)
RectF rf = new RectF(100 ,100 ,200 ,200) ;
50表明x方向的半徑,20表示y方向的半徑
mCanvas.drawRoundRect(rf, 50, 20, mPaint) ;
13、畫任意多邊形
Path path = new Path() ;
path.moveTo(100, 100) ;
path.lineTo(200, 200) ;
path.lineTo(300, 200) ;
mCanvas.drawPath(path, mPaint) ;
14、通過Path對象,也可以畫其他的圖形
Path path = new Path() ;
path.addCircle(100, 100, 20, Path.Direction.CCW) ;
mCanvas.drawPath(path ,mPaint);
drawBitmap
drawText
drawPicture
Rect r = new Rect(100,100,200,200) ;
ByteArrayOutputStream out = new ByteArrayOutputStream();
Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.bg) ;
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out) ;
InputStream in = new ByteArrayInputStream(out.toByteArray()) ;
Picture picture = Picture.createFromStream(mContext.getResources().openRawResource(R.raw.bg)) ;
mCanvas.drawPicture(picture) ;
15、畫bitmap對象
mCanvas.drawBitmap(BitmapFactory.decodeResource(mContext.getResources(), R.drawable.bg),100, 100, mPaint) ;
16、Matrix中包含了對Bitmap的處理操作
Matrix m = new Matrix() ;
m.postScale(2, 2) ;
m.postRotate(60) ;
mCanvas.drawBitmap(BitmapFactory.decodeResource(mContext.getResources(), R.drawable.bg), m, mPaint) ;
Paint即畫筆,在繪制文本和圖形用它來設置圖形顏色, 樣式等繪制信息。
1.圖形繪制
setARGB(int a,int r,int g,int b);
設置繪制的顏色,a代表透明度,r,g,b代表顏色值。
setAlpha(int a);
設置繪制圖形的透明度。
setColor(int color);
設置繪制的顏色,使用顏色值來表示,該顏色值包括透明度和RGB顏色。
setAntiAlias(boolean aa);
設置是否使用抗鋸齒功能,會消耗較大資源,繪制圖形速度會變慢。
setDither(boolean dither);
設定是否使用圖像抖動處理,會使繪制出來的圖片顏色更加平滑和飽滿,圖像更加清晰
setFilterBitmap(boolean filter);
如果該項設置為true,則圖像在動畫進行中會濾掉對Bitmap圖像的優化操作,加快顯示
速度,本設置項依賴於dither和xfermode的設置
setMaskFilter(MaskFilter maskfilter);
設置MaskFilter,可以用不同的MaskFilter實現濾鏡的效果,如濾化,立體等
setColorFilter(ColorFilter colorfilter);
設置顏色過濾器,可以在繪制顏色時實現不用顏色的變換效果
setPathEffect(PathEffect effect);
設置繪制路徑的效果,如點畫線等
setShader(Shader shader);
設置圖像效果,使用Shader可以繪制出各種漸變效果
setShadowLayer(float radius ,float dx,float dy,int color);
在圖形下面設置陰影層,產生陰影效果,radius為陰影的角度,dx和dy為陰影在x軸和y軸上的距離,color為陰影的顏色
setStyle(Paint.Style style);
設置畫筆的樣式,為FILL,FILL_OR_STROKE,或STROKE
setStrokeCap(Paint.Cap cap);
當畫筆樣式為STROKE或FILL_OR_STROKE時,設置筆刷的圖形樣式,如圓形樣式
Cap.ROUND,或方形樣式Cap.SQUARE
setSrokeJoin(Paint.Join join);
設置繪制時各圖形的結合方式,如平滑效果等
setStrokeWidth(float width);
當畫筆樣式為STROKE或FILL_OR_STROKE時,設置筆刷的粗細度
setXfermode(Xfermode xfermode);
設置圖形重疊時的處理方式,如合並,取交集或並集,經常用來制作橡皮的擦除效果
2.文本繪制
setFakeBoldText(boolean fakeBoldText);
模擬實現粗體文字,設置在小字體上效果會非常差
setSubpixelText(boolean subpixelText);
設置該項為true,將有助於文本在LCD屏幕上的顯示效果
setTextAlign(Paint.Align align);
設置繪制文字的對齊方向
setTextScaleX(float scaleX);
設置繪制文字x軸的縮放比例,可以實現文字的拉伸的效果
setTextSize(float textSize);
設置繪制文字的字號大小
setTextSkewX(float skewX);
設置斜體文字,skewX為傾斜弧度
setTypeface(Typeface typeface);
設置Typeface對象,即字體風格,包括粗體,斜體以及襯線體,非襯線體等
setUnderlineText(boolean underlineText);
設置帶有下劃線的文字效果
setStrikeThruText(boolean strikeThruText);
設置帶有刪除線的效果
Matrix類,Matrix是一個3 x 3的矩陣,他對圖片的處理分為四個基本類型:
cosX -sinX translateX
sinX cosY translateY
0 0 scale
通過這個矩陣實現下面這些變化
1、Translate————平移變換
2、Scale————縮放變換
3、Rotate————旋轉變換
4、Skew————錯切變換
在Android的API裡對於每一種變換都提供了三種操作方式:set(用於設置Matrix中的值)、post(後乘,根據矩陣的原理,相當於左乘)、pre(先乘,相當於矩陣中的右乘)。默認時,這四種變換都是圍繞(0,0)點變換的,當然可以自定義圍繞的中心點,通常圍繞中心點。
首先說說平移,在對圖片處理的過程中,最常用的就是對圖片進行平移操作,該方法為setTranslate(),平移意味著在x軸和y軸上簡單地移動圖像。setTranslate方法采用兩個浮點數作為參數,表示在每個軸上移動的數量。第一個參數是圖像將在x軸上移動的數量,而第二個參數是圖像將在y軸上移動的數量。在x軸上使用正數進行平移將向右移動圖像,而使用負數將向左移動圖像。在y軸上使用正數進行平移將向下移動圖像,而使用負數將向上移動圖像。
再看縮放,Matrix類中另一個有用的方法是setScale方法。它采用兩個浮點數作為參數,分別表示在每個軸上所產生的縮放量。第一個參數是x軸的縮放比例,而第二個參數是y軸的縮放比例。如:matrix.setScale(1.5f,1);
比較復雜的就是圖片的旋轉了,內置的方法之一是setRotate方法。它采用一個浮點數表示旋轉的角度。圍繞默認點(0,0),正數將順時針旋轉圖像,而負數將逆時針旋轉圖像,其中默認點是圖像的左上角,如:
Matrix matrix = new Matrix();
matrix.setRotate(15);
另外,也可以使用旋轉的角度及圍繞的旋轉點作為參數調用setRotate方法。選擇圖像的中心點作為旋轉點,如:
matrix.setRotate(15,bmp.getWidth()/2,bmp.getHeight()/2);
對於錯切變換,由於本博主的知識有限這裡不作解釋。
了解這些基礎知識後,我們開始實現我們的功能先上圖:
第一張加一個標注物眼睛附近
這裡寫圖片描述
第二張放大後眼睛那個標注物不見了
這裡寫圖片描述
第三張移動後那個標注物顯示出來,並且繼續添加一個標注物第二個標注物手附近
這裡寫圖片描述
縮小之後我們點擊標注物看打印信息,如果點擊的是標注物則打印出第幾個標注物,如果點擊的不是標注物則新增標志物截圖如下
這裡寫圖片描述
這裡寫圖片描述
基本功能實現代碼如下:

package test.com.surfaceviewoverlay;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.FloatMath;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.TabHost;
import android.widget.Toast;

import java.util.ArrayList;


/**
 * Created by Administrator on 2016/5/20.
 */
public class OverSurfaceView extends SurfaceView implements SurfaceHolder.Callback,Runnable{
    private static final String TAG="測試";
    private Canvas canvas = null; //定義畫布
    private Thread th = null;     //定義線程
    private SurfaceHolder sfh = null;
    //不支持下面兩種模式
    private static final int NONE = 0;
    private static final int CLICK=3;//單點模式
    /** 拖拉照片模式 */
    private static final int DRAG = 1;
    //放大縮小模式
    private static final int ZOOM = 2;
    //初始化為空模式
    private int mode = NONE;
    private PointF start = new PointF();
    private PointF mid = new PointF();
    /** 最後一次觸摸時的位置 */
    private PointF end = new PointF();
    /** 地圖中心位置中心 */
    private PointF screenCenter = new PointF();
    /** 圖紙寬高 */
    private PointF mapCenter = new PointF();
    private Bitmap bm;//加載的地圖
    /** 標注點 */
    // 縮放倍率
    private float rate = 1f;
    //圖片縮放前後連個手指間的距離
    private float oldDist = 1f;
    private float newDist;
    private float oldRate = 1;
    private Bitmap b;//標注物
    //控件寬高
    private int h;
    private Matrix matrix;
    private int w;
    //圖片長寬
    private int mapH;
    private int mapW;
    private float scaleH;//原始高縮放比例
    private float scaleW;//原始寬縮放比例
    private ArrayList positionPoints;//裝標注點信息的點
    public OverSurfaceView(Context context) {
        super(context);
        sfh = getHolder();
        sfh.addCallback(this);
        th = new Thread(this);
        positionPoints=new ArrayList<>();
    }//,沒有自定義屬性,不需要再xml中使用所以只重載這個構造方法

    public OverSurfaceView(Context context, AttributeSet attrs) {
        super(context, attrs);//在xml中使用就要定義這個構造方法
        sfh = getHolder();
        sfh.addCallback(this);
        th = new Thread(this);
    }

    @Override
    public void run() {

    }
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        bm = BitmapFactory.decodeResource(getResources(), R.drawable.mv);
        mapH=bm.getHeight();
        mapW=bm.getWidth();
        h=getHeight();
        w=getWidth();
        screenCenter.set(w/2, h/2);
        mapCenter.set( mapW/2, mapH/2);//記錄地圖中心位置
        calculateScale();
        draw();
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {

    }
    private void draw()
    {
        canvas  = sfh.lockCanvas() ;
        Paint paint=new Paint();
        matrix = new Matrix();

        matrix.setScale(rate, rate,mapCenter.x, mapCenter.y);
        matrix.postTranslate(screenCenter.x+(end.x - start.x)- mapCenter.x
                ,screenCenter.y+(end.y - start.y) - mapCenter.y );

            Log.e("rate1",""+rate+","+bm.getHeight()+","+bm.getWidth()+","+screenCenter.x+","+mapCenter.x*rate);
        canvas.drawColor(Color.WHITE);
        canvas.drawBitmap(bm, matrix,paint);
       /*//**背景顏色*//*
        *//**標注坐標*//*
        *//** 畫標注點 */
        b = BitmapFactory.decodeResource(getResources(), R.drawable.marker);
        Matrix matrix=new Matrix();
       for(int i=0;i 10f) {
                        screenCenter.x=getWidth()/2;
                        screenCenter.y=getHeight()/2;
                        midPoint(mid, event);
                        mode = ZOOM;
                    }
                    break;
                case MotionEvent.ACTION_UP:
                    boolean flag=whichItemImage(start.x, start.y);
                    oldRate = rate;
                    float x= (float) Math.sqrt((event.getX()-start.x)*(event.getX()-start.x)+ (event.getY()-start.y)*(event.getY()-start.y));
                    if (x<10&&mode==click&&flag){ positionpoint="new" screencenter.x-="" screencenter.y-="" else="" mode="=CLICK&&x" screencenter.x="" end.x="" -="" screencenter.y="" end.y="" motionevent.action_pointer_up:="" motionevent.action_move:="" x="(float)" if="">10){//設置最後一個點的位置
                        if(screenCenter.x+(event.getX()-start.x) 10f&&((newDist-oldDist)>10||(newDist-oldDist)<-10)){
                            rate = oldRate * (newDist / oldDist);//設置縮放比例
                            draw();
                        }
                    }

                    break;
            }
            return true;
        }

    /**
     * 對所畫點的判斷,因為圖片比較小,所以在坐標點上X、Y點分別加減20dp像素,也就是在正常的情況下圖片的點擊區域是一個邊長為40dp的正方形,
     * 因為涉及到縮放,需要乘以Scale(縮放比例)所以點擊區域大小也是變的
     */
    public boolean whichItemImage(float x, float y) {
        boolean flag=true;

        for (int i = 0; i < positionPoints.size(); i++) {
            float x1 = screenCenter.x + (end.x - start.x)
                    - bm.getWidth() * rate / 2 + positionPoints.get(i).getPointX() * rate
                    + 40;
            float x2 = screenCenter.x + (end.x - start.x)
                    - bm.getWidth() * rate / 2 + positionPoints.get(i).getPointX() * rate
                    - 40;
            float y1 = screenCenter.y + (end.y - start.y)
                    - bm.getHeight() * rate / 2 + positionPoints.get(i).getPointY() * rate
                    + 68;
            float y2 = screenCenter.y + (end.y - start.y)
                    - bm.getHeight() * rate / 2 + positionPoints.get(i).getPointY() * rate
                    - 68;
            Log.d(TAG, "x1========" + x1);
            Log.d(TAG, "x2========" + x2);
            Log.d(TAG, "y1========" + y1);
            Log.d(TAG, "y2========" + y2);
            if (x <= x1 && x >= x2 && y <= y1 && y >= y2) {
                Log.e("你點擊了哪個按鈕", ""+i);
                flag=false;
            }
        }
  return flag;
    }
    private float spacing(MotionEvent event) {
        float x = event.getX(0) - event.getX(1);
        float y = event.getY(0) - event.getY(1);
        return  (float)Math.sqrt(x * x + y * y);
    }
//求重點坐標
    private void midPoint(PointF point, MotionEvent event) {
        float x = event.getX(0) + event.getX(1);
        float y = event.getY(0) + event.getY(1);
        point.set(x / 2, y / 2);
    }
}

由於時間關系我會在下一篇博客將代碼解釋清楚,並詳細的告訴讀者在實現功能的時候注意細節。

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