当前位置: 首页 > 编程笔记 >

Android自定义控件实现不规则区域点击事件

慕学海
2023-03-14
本文向大家介绍Android自定义控件实现不规则区域点击事件,包括了Android自定义控件实现不规则区域点击事件的使用技巧和注意事项,需要的朋友参考一下

本文实例为大家分享了Android实现不规则区域点击事件的具体代码,供大家参考,具体内容如下

先看看效果

对于上面的图形实现主要用到svg,通过解析svg获取不规则的图形,对于svg文件这个一般需要美工提供,不需要我们开发实现。

实现上面效果第一步是解析svg文件代码如下

package demo.zjd.com.taiwandemo.utils; 
 
import android.graphics.RectF; 
import android.util.Xml; 
 
import org.xmlpull.v1.XmlPullParser; 
import org.xmlpull.v1.XmlPullParserException; 
 
import java.io.IOException; 
import java.io.InputStream; 
import java.util.ArrayList; 
import java.util.List; 
 
import demo.zjd.com.taiwandemo.bean.CityPath; 
import demo.zjd.com.taiwandemo.bean.ViewAttr; 
import demo.zjd.com.taiwandemo.calback.ParserCallBack; 
 
/** 
 * Created by zhangjd on 2017/6/1. 
 * 解析svg xml 
 */ 
 
public class SVGXmlParserUtils { 
 
  public static void parserXml(final InputStream in, final ParserCallBack mParserCallBack){ 
    new Thread(new Runnable() { 
      @Override 
      public void run() { 
        List<CityPath> list=new ArrayList<>(); 
        ViewAttr mViewAttr=new ViewAttr(); 
        parserXml(in,list,mViewAttr); 
        if(mParserCallBack!=null){ 
          mParserCallBack.callback(list,mViewAttr); 
        } 
      } 
    }).start(); 
  } 
 
  private static void parserXml(InputStream in, List<CityPath> list, ViewAttr mViewAttr){ 
    XmlPullParser parser = Xml.newPullParser(); 
    RectF mRectF=new RectF(); 
    try { 
      parser.setInput(in, "UTF-8"); 
      int eventType = parser.getEventType(); 
      String name = null; 
      CityPath mCityPath = null; 
      list.clear(); 
      while (eventType != XmlPullParser.END_DOCUMENT) { 
        switch (eventType) { 
          case XmlPullParser.START_DOCUMENT:// 文档开始事件,可以进行数据初始化处理 
            break; 
          case XmlPullParser.START_TAG:// 开始元素事件 
            name = parser.getName(); 
            if ("path".equals(name)) { 
              mCityPath = new CityPath(); 
              mCityPath.setId(parser.getAttributeValue(null, "id")); 
              mCityPath.setTitle(parser.getAttributeValue(null, "title")); 
              mCityPath.setPathData(parser.getAttributeValue(null, "d")); 
            } 
            break; 
          case XmlPullParser.END_TAG:// 结束元素事件 
            name = parser.getName(); 
            if ("path".equals(name)) {//这个地方主要处理屏幕适配问题,后面后详细讲解 
              mCityPath.initPath(); 
              //处理path的边界 
              //计算控制点的边界 
              mCityPath.getmPath().computeBounds(mRectF, true); 
              mViewAttr.colSize(mRectF); 
              list.add(mCityPath); 
            } 
            break; 
        } 
        eventType = parser.next(); 
      } 
    } catch (XmlPullParserException e) { 
      e.printStackTrace(); 
    } catch (IOException e) { 
      e.printStackTrace(); 
    } finally { 
      if(in!=null){ 
        try { 
          in.close(); 
        } catch (IOException e) { 
          e.printStackTrace(); 
        } 
      } 
    } 
 
  } 
} 

解析完svg文件之后就是绘制图像代码如下:

 @Override 
  protected void onDraw(Canvas canvas) { 
    super.onDraw(canvas); 
    if (list == null) { 
      return; 
    } 
    //    Matrix mMatrix = new Matrix(); 
//    mMatrix.postScale(0.5f,0.5f); 
//    mMatrix.setScale(0.5f,0.5f);//这个地方要用concat方法不能用这个方法 
//    canvas.concat(mMatrix); 
    //上面的方法也可以 
//    canvas.restore(); 
    canvas.scale(scale, scale); 
    canvas.drawColor(Color.YELLOW); 
    for (int i = 0; i < list.size(); i++) { 
      CityPath path = list.get(i); 
      //绘制边的颜色 
      mPaint.setStrokeWidth(2); 
      mPaint.setStyle(Paint.Style.STROKE); 
      mPaint.setColor(Color.GRAY); 
      canvas.drawPath(path.getmPath(), mPaint); 
    } 
    if (mPath != null) {//mPath代表的是选中区域的path,如果不为空则一点击选中区域了 
      mPaint.setStrokeWidth(1); 
      mPaint.setStyle(Paint.Style.FILL); 
      mPaint.setColor(Color.GREEN); 
      mPaint.setShadowLayer(8,2,2,Color.BLACK); 
      canvas.drawPath(mPath, mPaint); 
    } 
    mPaint.clearShadowLayer(); 
 
} 

实现上面的方法就可以会出一个地图了,但是没有点击事件,接下来实现点击事件代码如下:

@Override 
public boolean onTouchEvent(MotionEvent event) { 
  if (event.getAction() == MotionEvent.ACTION_DOWN) {//点击的时候出发 
    float x = event.getX(); 
    float y = event.getY(); 
    if (list != null) 
      for (int i = 0; i < list.size(); i++) {//多所有的path进行遍历 
        CityPath cityPath = list.get(i); 
        if (cityPath.isArea(x / scale, y / scale)) {//这个地方要注意了,在查找点是否在path区域中药除以上面的缩放比例 
          mPath = cityPath.getmPath(); 
          postInvalidate(); 
          Toast.makeText(getContext(), cityPath.getTitle(), Toast.LENGTH_SHORT).show(); 
          break; 
        } 
      } 
  } 
  return super.onTouchEvent(event); 
} 

出发事件实现中主要的核心是判断点是否在path区域内实现代码如下:

public boolean isArea(float x,float y){ 
   RectF r=new RectF(); 
   //计算控制点的边界 
   mPath.computeBounds(r, true); 
   //设置区域路径和剪辑描述的区域 
   re.setPath(mPath, new Region((int)r.left,(int)r.top,(int)r.right,(int)r.bottom)); 
   return re.contains((int)x, (int)y); 
} 

上面的代码就可以实现不规则区域的点击了,接下来主要文件就是如何保证通过解析的svg文件可以再不同手机上的显示适配,我这里实现的方法是将每个path的最小外嵌矩形的大小都统计出来,然后进行整合获取所有path所在区域的最小值,然后和控件的大小进行比较算出缩放比代码如下:

//处理path的边界 
//计算控制点的边界 
  mCityPath.getmPath().computeBounds(mRectF, true); 
   mViewAttr.colSize(mRectF); 
  public void colSize(RectF mRectF) {     
  left = left == null ? mRectF.left : Math.min(mRectF.left, left); 
    top = top == null ? mRectF.top : Math.min(mRectF.top, top); 
    right = right == null ? mRectF.right : Math.max(mRectF.right, right); 
    bottom = bottom == null ? mRectF.bottom : Math.max(mRectF.bottom, bottom); 
} 

适配完成之后就大功告成,下面是代码的地址,如有改进的地方欢迎提出

下载:代码地址

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持小牛知识库。

 类似资料:
  • 本文向大家介绍Android 自定义Button控件实现按钮点击变色,包括了Android 自定义Button控件实现按钮点击变色的使用技巧和注意事项,需要的朋友参考一下 效果图如下所示: 一、shape 样式:(在drawable新建--》new--》Drawable resource file 在父级标签selector添加Item ) 二、style 样式: 三、Button控件调用styl

  • 本文向大家介绍Android 自定义View实现单击和双击事件的方法,包括了Android 自定义View实现单击和双击事件的方法的使用技巧和注意事项,需要的朋友参考一下 自定义View, 1. 自定义一个Runnable线程TouchEventCountThread ,  用来统计500ms内的点击次数 2. 在MyView中的 onTouchEvent 中调用 上面的线程 3. 自定义一个Ha

  • 本文向大家介绍Android自定义控件实现折线图,包括了Android自定义控件实现折线图的使用技巧和注意事项,需要的朋友参考一下 本文实例实现一个如下图所示的Android折线图,供大家参考,具体内容如下 首先是控件绘图区域的划分,控件左边取一小部分(控件总宽度的八分之一)绘制表头,右边剩余的部分绘制表格 确定表格的行列数,首先绘制一个三行八列的网格,设置好行列的坐标后开始绘制 网格绘制完成后,

  • 本文向大家介绍Android自定义控件实现饼状图,包括了Android自定义控件实现饼状图的使用技巧和注意事项,需要的朋友参考一下 本文实现一个如图所示的控件,包括两部分,左边的饼状图和中间的两个小方块,及右边的两行文字 实现起来比较简单,只是一些绘图API的调用 核心代码在onDraw函数里边,对静态控件进行绘制即可 Canvas 绘制文本时,使用FontMetrics对象,计算位置的坐标。参考

  • 本文向大家介绍Android点击事件的实现方式,包括了Android点击事件的实现方式的使用技巧和注意事项,需要的朋友参考一下 在之前博文中多次使用了点击事件的处理实现,有朋友就问了,发现了很多按钮的点击实现,但有很多博文中使用的实现方式有都不一样,到底是怎么回事。今天我们就汇总一下点击事件的实现方式。 点击事件的实现大致分为以下三种: (1)Activity 实现接口方式实现点击事件(经常使用)

  • 本文向大家介绍bootstrap-treeview自定义双击事件实现方法,包括了bootstrap-treeview自定义双击事件实现方法的使用技巧和注意事项,需要的朋友参考一下 bootstrap-treeview是一款效果非常酷的基于bootstrap的jQuery多级列表树插件。该jQuery插件基于Twitter Bootstrap,以简单和优雅的方式来显示一些继承树结构,如视图树、列表树