Android自定义万能Canvas画布

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android自定义万能Canvas画布相关的知识,希望对你有一定的参考价值。

一、需求:

1.在自定义的画布中实现可缩放手势,摇一摇可对控件进行整理排序;

2.画布中可以添加位置设定的控件,控件可以响应点击、长按、拖动事件;

3.控件A长按事件会隐藏画布中的控件除了A之外,显示另一个控件B;当A在在底层画布中拖动,拖动结束之后回到原画布;当A移动B的位置范围响应操作(可以添加另方面功能)。

二、实现思想:

1、画布的的手势缩放、控件的添加,在我的上一篇关于画布文章中已经实现了这个功能,这里不再赘述;

2、要实现上述的几个功能只需要屏幕上添加两层画布,一层画布用于添加控件在这层中可以实现控件的点击、拖动、画布缩放、长按事件、整理排序控件。底层画布用于长按其他控件隐藏之后A控件的拖动和B控件的显示及A拖动到B之后的事件响应。

3、当A控件结束拖动(抬起时)回到第一层画布中。

三、效果展示:

技术分享

四、具体实现:

1.先添加两层画布用布局可以RelativeLayout包裹着,如:

[html] view plain copy
 
 技术分享技术分享
  1. <RelativeLayout  
  2.      android:layout_width="match_parent"  
  3.      android:layout_height="match_parent">  
  4.      <com.view.ActionEditorCanvasView  
  5.          android:id="@+id/action_editor_canvas_gamepad_test"  
  6.          android:visibility="gone"  
  7.          android:layout_width="match_parent"  
  8.          android:layout_height="match_parent"/>  
  9.      <com.view.ActionEditorCanvasView  
  10.          android:id="@+id/action_editor_canvas_test"  
  11.          android:layout_width="match_parent"  
  12.          android:layout_height="match_parent"/>  
  13.  </RelativeLayout>  

2.当控件添加到画布中要获取到对应控件的位置信息(将添加的控件添加到一个集合中),判断点击时是否是落在控件之上,这些都是在view中的onTouchEvent(MotionEvent event)进行处理:

 

 

[java] view plain copy
 
 技术分享技术分享
  1. private int getDown2Widget() {  
  2.        for (int i = 0; i < mDrawableList.size(); i++) {  
  3.            int xcoords = mDrawableList.get(i).getXcoords();  
  4.            int ycoords = mDrawableList.get(i).getYcoords();  
  5.            double abs = Math.sqrt((DownX - xcoords) * (DownX - xcoords) + (DownY - ycoords) * (DownY - ycoords));  
  6.            //点落在控件内  
  7.            if (abs < ActionWidget.RADIUS) {  
  8.                return i;  
  9.            }  
  10.        }  
  11.        return -1;  
  12.    }  

3、在画布中实现Move、LongPress、Up、Click的接口回调用于对外应用:

 

 

[java] view plain copy
 
 技术分享技术分享
  1. public onWidgetUpListener mOnWidgetUpListener;  
  2. public interface onWidgetUpListener{  
  3.     void onWidgetUp(int index,int x,int y);  
  4. }  
  5.   
  6. public void  setOnWidgetUpListener(onWidgetUpListener mOnWidgetUpListener){  
  7.     this.mOnWidgetUpListener=mOnWidgetUpListener;  
  8. }  
  9.   
  10. public onWidgetMoveListener mOnWidgetMoveListener;  
  11.   
  12. public interface onWidgetMoveListener{  
  13.      void onWidgetMove(int index,int x,int y);  
  14. }  
  15.   
  16. public void  setOnWidgetMoveListener(onWidgetMoveListener moveListener){  
  17.     this.mOnWidgetMoveListener=moveListener;  
  18. }  
  19.   
  20. public onWidgetLongPressListener mOnWidgetLongPressListener;  
  21.   
  22. public interface onWidgetLongPressListener{  
  23.     void onWidgetLongPress(int index,int x,int y);  
  24. }  
  25.   
  26. public void setOnWidgetLongPressListener(onWidgetLongPressListener mOnWidgetLongPressListener){  
  27.     this.mOnWidgetLongPressListener=mOnWidgetLongPressListener;  
  28. }  
  29.   
  30.   
  31. public onWidgetClickListener mOnWidgetClickListener;  
  32.   
  33. public interface onWidgetClickListener{  
  34.     void onWidgetClick(int index,int x,int y);  
  35. }  
  36.   
  37. public void setOnWidgetClickListener(onWidgetClickListener mOnWidgetClickListener){  
  38.     this.mOnWidgetClickListener=mOnWidgetClickListener;  
  39. }  

4.接下来就是处理拖动、点击、长按、抬起的事件的处理:

[java] view plain copy
 
 技术分享技术分享
  1. public boolean onTouchEvent(MotionEvent event) {         
  2.        switch (event.getAction()) {  
  3.            case MotionEvent.ACTION_DOWN: {  
  4.                mDownTime = System.currentTimeMillis();  
  5.                DownX = event.getX();//float DownX  
  6.                DownY = event.getY();//float DownY  
  7.                //判断点击的坐标范围是否在控件上  
  8.                mDown2Widget = getDown2Widget();  
  9.                moveX = 0;  
  10.                moveY = 0;  
  11.                moveX1 = 0;  
  12.                moveY1 = 0;  
  13.            }  
  14.            break;  
  15.            case MotionEvent.ACTION_MOVE: {  
  16.                moveX += Math.abs(event.getX() - DownX);//X轴距离  
  17.                moveY += Math.abs(event.getY() - DownY);//y轴距离  
  18.                moveX1 = event.getX();  
  19.                moveY1 = event.getY();  
  20.                if (moveX == 0 && moveY == 0) {  
  21.                    mMoveTime = System.currentTimeMillis();  
  22.                    long DValueTime = mMoveTime - mDownTime;//计算点击下去是否有移动及事件是否符合长按的时间值,这样可以判断是否是长按事件  
  23.                    if (DValueTime>200){<span style="white-space:pre">    </span>  
  24.                        if (mOnWidgetLongPressListener!=null){  
  25.                            mOnWidgetLongPressListener.onWidgetLongPress(mDown2Widget,(int)moveX1,(int)moveY1);  
  26.                        }  
  27.                    }  
  28.                    return true;  
  29.                } else {  
  30.                    if (mDown2Widget > -1) {  
  31.                        if (mOnWidgetMoveListener!=null){  
  32.                            mOnWidgetMoveListener.onWidgetMove(mDown2Widget,(int)moveX1,(int)moveY1);  
  33.                        }  
  34.                        mDrawableList.get(mDown2Widget).setXcoords((int) moveX1);//点击在控件之上进行的move则把控件坐标值重置,从而是实现控件拖动  
  35.                        mDrawableList.get(mDown2Widget).setYcoords((int) moveY1);  
  36.                        invalidate();  
  37.                    }  
  38.                }  
  39.                DownX = event.getX();  
  40.                DownY = event.getY();  
  41.            }  
  42.            break;  
  43.            case MotionEvent.ACTION_UP: {  
  44.                long moveTime = System.currentTimeMillis() - currentMS;//移动时间  
  45.                mUpTime = System.currentTimeMillis();  
  46.                long DValueTime = mUpTime - mDownTime;//判断从按下到抬起的实现,从而实现判断是否是点击  
  47.                if (mDown2Widget > -1) {  
  48.                    //判断是否为拖动事件  
  49.                    if (!(moveTime > 1000 && (moveX > 100 || moveY > 100))) {  
  50.                        if (DValueTime < 200) {  
  51.                            if (mOnWidgetClickListener!=null){  
  52.                                mOnWidgetClickListener.onWidgetClick(mDown2Widget,(int)moveX1,(int)moveY1);  
  53.                            }  
  54.                        }  
  55.                    }  
  56.                }  
  57.                if (mOnWidgetUpListener!=null){//判断是否是抬起事件  
  58.                    mOnWidgetUpListener.onWidgetUp(mDown2Widget,(int)moveX1,(int)moveY1);  
  59.                }  
  60.            }  
  61.            break;  
  62.        }  
  63.        return true;  
  64.   
  65.    }  


5、在底层画布添加控件B,并获取位置信息存起来:

 

 

[java] view plain copy
 
 技术分享技术分享
  1. mBitmap= BitmapFactory.decodeResource(getResources(),R.drawable.ic_launcher);  
  2. mGamePadBitmap=new CBitmap(mBitmap,200,1000);  
  3. mXcoords = mGamePadBitmap.getXcoords();  
  4. mYcoords = mGamePadBitmap.getYcoords();  
  5. mGamePadCanvasView.addCanvasDrawable(mGamePadBitmap);  


6、处理长按事件,隐藏第一层画布显示底层画布,并获取A控件位置在底层画布中画出来:

 

 

[java] view plain copy
 
 技术分享技术分享
  1. mCanvasView.setOnWidgetLongPressListener(new ActionEditorCanvasView.onWidgetLongPressListener() {  
  2.      @Override  
  3.      public void onWidgetLongPress(int index, int x, int y) {  
  4.          ActionWidget actionWidget = (ActionWidget) mCanvasView.mDrawableList.get(index);  
  5.          mCanvasView.setVisibility(View.GONE);  
  6.          mGamePadCanvasView.setVisibility(View.VISIBLE);  
  7.          mGamePadWidget=new ActionWidget(x, y, mPaint);  
  8.          mGamePadCanvasView.addCanvasDrawable(mGamePadWidget);  
  9.          isGamePadCanvas=true;//把是否显示底层画布的开关开启  
  10.      }  
  11.  });  

7、判断A控件是否移动B控件的位置范围之上:

 

 

[java] view plain copy
 
 技术分享技术分享
  1. mCanvasView.setOnWidgetMoveListener(new ActionEditorCanvasView.onWidgetMoveListener() {  
  2.             @Override  
  3.             public void onWidgetMove(int index, int x, int y) {  
  4.                 if (isGamePadCanvas){  
  5.                     if (mGamePadWidget!=null){  
  6.                         mGamePadCanvasView.mDrawableList.get(1).setXcoords(x);  
  7.                         mGamePadCanvasView.mDrawableList.get(1).setYcoords(y);  
  8.                         mGamePadCanvasView.invalidate();  
  9.                         if ((x>mXcoords&&x<mXcoords+250)&&(y>mYcoords&&y<mYcoords+250)){  
  10.                             Toast.makeText(ActionCanvasTestActivity.this, "控件移动到控制器按钮界面!!!!!" , Toast.LENGTH_SHORT).show();  
  11.                         }  
  12.                     }  
  13.                }  
  14.             }  
  15.         });  

8、最后是判断抬起事件,如底层画布是显示则隐藏底层画布显示第一层画布:

[java] view plain copy
 
 技术分享技术分享
  1. mCanvasView.setOnWidgetUpListener(new ActionEditorCanvasView.onWidgetUpListener() {  
  2.       @Override  
  3.       public void onWidgetUp(int index, int x, int y) {  
  4.           if (isGamePadCanvas){  
  5.               mCanvasView.setVisibility(View.VISIBLE);  
  6.               mGamePadCanvasView.setVisibility(View.GONE);  
  7.               mGamePadCanvasView.mDrawableList.remove(1);  
  8.               isGamePadCanvas=false;  
  9.           }  
  10.       }  
  11.   });  

 

五、Demo项目地址:http://download.csdn.net/download/wangyongyao1989/9901019





以上是关于Android自定义万能Canvas画布的主要内容,如果未能解决你的问题,请参考以下文章

自定义view画图

Android 绘图基础:Canvas画布——自定义View基础(绘制表盘矩形圆形弧渐变)

Android自定义View(3) 《Canvas绘制简单的图形》

android 自定义view 怎么裁剪画布

Android自定义View实战教程5??---Canvas详解及代码绘制安卓机器人

Android自定义View实战教程5??---Canvas详解及代码绘制安卓机器人