Android自定义万能Canvas画布

原创 2017年07月15日 01:10:11

一、需求:

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

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

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

二、实现思想:

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

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

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

三、效果展示:


四、具体实现:

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

   <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <com.view.ActionEditorCanvasView
            android:id="@+id/action_editor_canvas_gamepad_test"
            android:visibility="gone"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
        <com.view.ActionEditorCanvasView
            android:id="@+id/action_editor_canvas_test"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
    </RelativeLayout>
2.当控件添加到画布中要获取到对应控件的位置信息(将添加的控件添加到一个集合中),判断点击时是否是落在控件之上,这些都是在view中的onTouchEvent(MotionEvent event)进行处理:

 private int getDown2Widget() {
        for (int i = 0; i < mDrawableList.size(); i++) {
            int xcoords = mDrawableList.get(i).getXcoords();
            int ycoords = mDrawableList.get(i).getYcoords();
            double abs = Math.sqrt((DownX - xcoords) * (DownX - xcoords) + (DownY - ycoords) * (DownY - ycoords));
            //点落在控件内
            if (abs < ActionWidget.RADIUS) {
                return i;
            }
        }
        return -1;
    }
3、在画布中实现Move、LongPress、Up、Click的接口回调用于对外应用:

    public onWidgetUpListener mOnWidgetUpListener;
    public interface onWidgetUpListener{
        void onWidgetUp(int index,int x,int y);
    }

    public void  setOnWidgetUpListener(onWidgetUpListener mOnWidgetUpListener){
        this.mOnWidgetUpListener=mOnWidgetUpListener;
    }

    public onWidgetMoveListener mOnWidgetMoveListener;

    public interface onWidgetMoveListener{
         void onWidgetMove(int index,int x,int y);
    }

    public void  setOnWidgetMoveListener(onWidgetMoveListener moveListener){
        this.mOnWidgetMoveListener=moveListener;
    }

    public onWidgetLongPressListener mOnWidgetLongPressListener;

    public interface onWidgetLongPressListener{
        void onWidgetLongPress(int index,int x,int y);
    }

    public void setOnWidgetLongPressListener(onWidgetLongPressListener mOnWidgetLongPressListener){
        this.mOnWidgetLongPressListener=mOnWidgetLongPressListener;
    }


    public onWidgetClickListener mOnWidgetClickListener;

    public interface onWidgetClickListener{
        void onWidgetClick(int index,int x,int y);
    }

    public void setOnWidgetClickListener(onWidgetClickListener mOnWidgetClickListener){
        this.mOnWidgetClickListener=mOnWidgetClickListener;
    }
4.接下来就是处理拖动、点击、长按、抬起的事件的处理:

 public boolean onTouchEvent(MotionEvent event) {       
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN: {
                mDownTime = System.currentTimeMillis();
                DownX = event.getX();//float DownX
                DownY = event.getY();//float DownY
                //判断点击的坐标范围是否在控件上
                mDown2Widget = getDown2Widget();
                moveX = 0;
                moveY = 0;
                moveX1 = 0;
                moveY1 = 0;
            }
            break;
            case MotionEvent.ACTION_MOVE: {
                moveX += Math.abs(event.getX() - DownX);//X轴距离
                moveY += Math.abs(event.getY() - DownY);//y轴距离
                moveX1 = event.getX();
                moveY1 = event.getY();
                if (moveX == 0 && moveY == 0) {
                    mMoveTime = System.currentTimeMillis();
                    long DValueTime = mMoveTime - mDownTime;//计算点击下去是否有移动及事件是否符合长按的时间值,这样可以判断是否是长按事件
                    if (DValueTime>200){	
                        if (mOnWidgetLongPressListener!=null){
                            mOnWidgetLongPressListener.onWidgetLongPress(mDown2Widget,(int)moveX1,(int)moveY1);
                        }
                    }
                    return true;
                } else {
                    if (mDown2Widget > -1) {
                        if (mOnWidgetMoveListener!=null){
                            mOnWidgetMoveListener.onWidgetMove(mDown2Widget,(int)moveX1,(int)moveY1);
                        }
                        mDrawableList.get(mDown2Widget).setXcoords((int) moveX1);//点击在控件之上进行的move则把控件坐标值重置,从而是实现控件拖动
                        mDrawableList.get(mDown2Widget).setYcoords((int) moveY1);
                        invalidate();
                    }
                }
                DownX = event.getX();
                DownY = event.getY();
            }
            break;
            case MotionEvent.ACTION_UP: {
                long moveTime = System.currentTimeMillis() - currentMS;//移动时间
                mUpTime = System.currentTimeMillis();
                long DValueTime = mUpTime - mDownTime;//判断从按下到抬起的实现,从而实现判断是否是点击
                if (mDown2Widget > -1) {
                    //判断是否为拖动事件
                    if (!(moveTime > 1000 && (moveX > 100 || moveY > 100))) {
                        if (DValueTime < 200) {
                            if (mOnWidgetClickListener!=null){
                                mOnWidgetClickListener.onWidgetClick(mDown2Widget,(int)moveX1,(int)moveY1);
                            }
                        }
                    }
                }
                if (mOnWidgetUpListener!=null){//判断是否是抬起事件
                    mOnWidgetUpListener.onWidgetUp(mDown2Widget,(int)moveX1,(int)moveY1);
                }
            }
            break;
        }
        return true;

    }

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

        mBitmap= BitmapFactory.decodeResource(getResources(),R.drawable.ic_launcher);
        mGamePadBitmap=new CBitmap(mBitmap,200,1000);
        mXcoords = mGamePadBitmap.getXcoords();
        mYcoords = mGamePadBitmap.getYcoords();
        mGamePadCanvasView.addCanvasDrawable(mGamePadBitmap);

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

       mCanvasView.setOnWidgetLongPressListener(new ActionEditorCanvasView.onWidgetLongPressListener() {
            @Override
            public void onWidgetLongPress(int index, int x, int y) {
                ActionWidget actionWidget = (ActionWidget) mCanvasView.mDrawableList.get(index);
                mCanvasView.setVisibility(View.GONE);
                mGamePadCanvasView.setVisibility(View.VISIBLE);
                mGamePadWidget=new ActionWidget(x, y, mPaint);
                mGamePadCanvasView.addCanvasDrawable(mGamePadWidget);
                isGamePadCanvas=true;//把是否显示底层画布的开关开启
            }
        });
7、判断A控件是否移动B控件的位置范围之上:

mCanvasView.setOnWidgetMoveListener(new ActionEditorCanvasView.onWidgetMoveListener() {
            @Override
            public void onWidgetMove(int index, int x, int y) {
                if (isGamePadCanvas){
                    if (mGamePadWidget!=null){
                        mGamePadCanvasView.mDrawableList.get(1).setXcoords(x);
                        mGamePadCanvasView.mDrawableList.get(1).setYcoords(y);
                        mGamePadCanvasView.invalidate();
                        if ((x>mXcoords&&x<mXcoords+250)&&(y>mYcoords&&y<mYcoords+250)){
                            Toast.makeText(ActionCanvasTestActivity.this, "控件移动到控制器按钮界面!!!!!" , Toast.LENGTH_SHORT).show();
                        }
                    }
               }
            }
        });
8、最后是判断抬起事件,如底层画布是显示则隐藏底层画布显示第一层画布:
      mCanvasView.setOnWidgetUpListener(new ActionEditorCanvasView.onWidgetUpListener() {
            @Override
            public void onWidgetUp(int index, int x, int y) {
                if (isGamePadCanvas){
                    mCanvasView.setVisibility(View.VISIBLE);
                    mGamePadCanvasView.setVisibility(View.GONE);
                    mGamePadCanvasView.mDrawableList.remove(1);
                    isGamePadCanvas=false;
                }
            }
        });

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


版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

Blockly在Android中的集成及源码分析

在Android中集成Blockly模块可以通过拖拽类似于搭建积木的方式来实现基本的逻辑和操作的编程,这种图形化的编程之后最终的结果能以代码的形式显示出来或能用这样的代码去操控机器人。 1.实现的过程...

android中自定义画布Canvas的实现

一、要求: 1.画布绘制控件的方法,控件应该是一个可以自定义的; 2.画布是可以缩放,且提供一个缩放的方法供外使用; 3.控件之间连线的方法; 4.画布缩放之后手势滑动的识别实现; 二、在gith...

android自定义控件画布canvas背景色失效变黑色

错误示范: *********************************************************************************************...

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

(转自:http://blog.csdn.net/danfengw/article/details/48503619)     今天学习了Canvas画布,感觉挺好玩的,通过它我们可以自定...
  • Baby_T
  • Baby_T
  • 2016年10月17日 10:55
  • 502

Android自定义View(六)_Canvas之画布操作

上一篇Canvas之绘制基本形状中我们了解了如何使用Canvas绘制基本图形,本次了解一些基本的画布操作。本来想把画布操作放到后面部分的,但是发现很多图形绘制都离不开画布操作,于是先讲解一下画布的基本...

【Android】自定义View、画布Canvas与画笔Paint

安卓自定义View其实很简单。这个View可以像《【Android】利用Java代码布局,按钮添加点击事件》(点击打开链接)一样,利用Java代码生成一系列的组件。也可以配合画布Canvas与画笔Pa...

android 中的绘制类Paint 画笔,Canvas 画布,Bitmap 类和BitmapFactory及自定义属性

常用的绘图类是Paint 画笔,Canvas 画布,Bitmap 类和BitmapFactoryPaint类Paint类代表画笔,用来描述图形的颜色和风格,如线宽,颜色,透明度,和填充效果等信 息,...

【Android】自定义View、画家(画布)Canvas与画笔Paint的应用——画图、涂鸦板app的实现

利用一个简单的画图app来说明安卓的图形处理类与自定义View的应用。 如下图,有一个供用户自己任意画图、涂鸦的app, 这里不做那么花俏了,仅提供黑白两色,但可以改变笔尖的粗细。 实质...

Android自定义画布及环形菜单

  • 2017年07月02日 11:16
  • 24.09MB
  • 下载

安卓之自定义UI(画布Canvas)

1.什么是画布? 画布(Canvas)是图形编程中一个很普通的概念,通常由三个基本的绘图组件组成:        1.Canvas  提供了绘图方法,可以向底层的位图绘制基本图形。       ...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Android自定义万能Canvas画布
举报原因:
原因补充:

(最多只允许输入30个字)