日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

android 画布 轨迹,Android 多点触控,绘制滑动轨迹和十字光标

發布時間:2023/12/29 Android 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 android 画布 轨迹,Android 多点触控,绘制滑动轨迹和十字光标 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

這個測試項,要捕捉當前有幾個觸摸點,當前觸摸點坐標,滑動事件在x軸、y軸方向的速度等信息,在觸摸時跟隨觸摸點會出現十字光標,繪制出滑動軌跡。

首先繪制出暗色格子背景,采用了自定義View,較為簡單,核心代碼如下:

Paint paint; //畫筆

private int mWidth;

private int mHeight;

public Check(Context context, AttributeSet attrs) {

super(context, attrs);

paint = new Paint();

paint.setColor(getResources().getColor(R.color.deepGray));//設置畫筆顏色

paint.setStrokeJoin(Paint.Join.ROUND);//設置畫筆圖形接觸時筆跡的形狀

paint.setStrokeCap(Paint.Cap.ROUND);//設置畫筆離開畫板時筆跡的形狀

paint.setStrokeWidth(1); //設置畫筆的寬度

}

/**

* 這個方法可以獲得控件的寬高

* @param canvas

*/

@Override

protected void onSizeChanged(int w, int h, int oldw, int oldh) {

mWidth = w;

mHeight = h;

}

/**

* 繪制網格線

* @param canvas

*/

@Override

protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

canvas.drawColor(Color.BLACK);

int lineStart = 80;

int space = lineStart; //長寬間隔

int vertz = lineStart;

int hortz = lineStart;

for (int i = 0; i < 100; i++) {

canvas.drawLine(0, vertz, mWidth, vertz, paint);

canvas.drawLine(hortz, 0, hortz, mHeight, paint);

vertz += space;

hortz += space;

}

}

接下來,因為要在這個背景上畫圖,我在其上覆蓋一層透明ImageView,給該iv設置這個屬性:

android:background="@android:color/transparent"

接下來的繪制滑動軌跡和十字光標都在這個iv上完成。

接下來遇到了一些坑,都踩了一遍。

因為這個繪圖是發生在一個Fragment里,我的繪圖界面要設置全屏,但是該Activity中的其他Fragment則不需要這個設置。于是就在這個Fragment中獲取到Window,然后設置全屏標記,然后讓根視圖MATCH_PARENT。

getActivity().getWindow().setFlags(

WindowManager.LayoutParams.FLAG_FULLSCREEN,

WindowManager.LayoutParams.FLAG_FULLSCREEN);

//mRootView是BaseFragment中設置的該Fragment的視圖

this.mRootView.setLayoutParams(

new FrameLayout.LayoutParams(

FrameLayout.LayoutParams.MATCH_PARENT,

FrameLayout.LayoutParams.MATCH_PARENT));

創建bitmap,設置bitmap的高寬時,遇到了問題。

因為在onCreateView中View.getWidth和View.getHeight無法獲得一個view的高度和寬度,這是因為View組件布局要在onResume回調后完成。所以現在需要使用getViewTreeObserver().addOnGlobalLayoutListener()來獲得寬度或者高度。這是獲得一個view的寬度和高度的方法之一。

OnGlobalLayoutListener 是ViewTreeObserver的內部類,當一個視圖樹的布局發生改變時,可以被ViewTreeObserver監聽到,這是一個注冊監聽視圖樹的觀察者(observer),在視圖樹的全局事件改變時得到通知。ViewTreeObserver不能直接實例化,而是通過getViewTreeObserver()獲得。

mTouchScreenIv.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {

@Override

public void onGlobalLayout() {

mTouchScreenIvWidth = mTouchScreenIv.getWidth();

mTouchScreenIvHeight = mTouchScreenIv.getHeight();

// 創建空白圖片

mBitmap1 = Bitmap.createBitmap(mTouchScreenIvWidth, mTouchScreenIvHeight, Bitmap.Config.ARGB_8888);

mBitmap2 = Bitmap.createBitmap(mTouchScreenIvWidth, mTouchScreenIvHeight, Bitmap.Config.ARGB_8888);

// 創建兩張畫布

mCanvas1 = new Canvas(mBitmap1); //底層畫軌跡的畫布

mCanvas2 = new Canvas(mBitmap2); //上面一層畫十字架的畫布

// 創建畫筆

mPaint1 = new Paint(); //畫軌跡的畫筆

mPaint2 = new Paint(); //畫十字架的畫筆

// 畫筆顏色為藍色

mPaint1.setColor(getResources().getColor(R.color.lightBlue));

mPaint2.setColor(getResources().getColor(R.color.lightBlue));

// 寬度1個像素

mPaint1.setStrokeWidth(1);

mPaint2.setStrokeWidth(1);

// 先將白色背景畫上

mCanvas1.drawBitmap(mBitmap1, new Matrix(), mPaint1);

mCanvas2.drawBitmap(mBitmap2, new Matrix(), mPaint2);

mBitmap3 = mergeBitmap(mBitmap1, mBitmap2);//將兩張bitmap圖合為一張

mTouchScreenIv.setImageBitmap(mBitmap3);

//用完要解除監聽

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {

mTouchScreenIv.getViewTreeObserver().removeOnGlobalLayoutListener(this);

}

}

});

把兩個bitmap合成一個bitmap

/**

* 把兩個位圖覆蓋合成為一個位圖,以底層位圖的長寬為基準

* @param backBitmap 在底部的位圖

* @param frontBitmap 蓋在上面的位圖

* @return

*/

public Bitmap mergeBitmap(Bitmap backBitmap, Bitmap frontBitmap) {

if (backBitmap == null || backBitmap.isRecycled()

|| frontBitmap == null || frontBitmap.isRecycled()) {

Log.e(TAG, "backBitmap=" + backBitmap + ";frontBitmap=" + frontBitmap);

return null;

}

Bitmap bitmap = backBitmap.copy(Bitmap.Config.ARGB_8888, true);

Canvas canvas = new Canvas(bitmap);

Rect baseRect = new Rect(0, 0, backBitmap.getWidth(), backBitmap.getHeight());

Rect frontRect = new Rect(0, 0, frontBitmap.getWidth(), frontBitmap.getHeight());

canvas.drawBitmap(frontBitmap, frontRect, baseRect, null);

return bitmap;

}

給iv控件設置觸摸事件。因為是多點觸摸事件,所以記錄down的起始點和move時的終止點都需要使用float數組。設置四個大小為10的數組。

添加 觸摸事件的速度檢測器。

單點觸摸事件ACTION_DOWN ,多點觸摸事件ACTION_POINTER_DOWN,使用case穿透將兩種事件一起監聽,遍歷觸摸事件,獲得坐標,進行操作。

@Override

protected void setListener() {

mTouchScreenCheck.setOnTouchListener(new View.OnTouchListener() {

@Override

public boolean onTouch(View view, MotionEvent motionEvent) {

//當前DOWN或者UP的是手指的index

int curPointerIndex = motionEvent.getActionIndex();

//通過index獲得當前手指的id

int curPointerId = motionEvent.getPointerId(curPointerIndex);

//添加事件的速度計算器

if (mVelocityTracker == null) {

mVelocityTracker = VelocityTracker.obtain();

}

mVelocityTracker.addMovement(motionEvent);

int actionMasked = motionEvent.getActionMasked();

Log.i(TAG, "actionMasked === " + actionMasked);

switch (actionMasked) {

case MotionEvent.ACTION_DOWN:

case MotionEvent.ACTION_POINTER_DOWN:

mCanvas1.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);

mCanvas2.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);

mTouchScreenIv.setImageBitmap(mergeBitmap(mBitmap1, mBitmap2));

//設置當前有幾個觸摸點

pointerCount = motionEvent.getPointerCount();

if (pointerCount > 10) {

pointerCount = 10;

}

mActivePointers.append(curPointerId, curPointerId);

//在down事件中的操作

DownPoint(motionEvent);

mTouchScreenIv.setImageBitmap(mergeBitmap(mBitmap1, mBitmap2));

break;

case MotionEvent.ACTION_MOVE:

//獲取當前觸摸事件的個數

if (motionEvent.getPointerCount() > pointerCount) {

pointerCount = motionEvent.getPointerCount();

}

mTouchScreenTvP.setText("P:" + motionEvent.getPointerCount() + "/" + pointerCount);

//清除十字架

mCanvas2.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);

//在移動時的操作

MovePoint(motionEvent);

mTouchScreenIv.setImageBitmap(mergeBitmap(mBitmap1, mBitmap2));

break;

case MotionEvent.ACTION_UP:

case MotionEvent.ACTION_POINTER_UP:

//計算并顯示坐標偏移量,并且設置背景顏色

setDxDy(motionEvent);

//清除十字架

mCanvas2.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);

//清除這個觸摸事件的ID

mActivePointers.remove(curPointerId);

mTouchScreenTvP.setText("P:" + 0 + "/" + pointerCount);

mTouchScreenIv.setImageBitmap(mergeBitmap(mBitmap1, mBitmap2));

break;

}

return true;

}

});

}

/**

* 在down事件中的操作

* @param motionEvent

*/

private void DownPoint(MotionEvent motionEvent) {

for (int i = 0; i < motionEvent.getPointerCount(); i++) {

int pointerId = mActivePointers.get(motionEvent.getPointerId(i));

try {

//獲取觸摸點的X,y坐標

startXs[pointerId] = motionEvent.getX(pointerId);

startYs[pointerId] = motionEvent.getY(pointerId);

finalStartX = startXs[pointerId];

finalStartY = startYs[pointerId];

//設置上面的字變化并且背景顏色為白色

mTouchScreenTvDx.setText("X:" + Math.round(motionEvent.getX(pointerId) * 10) / 10.0);

mTouchScreenTvDx.setBackgroundColor(Color.WHITE);

mTouchScreenTvDy.setText("Y:" + Math.round(motionEvent.getY(pointerId) * 10) / 10.0);

mTouchScreenTvDy.setBackgroundColor(Color.WHITE);

} catch (IllegalArgumentException e) {

// 此處捕捉系統bug,以防程序停止

e.printStackTrace();

}

mTouchScreenTvP.setText("P:" + pointerCount + "/" + pointerCount);

// 在開始和結束坐標間畫一個點

mCanvas1.drawPoint(startXs[pointerId], startYs[pointerId], mPaint1);

//畫十字架

mCanvas2.drawLine(0, startYs[pointerId], mTouchScreenIvWidth, startYs[pointerId], mPaint2);

mCanvas2.drawLine(startXs[pointerId], 0, startXs[pointerId], mTouchScreenIvHeight, mPaint2);

}

}

/**

* 在移動時對點的操作

* @param motionEvent

*/

private void MovePoint(MotionEvent motionEvent) {

for (int i = 0; i < motionEvent.getPointerCount(); i++) {

int pointerId = mActivePointers.get(motionEvent.getPointerId(i));

Log.i(TAG, "1111111 move pointerId" + pointerId);

Log.i(TAG, "1111111 endXS size " + endXs.length);

try {

// 獲取手移動后的坐標

endXs[pointerId] = motionEvent.getX(pointerId);

endYs[pointerId] = motionEvent.getY(pointerId);

// 在開始和結束坐標間畫一條線

mCanvas1.drawLine(startXs[pointerId], startYs[pointerId], endXs[pointerId], endYs[pointerId], mPaint1);

//重新畫十字架

mCanvas2.drawLine(0, endYs[pointerId], mTouchScreenIvWidth, endYs[pointerId], mPaint2);

mCanvas2.drawLine(endXs[pointerId], 0, endXs[pointerId], mTouchScreenIvHeight, mPaint2);

//設置顯示坐標的數字變化并且背景顏色為白色

mTouchScreenTvDx.setText("X:" + Math.round(endXs[pointerId] * 10) / 10.0);

mTouchScreenTvDx.setBackgroundColor(Color.WHITE);

mTouchScreenTvDy.setText("Y:" + Math.round(endYs[pointerId] * 10) / 10.0);

mTouchScreenTvDy.setBackgroundColor(Color.WHITE);

//獲取當前觸摸事件的速度

mVelocityTracker.computeCurrentVelocity(10);

mTouchScreenTvXv.setText("Xv:" +

Math.round(mVelocityTracker.getXVelocity(0) * 1000) / 1000.0 + "");

mTouchScreenTvYv.setText("Yv:" +

Math.round(mVelocityTracker.getYVelocity(0) * 1000) / 1000.0 + "");

// 刷新開始坐標

startXs[pointerId] = (int) motionEvent.getX(pointerId);

startYs[pointerId] = (int) motionEvent.getY(pointerId);

} catch (IllegalArgumentException e) {

// TODO Auto-generated catch block

e.printStackTrace();

Log.i(TAG, "11111:IllegalArgumentException ");

}

}

}

/**

* 計算并顯示坐標偏移量,并且設置背景顏色

* @param motionEvent

*/

private void setDxDy(MotionEvent motionEvent) {

float dx = motionEvent.getX() - finalStartX;

float dy = motionEvent.getY() - finalStartY;

mTouchScreenTvDx.setText("dX:" + Math.round(dx * 10) / 10.0);

if (dx > 0.1 || dx < -0.1) {

mTouchScreenTvDx.setBackgroundColor(Color.RED);

} else {

mTouchScreenTvDx.setBackgroundColor(Color.WHITE);

}

mTouchScreenTvDy.setText("dY:" + Math.round(dy * 10) / 10.0);

if (dy > 0.1 || dy < -0.1) {

mTouchScreenTvDy.setBackgroundColor(Color.RED);

} else {

mTouchScreenTvDy.setBackgroundColor(Color.WHITE);

}

}

ACTION_DOWN :當觸摸到第一個點時,被觸發

ACTION_POINTER_DOWN:當控件上已經有點被觸摸,再次有點被觸摸時,觸發該事件。

ACTION_UP 和 ACTION_POINTER_UP 也是類似的,最后一個點抬起時才觸發ACTION_UP。

但是ACTION_MOVE沒有類似的方法,可以通過遍歷觸摸事件,獲得每一個觸摸事件。

在觸摸時每一個觸摸事件會被分配一個id,通過不同的id獲取每一個觸摸點的坐標。

遺留bug:每當有新的觸摸事件時,以前的滑動軌跡會被清空。

總結

以上是生活随笔為你收集整理的android 画布 轨迹,Android 多点触控,绘制滑动轨迹和十字光标的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。