Android不规则点击区域详解

摘要

今天要和大家分享的是Android不规则点击区域,准确说是在视觉上不规则的图像点击响应区域分发。

其实这个问题比较简单,对于很多人来说根本不值得做为一篇博文写出来,但在我的群里确实有童鞋不了解如何实现并且很想知道完整的流程是什么样的,故完成demo作为参考。

以下篇幅记录个人分析流程。

我们的需求。

我们需要实现chrome这样的不同颜色区域点击响应不同的事件。Chrome中分别点击红色、黄色、绿色、蓝色进行不同的事件响应。

经过我们对android组件的了解,组件都是矩形的(即使看上去不是矩形),所以点击区域也是一个矩形。

实现原理。

就原理上讨论的话我认为有两种方式比较简单,一种是利用数学线性规划,另一种是通过像素颜色判断。当然两种都有使用的范围和优缺点,今天就只针对像素颜色判断进行讲解。

我们把chrome的颜色做成4张图(也就是4个图层),每张图都只有一种颜色(准确说是一定范围的颜色),并且每张图的大小都是一样的,颜色的位置相对效果图是一致的,其他用透明像素,这样做是为了方便贴图。然后点击的时候判断点击的颜色是否是透明就可以了,如果是透明那么不处理点击事件,如果不是透明那么需要处理事件。

实践切图。

切图的最终效果如下:(四周的灰色是图的范围,实际并没有颜色是透明的)

程序判断透明。

为了方便管理,所以直接把判断部分写在组件内部,也就是自定义组件。程序比较简单,直接上代码。

package com.vane.ui.widget;

import android.content.Context;

import android.graphics.Bitmap;

import android.graphics.Color;

import android.graphics.drawable.BitmapDrawable;

import android.graphics.drawable.Drawable;

import android.graphics.drawable.StateListDrawable;

import android.util.AttributeSet;

import android.view.MotionEvent;

import android.widget.FrameLayout;

public class MenuViewItem extends FrameLayout {

    private int width = -1;

    private int height = -1;

    private Bitmap bitmap;

    public MenuViewItem(Context context) {

        super( context);

    }

    public MenuViewItem(Context context, AttributeSet attrs, int defStyle) {

        super( context, attrs, defStyle);

    }

    public MenuViewItem(Context context, AttributeSet attrs) {

        super( context, attrs);

    }

    @Override

    public boolean onTouchEvent(MotionEvent event) {

        int action = event.getAction();

        if(action != MotionEvent.ACTION_DOWN) {

            return super.onTouchEvent( event);

        }

        int x = (int)event.getX();

        int y = (int)event.getY();

        if(width == -1 || height == -1) {

            Drawable drawable = ((StateListDrawable)getBackground()).getCurrent();

            bitmap = ((BitmapDrawable)drawable).getBitmap();

            width = getWidth();

            height = getHeight();

        }

        if(null == bitmap || x < 0 || y < 0 || x >= width || y >= height) {

            return false;

        }

        int pixel = bitmap.getPixel( x, y);

        if(Color.TRANSPARENT == pixel) {

            return false;

        }

        return super.onTouchEvent( event);

    }

}

Drawable drawable = ((StateListDrawable)getBackground()).getCurrent(); 因为我用的背景是selector,如果你用的不是selector那么可以把这段代码你实际设置的背景的drawable类型。这里唯一需要说明的是onTouchEvent方法,返回true表示组件需要拦截touch事件,返回false表示不拦截那么事件会继续分发到viewgroup中的其他child去。程序中有段

如何使用。

使用也很简单,直接贴出activity_main.l布局文件。

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"

    xmlns:tools="http://schemas.android.com/tools"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    android:gravity="center"

    android:orientation="vertical" >

    <com.vane.ui.widget.MenuViewItem

        android:id="@+id/menu_1"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_gravity="center"

        android:background="@drawable/chrome_1" />

    <com.vane.ui.widget.MenuViewItem

        android:id="@+id/menu_2"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_gravity="center"

        android:background="@drawable/chrome_2" />

    <com.vane.ui.widget.MenuViewItem

        android:id="@+id/menu_3"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_gravity="center"

        android:background="@drawable/chrome_3" />

    <com.vane.ui.widget.MenuViewItem

        android:id="@+id/menu_4"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_gravity="center"

        android:background="@drawable/chrome_4" />

</FrameLayout>

chrome_1.xml资源如下:布局里面的背景是selector,下面贴出一个的相应资源结构,其他的都是一样的。

<?xml version="1.0" encoding="utf-8"?>

<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:drawable="@drawable/chrome_1_s" android:state_pressed="true"/>

    <item android:drawable="@drawable/chrome_1_n"/>

</selector>

这里面仅仅是按下和非按下状态的不同资源。

完整demo。

扯淡的代码就不说了,demo使用的资源都是上文中讲的,直接贴代码。

package com.vane.demo;

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Toast; public class MainActivity extends Activity implements OnClickListener { private Toast mToast; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate( savedInstanceState);
setContentView( R.layout.activity_main);
findViewById( R.id.menu_1).setOnClickListener( this);
findViewById( R.id.menu_2).setOnClickListener( this);
findViewById( R.id.menu_3).setOnClickListener( this);
findViewById( R.id.menu_4).setOnClickListener( this);
} @Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate( R.menu.main, menu);
return true;
} @Override
public void onClick(View v) {
if(null != mToast) {
mToast.cancel();
}
switch(v.getId()) {
case R.id.menu_1:
mToast = Toast.makeText( this, "red", Toast.LENGTH_SHORT);
break;
case R.id.menu_2:
mToast = Toast.makeText( this, "yellow", Toast.LENGTH_SHORT);
break;
case R.id.menu_3:
mToast = Toast.makeText( this, "green", Toast.LENGTH_SHORT);
break;
case R.id.menu_4:
mToast = Toast.makeText( this, "blue", Toast.LENGTH_SHORT);
break;
}
mToast.show();
}
}

demo的实现效果。


 左图是正常截图,右图是点击在红色区域上的截图。

总结。

不规则点击区域的本质是图像像素判断是否是指定颜色(本例中是透明),然后进行touch事件的分发处理。当然如何你不了解touch分发的话可能就不那么容易理解为什么会这么做。

如果文中有任何疑问或者不妥之处欢迎留言交流。在此也留下QQ群311536202,欢迎交流。

Android不规则点击区域详解的更多相关文章

  1. Android 之窗口小部件详解--App Widget

    Android 之窗口小部件详解--App Widget  版本号 说明 作者 日期  1.0  添加App Widge介绍和示例  Sky Wang 2013/06/27        1 App ...

  2. Android中的windowSoftInputMode属性详解

    这篇文章主要介绍了Android中的windowSoftInputMode属性详解,本文对windowSoftInputMode的9个属性做了详细总结,需要的朋友可以参考下     在前面的一篇文章中 ...

  3. Android 之窗口小部件详解(三)  部分转载

    原文地址:http://blog.csdn.net/iefreer/article/details/4626274. (一) 应用程序窗口小部件App Widgets 应用程序窗口小部件(Widget ...

  4. Android 的事件传递机制,详解

    Android 的事件传递机制,详解 前两天和一个朋友聊天的时候.然后说到事件传递机制.然后让我说的时候,忽然发现说的不是非常清楚,事实上Android 的事件传递机制也是知道一些,可是感觉自己知道的 ...

  5. Drawable实战解析:Android XML shape 标签使用详解(apk瘦身,减少内存好帮手)

    Android XML shape 标签使用详解   一个android开发者肯定懂得使用 xml 定义一个 Drawable,比如定义一个 rect 或者 circle 作为一个 View 的背景. ...

  6. Android Design Support Library使用详解

    Android Design Support Library使用详解 Google在2015的IO大会上,给我们带来了更加详细的Material Design设计规范,同时,也给我们带来了全新的And ...

  7. 《Android群英传》读书笔记 (5) 第十一章 搭建云端服务器 + 第十二章 Android 5.X新特性详解 + 第十三章 Android实例提高

    第十一章 搭建云端服务器 该章主要介绍了移动后端服务的概念以及Bmob的使用,比较简单,所以略过不总结. 第十三章 Android实例提高 该章主要介绍了拼图游戏和2048的小项目实例,主要是代码,所 ...

  8. Android中Canvas绘图基础详解(附源码下载) (转)

    Android中Canvas绘图基础详解(附源码下载) 原文链接  http://blog.csdn.net/iispring/article/details/49770651   AndroidCa ...

  9. Android高效率编码-第三方SDK详解系列(三)——JPush推送牵扯出来的江湖恩怨,XMPP实现推送,自定义客户端推送

    Android高效率编码-第三方SDK详解系列(三)--JPush推送牵扯出来的江湖恩怨,XMPP实现推送,自定义客户端推送 很久没有更新第三方SDK这个系列了,所以更新一下这几天工作中使用到的推送, ...

随机推荐

  1. LRU缓存实现(Java)

    LRU Cache的LinkedHashMap实现 LRU Cache的链表+HashMap实现 LinkedHashMap的FIFO实现 调用示例 LRU是Least Recently Used 的 ...

  2. Web开发者的六个代码调试平台

    代码调试平台是Web开发者进行开发.测试.分享.协作和交流的网络应用,它们支持实时的编辑.预览HTML.CSS和JavaScript的客户端代码.这些代码调试平台最值得称道的地方在于,它们中的大多数都 ...

  3. SQL order by的用法

    首先,order by是用来写在where之后,给多个字段来排序的一个DQL查询语句. 其次,order by写法: 1.  select 字段列表/* from 表名 where 条件 order ...

  4. paip.杀不死进程的原因--僵尸进程的解决.txt

    paip.杀不死进程的原因--僵尸进程的解决.txt 作者Attilax  艾龙,  EMAIL:1466519819@qq.com 来源:attilax的专栏 地址:http://blog.csdn ...

  5. paip.获取文件名从路径uapi java python php总结...

    paip.获取文件名从路径uapi java python php总结... =====uapi basename_noext($fname); =============java  自己写.. St ...

  6. 修改Oracle并行度的方法

    Oracle并行度默认为1,适当修改并行度对提高性能有很大帮助 1.查看并行度 select table_name,degree from user_tables; --并行度按照用户表分别设置 2. ...

  7. CreateJSのeasel.js(一)

    CreateJS是基于HTML5开发的一套模块化的库和工具. 基于这些库,可以非常快捷地开发出基于HTML5的游戏.动画和交互应用. CreateJS为CreateJS库,可以说是一款为HTML5游戏 ...

  8. MySQL Cluster 7.3.3 官方版本下载

    MySQL Cluster 是 MySQL 适合于分布式计算环境的高实用.高冗余版本.它采用了NDB Cluster 存储引擎,允许在1个 Cluster 中运行多个MySQL服务器.在MyQL 5. ...

  9. What is /proc/slabinfo?

    /proc/slabinfo gives information about memory usage on the slab level. Linux kernels uses slab pools ...

  10. iOS:Tools:快速注释Doxygen

    Xcode5有个新特性就是自己定义的函数也会被检测集成到代码提示里面,也就是在Quick Help有提示.如 /** * @brief 设置id * * @param id 要设置的id */ +(v ...