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. public void  setOnWidgetUpListener(onWidgetUpListener mOnWidgetUpListener){
  6. this.mOnWidgetUpListener=mOnWidgetUpListener;
  7. }
  8. public onWidgetMoveListener mOnWidgetMoveListener;
  9. public interface onWidgetMoveListener{
  10. void onWidgetMove(int index,int x,int y);
  11. }
  12. public void  setOnWidgetMoveListener(onWidgetMoveListener moveListener){
  13. this.mOnWidgetMoveListener=moveListener;
  14. }
  15. public onWidgetLongPressListener mOnWidgetLongPressListener;
  16. public interface onWidgetLongPressListener{
  17. void onWidgetLongPress(int index,int x,int y);
  18. }
  19. public void setOnWidgetLongPressListener(onWidgetLongPressListener mOnWidgetLongPressListener){
  20. this.mOnWidgetLongPressListener=mOnWidgetLongPressListener;
  21. }
  22. public onWidgetClickListener mOnWidgetClickListener;
  23. public interface onWidgetClickListener{
  24. void onWidgetClick(int index,int x,int y);
  25. }
  26. public void setOnWidgetClickListener(onWidgetClickListener mOnWidgetClickListener){
  27. this.mOnWidgetClickListener=mOnWidgetClickListener;
  28. }

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. }

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

时间: 2024-10-11 12:32:17

Android自定义万能Canvas画布的相关文章

Android自定义View之画笔与画布

现在做的这个项目需要一个折线图的功能,当时想着使用第三方库来实现,结果总不能令我满意,只能通过自定义View用画笔去画了,这才发现 妈的 这东西我不会 赶紧去百度下,后来李大神把他画的折线图给我了,我一看那叫一个顶礼膜拜啊,通过百度和看源码翻译,一个方法一个方法的去看,,总算理出来一丢丢头绪,先记录下吧 在这里边有三个对象非常重要 Paint画笔 Canvas画布 Path路径 不多说了 代码撸起来 1.Paint画笔和Canvas画布 import android.content.Contex

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

友情链接: Canvas API Android自定义View[实战教程]3??--Paint类.Path类以及PathEffect类详解 神马是Canvas 基本概念 Canvas:可以理解为是一个为我们提供了各种工具的画布,我们可以在上面尽情的绘制(旋转,平移,缩放等等).可以理解为系统分配给我们一个一个内存空间,然后提供了一些对这个内存空间操作的方法(API), 实际存储是在下面的bitmap. 两种画布 这里canvas可以绘制两种类型的画图,分别是view和surfaceView. V

【读书笔记《Android游戏编程之从零开始》】12.游戏开发基础(Canvas 画布)

1.Canvas 画布 画布类 Canvas 封装了图形和图片绘制等内容,此类常用的函数说明如下: drawColor(int color) 作用:绘制颜色覆盖画布,常用于刷屏 参数:颜色值,也可用十六进制形式表示(ARGB) drawText(String text,float x,float y,Paint paint) 作用:绘制文本字符 第一个参数:文本内容 第二.三个参数:文本的X.Y坐标 第四个参数:画笔实例 drawPoint(float x,float y,Paint paint

Android自定义组件系列【9】——Canvas绘制折线图

有时候我们在项目中会遇到使用折线图等图形,Android的开源项目中为我们提供了很多插件,但是很多时候我们需要根据具体项目自定义这些图表,这一篇文章我们一起来看看如何在Android中使用Canvas绘制折线图.先看看绘制的效果: 实现原理很简单,我就直接给出代码: package com.example.testcanvasdraw; import java.util.ArrayList; import java.util.List; import java.util.Random; impo

Android 自定义View视图

创建全新的视图将满足我们独特的UI需求. 本文介绍在指南针开发中会用到的罗盘的界面UI,通过继承View类实现的自定义视图,以此来深刻了解自定义视图. 实现效果图: 源代码: 布局文件activity_main(其中CompassView继承View类): <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.

Android 自定义 view(三)&mdash;&mdash; onDraw

前言: 上一篇已经介绍了用自己定义的属性怎么简单定义一个view<Android 自定义view(二) -- attr 使用>,那么接下来我们继续深究自定义view,下一步将要去简单理解自定义view的两个比较重要的方法 onDraw(Canvas canvas) ,在探究 onDraw方法之前,我们必须先深入了解两个类Paint和Canvas .   第一:认识Paint 在探究onDraw之前首先必须要认识两个类,这里给出非常不错的两个资料参考网站,我也是从这里得到想要知道的东西,简单的说

android 自定义View弯曲滑竿指示器

android 自定义弯曲滑竿指示器 效果说明:滑竿指示器,是一段弯曲的圆弧,要求在杆上,有滑动小球事件,小球会根据下标文字的起始角度与终止角度,是否选择滑倒下一个位置.当点击下标文字时,小球也要做出相应的指示. 1)MainActivity package com.example.chenkui.myapplication; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import and

android自定义view-打造圆形ImageView(四)终结篇

前言: 说实话,这段时间忙着修改毕业论文,好长时间没有碰代码了,真是罪过呀.今天我们就来奉上我们打造圆形ImageView的终结篇,以后如果还有新的创意再说啦.本文是在前面三篇的基础上得来的,详细请戳android自定义view-打造圆形ImageView(一).android自定义view-打造圆形ImageView(二).android自定义view-打造圆形ImageView(三). 效果图: 正文: 其实看了上面的效果图,大家应该都一目了然了,就是很多应用经常见到的带有白色边缘的渐变头像

Android自定义组件系列【8】——遮罩文字动画

遮罩文字的动画我们在Flash中非常常见,作为Android的应用开发者你是否也想将这种动画做到你的应用中去呢?这一篇文章我们来看看如何自定义一个ImageView来实现让一张文字图片实现文字的遮罩闪烁效果,下面先来看看效果吧. (录屏幕延时导致效果看起来不是很好) 一.实现原理 实现原理是重写View的onCreate方法,获取图片资源后对每个像素的透明度进行修改来实现,再启动一个线程来循环改变某个区域中的像素透明度. RGBA基础知识:(下面几段介绍文字引用自维基百科) RGBA是代表Red