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. mysql 5.7 win7 压缩版安装

    1.下载mysql压缩版并解压: 2.复制my-defualt.ini , 命名为my.ini; 3. 3.1 运行在下图bin目录下运行:mysqld --install   安装mysql服务: ...

  2. PHP的错误报错级别设置原理简析

    原理简析 摘录php.ini文件的默认配置(php5.4): ; Common Values: ; E_ALL (Show all errors, warnings and notices inclu ...

  3. paip.输入法英文词库的处理 python 代码 o4

    paip.输入法英文词库的处理 python 代码 o4 目标是eng>>>中文>>atian 当输入非atian词的时候儿,能打印出 atian pinyin > ...

  4. iOS开发-NSURLSession详解

    Core Foundation中NSURLConnection在2003年伴随着Safari浏览器的发行,诞生的时间比较久远,iOS升级比较快,AFNetWorking在3.0版本删除了所有基于NSU ...

  5. Leetcode 155 Min Stack

    题意:设计一个能输出栈内最小值的栈 该题设计两个栈,一个栈是正常的栈s,而另一个是存最小值的栈sm 在push时要判断sm是否为空,如果为空或者非空但是栈顶元素大于等于插入值的 需要在sm中插入x 同 ...

  6. Liferay7 BPM门户开发之33: Portlet之间通信的3种方式(session、IPC Render Parameter、IPC Event、Cookies)

    文章介绍了5种方式,4种是比较常用的: Portlet session IPC Public Render Parameters IPC Event Cookies 参考地址: https://web ...

  7. python继承

    Python继承 继承实例: 父类和子类的关系: 继承树: 没有父类就继承object类,不要忘记调用super().__init__来初始化父类 代码: class Person(object): ...

  8. vs2012 MSDN帮助文档离线包下载安装方法

    vs2012安装文件 自带的 MSDN帮助文档不全, 需要自己手动添加需要的离线文档包, 具体方法如下 1. 打开 vs2012 2. 按 ctrl + alt + F1 打开帮助文档管理器 3. 在 ...

  9. informix 查看 当前锁表

    select username,sid,waiter,dbsname,tabname,rowidlk,keynum,type from sysmaster:syslocks l, sysmaster: ...

  10. Python中使用自定义类class作为海量数据结构时内存占用巨大的问题

    最近碰到处理一个二十多兆的文件时内存蹭蹭的吃掉四百多兆,吓死宝宝了. 无奈毕竟接触python时间有限,还没有完整的看过python的一些基础知识,我想一个合格的pythoner应该不会碰到这个问题. ...