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. Entity Framework问题总结

    Entity Framework WITH(NOLOCK) EF本身不支持WITH(NOLOCK), 都指出建议设置事务的级别为允许脏读. IsolationLevel = IsolationLeve ...

  2. ubuntu安装ftp服务器

    ubuntu安装ftp服务器 1: 安装vsftpd ~$ sudo apt-get install vsftpd ubuntu10.10自己装了,这步省略. 2: 配置vsftpd 2.1 修改vs ...

  3. hud2544dijkstra+堆优化

    该算法对于稠密图更加有效: 对于给出具有非负权重的边和源顶点S的图G,算法可在O(mlogn)时间内找出从s点到其他每一个顶点的距离. 如果图是稠密的,即对于某个ε>0,m>=n^(1+ε ...

  4. Help Viewer 2.2 独立运行

    "C:\Program Files (x86)\Microsoft Help Viewer\v2.2\HlpViewer.exe" /catalogName VisualStudi ...

  5. dom4j 读取xml

    package core.util; import java.io.File; import java.util.Iterator; import java.util.List; import org ...

  6. UVa 10387- Billiard

    UVa 10387- Billiard Table of Contents 1 题目 2 思路 3 代码 4 参考 1 题目 ============= Problem A: Billiard In ...

  7. Java性能提示(全)

    http://www.onjava.com/pub/a/onjava/2001/05/30/optimization.htmlComparing the performance of LinkedLi ...

  8. ios app 实现热更新(无需发新版本实现app添加新功能)

    目前能够实现热更新的方法,总结起来有以下三种 1. 使用FaceBook 的开源框架 reactive native,使用js写原生的iOS应用 ios app可以在运行时从服务器拉取最新的js文件到 ...

  9. js 生成笛卡尔积

    其实生成 笛卡尔积的方法原本很简单,for循环就可以了, function discarts() { //笛卡尔积 var twodDscartes = function (a, b) { var r ...

  10. 【转】webstorm 注册码 / phpstorm 注册码

    WebStorm注册码 User Name: EMBRACE License Key: ===== LICENSE BEGIN ===== 24718-12042010 00001h6wzKLpfo3 ...