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,歡迎交流。