package com.example.testonclick;
import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends Activity {
private static final String TAG = "MainActivity";
MyButton2 bt2;
TextView tv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bt2 = (MyButton2) findViewById(R.id.bt2);
tv = (TextView) findViewById(R.id.tv);
bt2.setOnClickListener(listener4);
bt2.setOnTouchListener(listener5);
}
MyButton2.OnClickListener listener4 = new MyButton2.OnClickListener(){
@Override
public void onClick(View v) {
Log.i(TAG,"onClick2 ");
switch(v.getId()){
case R.id.bt2:
tv.setText("从Button直接继承而来 -> onClick");
break;
}
}
};
MyButton2.OnTouchListener listener5 = new MyButton2.OnTouchListener(){
@Override
public boolean onTouch(View v, MotionEvent event) {
Log.i(TAG,"onTouch2 " + event.getAction());
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:
//v.setFocusable(true);
break;
case MotionEvent.ACTION_UP:
v.setFocusable(true);
v.requestFocus();
break;
case MotionEvent.ACTION_MOVE:
break;
}
tv.setText("onTouch2");
return false;
}
};
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
Log.i(TAG,"dispatchTouchEvent activity " + ev.getAction());
return super.dispatchTouchEvent(ev);
}
}
package com.example.testonclick;
import java.io.IOException;
import org.xmlpull.v1.XmlPullParserException;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.text.InputFilter;
import android.text.TextPaint;
import android.text.TextUtils;
import android.text.method.DialerKeyListener;
import android.text.method.DigitsKeyListener;
import android.text.method.KeyListener;
import android.text.method.PasswordTransformationMethod;
import android.text.method.TextKeyListener;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.inputmethod.EditorInfo;
import android.widget.Button;
import android.widget.TextView.BufferType;
import android.util.AttributeSet;
public class MyButton2 extends Button {
private static final String TAG = "MainActivity";
public MyButton2(Context context, AttributeSet attrs) {
//this(context, attrs,R.attr.buttonStyleDefault);
super(context, attrs);
}
//如果调用this(context, attrs,R.attr.buttonStyleSmall);自定义的按键类型
//调用上面的构造会调到com.android.internal.R.attr.buttonStyle,即按键的模式
public MyButton2(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
}
@Override
public void setFocusable(boolean focusable) {
Log.i(TAG,"setFocusable " + focusable);
super.setFocusable(focusable);
}
@Override
public void setPressed(boolean pressed) {
Log.i(TAG,"setPressed " + pressed);
super.setPressed(pressed);
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
Log.i(TAG,"dispatchTouchEvent " + event.getAction());
return super.dispatchTouchEvent(event);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.i(TAG,"onTouchEvent " + event.getAction());
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_UP:
break;
case MotionEvent.ACTION_MOVE:
break;
}
return super.onTouchEvent(event);
}
@Override
public boolean performLongClick() {
Log.i(TAG,"performLongClick ");
return super.performLongClick();
}
@Override
public void setOnClickListener(OnClickListener l) {
Log.i(TAG,"setOnClickListener " + l.getClass().getName().toString());
super.setOnClickListener(l);
}
@Override
public void setOnLongClickListener(OnLongClickListener l) {
Log.i(TAG,"setOnLongClickListener " + l.getClass().getName().toString());
super.setOnLongClickListener(l);
}
@Override
public boolean performClick() {
Log.i(TAG,"performClick ");
return super.performClick();
}
@Override
public void setOnTouchListener(OnTouchListener l) {
Log.i(TAG,"setOnTouchListener " + l.getClass().getName().toString());
super.setOnTouchListener(l);
}
@Override
public boolean post(Runnable action) {
Log.i(TAG,"post " + action.getClass().getName().toString());
return super.post(action);
}
/* (non-Javadoc)
* @see android.widget.TextView#onFocusChanged(boolean, int, android.graphics.Rect)
*/
@Override
protected void onFocusChanged(boolean focused, int direction,
Rect previouslyFocusedRect) {
Log.i(TAG,"onFocusChanged " + focused + " direction " + direction);
if(focused){
if(direction>0){
//performClick();
}
}
super.onFocusChanged(focused, direction, previouslyFocusedRect);
}
/* (non-Javadoc)
* @see android.view.View#setFocusableInTouchMode(boolean)
*/
@Override
public void setFocusableInTouchMode(boolean focusableInTouchMode) {
Log.i(TAG,"setFocusableInTouchMode " + focusableInTouchMode);
super.setFocusableInTouchMode(focusableInTouchMode);
}
}
<RelativeLayout 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"
tools:context=".MainActivity" >
<TextView
android:id="@+id/tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:text="@string/hello_world" />
<com.example.testonclick.MyButton2
android:id="@+id/bt2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@+id/tv"
android:layout_centerHorizontal="true"
android:layout_marginBottom="67dp"
android:textColor="@drawable/mid"
android:focusableInTouchMode="true"
android:focusable="false"
android:text="Button2" />
</RelativeLayout>
09-16 11:43:53.055: I/MainActivity(8867): setFocusable false
09-16 11:43:53.055: I/MainActivity(8867): setOnClickListener com.example.testonclick.MainActivity$1
09-16 11:43:53.066: I/MainActivity(8867): setOnTouchListener com.example.testonclick.MainActivity$2
09-16 11:44:04.276: I/MainActivity(8867): dispatchTouchEvent activity 0
09-16 11:44:04.276: I/MainActivity(8867): dispatchTouchEvent 0
09-16 11:44:04.276: I/MainActivity(8867): onTouch2 0
09-16 11:44:04.276: I/MainActivity(8867): onTouchEvent 0
09-16 11:44:04.365: I/MainActivity(8867): dispatchTouchEvent activity 1
09-16 11:44:04.365: I/MainActivity(8867): dispatchTouchEvent 1
09-16 11:44:04.365: I/MainActivity(8867): onTouch2 1
09-16 11:44:04.365: I/MainActivity(8867): setFocusable true
09-16 11:44:04.365: I/MainActivity(8867): onTouchEvent 1
09-16 11:44:04.365: I/MainActivity(8867): post android.view.View$PerformClick
09-16 11:44:04.385: I/MainActivity(8867): performClick
09-16 11:44:04.396: I/MainActivity(8867): onClick2
09-16 11:44:04.518: I/MainActivity(8867): setPressed false
1,myButton2初始化获取焦点,注册按键监听。
2,点击按键时,主activty分发按键
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
Log.i(TAG,"dispatchTouchEvent activity " + ev.getAction());
return super.dispatchTouchEvent(ev);
} -------01
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
Log.i(TAG,"dispatchTouchEvent " + event.getAction());
return super.dispatchTouchEvent(event);
} -------02
从01 到02中间还有很长一段路。
主要看02部分
public boolean dispatchTouchEvent(MotionEvent event) {
if (!onFilterTouchEventForSecurity(event)) {
return false;
}
if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED &&
mOnTouchListener.onTouch(this, event)) { ----03
return true;
}
return onTouchEvent(event);
}
03前面2个判断为真,看第3个判断
mOnTouchListener.onTouch(this, event)) ;mOnTouchListener为先前注册的值。看onTouch怎么调用。
onTouch为主activity实现的部分,返回值为false(不可以为true,否则按键就柱塞,到onTouch就停止)。调用到onTouchEvent
public boolean onTouchEvent(MotionEvent event) {
final int viewFlags = mViewFlags;
if ((viewFlags & ENABLED_MASK) == DISABLED) {
// A disabled view that is clickable still consumes the touch
// events, it just doesn't respond to them.
return (((viewFlags & CLICKABLE) == CLICKABLE ||
(viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE));
}
if (mTouchDelegate != null) {
if (mTouchDelegate.onTouchEvent(event)) {
return true;
}
}
if (((viewFlags & CLICKABLE) == CLICKABLE ||
(viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) {
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
boolean prepressed = (mPrivateFlags & PREPRESSED) != 0;
if ((mPrivateFlags & PRESSED) != 0 || prepressed) {
// take focus if we don't have it already and we should in
// touch mode.
boolean focusTaken = false;
if (isFocusable() && isFocusableInTouchMode() && !isFocused()) {
focusTaken = requestFocus();
}
if (!mHasPerformedLongPress) {
// This is a tap, so remove the longpress check
removeLongPressCallback();
// Only perform take click actions if we were in the pressed state
if (!focusTaken) {
// Use a Runnable and post this rather than calling
// performClick directly. This lets other visual state
// of the view update before click actions start.
if (mPerformClick == null) {
mPerformClick = new PerformClick();
}
if (!post(mPerformClick)) { ----> 直接到这里判断
performClick();
}
}
}
if (mUnsetPressedState == null) {
mUnsetPressedState = new UnsetPressedState();
}
if (prepressed) {
mPrivateFlags |= PRESSED;
refreshDrawableState();
postDelayed(mUnsetPressedState,
ViewConfiguration.getPressedStateDuration());
} else if (!post(mUnsetPressedState)) {
// If the post failed, unpress right now
mUnsetPressedState.run();
}
removeTapCallback();
}
break;
case MotionEvent.ACTION_DOWN:
if (mPendingCheckForTap == null) {
mPendingCheckForTap = new CheckForTap();
}
mPrivateFlags |= PREPRESSED;
mHasPerformedLongPress = false;
postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());
break;
case MotionEvent.ACTION_CANCEL:
mPrivateFlags &= ~PRESSED;
refreshDrawableState();
removeTapCallback();
break;
case MotionEvent.ACTION_MOVE:
final int x = (int) event.getX();
final int y = (int) event.getY();
// Be lenient about moving outside of buttons
int slop = mTouchSlop;
if ((x < 0 - slop) || (x >= getWidth() + slop) ||
(y < 0 - slop) || (y >= getHeight() + slop)) {
// Outside button
removeTapCallback();
if ((mPrivateFlags & PRESSED) != 0) {
// Remove any future long press/tap checks
removeLongPressCallback();
// Need to switch from pressed to not pressed
mPrivateFlags &= ~PRESSED;
refreshDrawableState();
}
}
break;
}
return true;
}
return false;
}
public boolean performClick() {
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
if (mOnClickListener != null) {
playSoundEffect(SoundEffectConstants.CLICK);
mOnClickListener.onClick(this);
return true;
}
return false;
}
1,获取焦点之后为什么可以点击触屏按键?
2,从activity到button的按键分发过程还没有完全理清?
但从按键分析来看:
1,一次按键响应,触发2个touch,先是down再是up(0->1),log中很清楚的说明这个情况。