on view
The event distribution mechanism of the view has been very faint, and today it is here to comb
MyView
First inherit the view class and customize a myview. And when initializing the view class can be clicked, here from the view Click event Distribution point of view, so do not consider drawing, measuring the implementation of related methods.
Public class MyView extends View {String TAG ="Activity"; Public MyView(Context context) {Super(context); Init (); } Public MyView(context context, AttributeSet attrs) {Super(context, attrs); Init (); } Public MyView(context context, AttributeSet attrs,intDEFSTYLEATTR) {Super(Context, attrs, defstyleattr); Init (); }Private void Init() {LOG.E (TAG,"The View clickable is"+ isclickable ()); }}
Place the entire myview in the layout file and look at the log logs.
<engineer.test.MyView android:id="@+id/myview" android:layout_width="150dp" android:layout_height="150dp" android:layout_centerInParent="true" android:background="#ff00ff" />
As you can see, the view class is not clickable by default.
Monitor the touch event of a view
This first clarifies the values corresponding to the events in the Motionevent
publicstaticfinalint0; publicstaticfinalint1; publicstaticfinalint2
Set Ontouchlistener for MyView and print the event log
myView = (MyView) findViewById(R.id.myview); myView.setOnTouchListener(new View.OnTouchListener() { @Override publiconTouchevent) { "myview_onTouch---->"+event.getAction()); returnfalse; } });
Click MyView to see the log:
As you can see, only the Action_down event has occurred, and the Action_up event has not occurred, which is why?
Set Onclicklistener for MyView and print the log
myView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Log.e(TAG, "the View clickable is " + myView.isClickable()); Log.e(TAG, "myview_onClick"); } });
Click MyView to see the log:
As you can see, after setting Clicklistener:
- MyView directly from a non-clickable control into a clickable control, Isclickable returns True.
- Both the Action_down and action_up events occurred.
- The touch event occurs before the Click event.
We see that the Ontouch method of Touchlistener has a return value, and the default return is False, we change it to true, and then click MyView to see the log:
As you can see, after clicking MyView multiple times, the click Method does not execute, that is, when the Ontouch event returns True, it is equivalent to shielding the click event from occurring
View Source Analysis
Based on the series of results and questions obtained above, let's take a look at the two methods Dispatchtouchevent and ontouchevent about event distribution in view.
First look at Dispatchtouchevent, because the first thing to do is this method
API comments
/**
* Pass the touch screen motion event to the target view, or this
* View if it is the target.
*
* @param event The motion event to be dispatched.
*
* @return True If the event is handled by the view, false otherwise.
*/
As you can see from the note, this method returns true if the current view is handling this event.
Dispatchtouchevent Source (capture main content)
PublicBooleandispatchtouchevent(motioneventEvent) {Boolean result =false;if(Onfiltertoucheventforsecurity (Event)) {//noinspection simplifiableifstatementListenerinfo li = mlistenerinfo;if(Li! =NULL&& Li.montouchlistener! =NULL&& (Mviewflags & enabled_mask) = = ENABLED && Li.mOnTouchListener.onTouch ( This,Event) {result =true; }if(!result && ontouchevent (Event) {result =true; } }returnResult }
As you can see, the default return value here is Result=false
- First, the Onfiltertoucheventforsecurity method detects whether the Click event actually occurs on the current view, and if so, the view handles the current click event, otherwise it returns false without handling the event.
- Next, when the view's touchlistener is not NULL, and the view is enable, and the Touchlistener Ontouch method returns True, Result=true, The Ontouchevent method in the following if statement does not execute so that the OnClick method is not called, which is consistent with the result of the last Test.
However , under normal circumstances, the Ontouch method returns false , so it is executed into the following ontouchevent method.
Ontouchevent Source code (interception of primary logic)
Public Boolean ontouchevent(Motionevent event) {Final floatx = Event.getx ();Final floaty = event.gety ();Final intViewFlags = Mviewflags;Final intAction = Event.getaction ();//view is not an enable, it consumes the touch event, just returns and does not enter into the PerformClick () method if((ViewFlags & enabled_mask) = = DISABLED) {if(Action = = motionevent.action_up && (mprivateflags & pflag_pressed)! =0) {setpressed (false); }//A disabled view that's clickable still consumes the touch //events, it just doesn ' t respond to them. return((viewflags & clickable) = = Clickable | | (ViewFlags & long_clickable) = = long_clickable) | | (ViewFlags & context_clickable) = = context_clickable); }if(Mtouchdelegate! =NULL) {if(Mtouchdelegate.ontouchevent (event)) {return true; } }if((viewflags & clickable) = = Clickable | | (ViewFlags & long_clickable) = = long_clickable) | | (ViewFlags & context_clickable) = = context_clickable) {Switch(action) { CaseMOTIONEVENT.ACTION_UP:Booleanprepressed = (Mprivateflags & pflag_prepressed)! =0;if((Mprivateflags & pflag_pressed)! =0|| prepressed) {//Take focus if we don't have an it already and we should in //Touch mode. BooleanFocustaken =false;if(Isfocusable () && isfocusableintouchmode () &&!isfocused ()) {Focustaken = Requestfocus (); }//Only perform take click on 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 =NewPerformClick (); }if(!post (Mperformclick)) {PerformClick (); } } } Break; }when//switch is finished, it will eventually return true return true; }//If Click,longclick and contextclickable are false, returns false return false; }
As can be seen, a normal veiw (i.e. enable), and can be clicked, when Action_up, will eventually enter the PerformClick () this method to go
Can look again, the implementation of the Performanceclick method
public boolean performclick () {final
boolean result; final Listenerinfo li = mlistenerinfo; if (Li! = null && li.monclicklistener! = null ) {playsoundeffect (Soundeffectconstants.click); Li.mOnClickListener.onClick (this ); result = true ; } else {result = false ; } sendaccessibilityevent (accessibilityevent.type_view_clicked); return result; }
The OnClick method in Onclicklistener is eventually executed, which is the method that we usually implement.
At the same time, you can also see that you can clickable,longclickable and contextclickable as long as there is a true, then at the end of the switch will also return true, This returns to the Dispatchtouchevent method above, returning result to true, which is the complete consumption (processing) of the touch event .
Here can take a look at the complete source code, the overall structure is once inside the IF statement, switch execution is complete, return true, that is, to ensure that the touch event is fully processed.
Of course, if clickable,longclickable and contextclickable are all three false, they will not go into the IF statement, and return to the False,dispatchtouchevent method directly is false, That is, the touch event is not handled, this is the beginning, we only set ontouchlistener for myview without setting the Onclicklistener when the view class default is not clickable, then when we click on the MyView, Action_down executes, the OnTouch () method returns False, and then Ontouchevent returns false, so that subsequent events do not continue, so there is no action_up.
Well, this finally cleared up the touch event distribution mechanism for view (excluding ViewGroup).
Finally, the following conclusions are drawn:
The order in which each method executes when the view receives a touch event
Ontouch–>ontouchevent–>onclick
Ontouch default returns False, returns True when subsequent events cannot be executed
Dispatchtouchevent returns true to handle the touch event, and the return result is affected by the Ontouchevent method
Ontouchevent returns true to indicate that a touch event has been consumed, otherwise it is not consumed.
The true and false of the view enable property does not fully determine the pass of the touch event, but it also has to consider its listener
Doubts: Here the source code in context_clickable This attribute is not able to understand, online also found no explanation.
Android View event Distribution mechanism grooming