Original address: https://developer.android.com/training/gestures/viewgroup.html
Handle touch events in ViewGroup with extreme caution, because there are many sub-view in ViewGroup, and these sub-view are different targets for different touch events. Make sure that each view receives the corresponding touch event correctly.
Interception of touch events in ViewGroup
The Onintercepttouchevent () method is called when the touch event reaches the viewgroup surface, which includes the inner child view. If Onintercepttouchevent () returns True, then the Motionevent object is intercepted, which means that the event is not passed to the child view, but is passed to the Ontouchevent () method of ViewGroup itself.
Onintercepttouchevent () gives ViewGroup itself an opportunity to intercept the event before the child view gets any events. If Onintercepttouchevent () returns True, the child view that originally processed the event receives a Action_cancel event. And the remainder of the original event will be transmitted to the ViewGroup Ontouchevent () method for routine processing. Onintercepttouchevent () can also return false so that the event will continue to pass through the view tree until it reaches the target view, and the target view will handle the event in its own Ontouchevent () method.
In the following example code, class Myviewgroup inherits ViewGroup and contains multiple view, which we call a child view here, and Myviewgroup is called the parent container view. If you swipe your finger in the horizontal direction, the child view will not receive touch events. The Myviewgroup will implement touch event processing by scrolling through its internals. In any case, if you press the button in the sub view, or slide in the vertical direction, then ViewGroup will not intercept these events, because the child view is the target view for that event. In these cases, onintercepttouchevent () should return false, and Myviewgroup's Ontouchevent () method will not be called.
Public class myviewgroup extends viewgroup { Private intMtouchslop; ... Viewconfiguration VC = Viewconfiguration.get (View.getcontext ()); Mtouchslop = Vc.getscaledtouchslop (); ...@Override Public Boolean onintercepttouchevent(Motionevent ev) {/ * * This method JUST determines whether we want to intercept the motion. * If We return true, Ontouchevent'll is called and we do the actual * scrolling there. */ Final intAction = motioneventcompat.getactionmasked (EV);//Always handle the case of the the touch gesture being complete. if(action = = Motionevent.action_cancel | | action = = MOTIONEVENT.ACTION_UP) {//Release the scroll.Misscrolling =false;return false;//Don't intercept touch event, let the child handle it}Switch(action) { CaseMotionevent.action_move: {if(misscrolling) {//We ' re currently scrolling, so yes, intercept the //Touch event! return true; }//If The user has dragged she finger horizontally more than //The touch slop, start the scroll // left as a exercise for the reader Final intXdiff = Calculatedistancex (EV);//Touch slop should be calculated using Viewconfiguration //constants. if(Xdiff > Mtouchslop) {//Start scrolling!Misscrolling =true;return true; } Break; } ... }//In general, we don ' t want to intercept touch events. They should be //Handled by the child view. return false; }@Override Public Boolean ontouchevent(Motionevent ev) {//Here we actually handle the touch event (e.g. if the action is Action_move, //scroll this container). //This method is only being called if the touch event is intercepted in //Onintercepttouchevent... }}
Note here that the ViewGroup also provides the Requestdisallowintercepttouchevent () method. When a child view does not want its parent container and ancestor container to intercept the touch event, ViewGroup calls it in the Onintercepttouchevent () method to determine whether to intercept the event.
Using Viewconfiguration constants
In the above code, Viewconfiguration is used to initialize a variable named Mtouchslop. You can use Viewconfiguration to access the common distance, speed and time used by the Android system.
"Mtouchslop" refers to the distance in pixels that the touch event was moved before it was intercepted. Touch slop is often used to prevent accidental scrolling when a user performs a touch operation.
The other two common methods of Viewconfiguration are getscaledminimumflingvelocity () and getscaledmaximumflingvelocity (). The two methods return the minimum and maximum speed values that are used to initialize the scroll, respectively. In units of pixels per second:
Viewconfiguration VC = Viewconfiguration.get (View.getcontext ());Private intMslop = Vc.getscaledtouchslop ();Private intMminflingvelocity = Vc.getscaledminimumflingvelocity ();Private intMmaxflingvelocity = Vc.getscaledmaximumflingvelocity ();.. CaseMotionevent.action_move: {...floatDeltaX = MOTIONEVENT.GETRAWX ()-mdownx;if(Math.Abs (DeltaX) > Mslop) {//A swipe occurred, do something}... CaseMotionevent.action_up: {...}if(mminflingvelocity <= Velocityx && velocityx <= mmaxflingvelocity && velocityy < Veloc Ityx) {//The criteria has been satisfied, do something}}
Extend the touch area of a child view
The touchdelegate provided by Android makes it possible to extend the touch area of the child view. This is especially useful when the child view itself is very small, and its touch area needs to be large. You can also use this method to narrow the touch area of a child view if you need to.
In the following example, ImageButton as our "Delegate View" (which means the view that requires the parent container to extend the touch area). The following is a sample layout file:
<relativelayout xmlns: Android = "http://schemas.android.com/apk/res/android" android:id =" @+id/parent_layout " android:layout_width = "match_parent" android:layout_height = "match_parent" tools:context =". Mainactivity "; <ImageButton android:id= "@+id/button"android:layout_width="Wrap_ Content "android:layout_height=" Wrap_content "android:background=" @null " android:src="@drawable/icon" /> </relativelayout>
The following code does the following things:
- Get the parent container view and post a Runnale object to the UI thread. This ensures that the parent container has finished arranging the child view before calling the Gethitrect () method. Gethitrect () returns the click Matrix (Touch area) of the current view within the parent container coordinates.
- Locate ImageButton, and then call its Gethitrect () method to get the touch border of the view.
- Expands the touch area of the ImageButton.
- Instantiate a touchdelegate, and the touch area matrix to be extended is passed in as a parameter to the ImageView to extend the touch area.
- The touchdelegate is set to the parent container view, so that the extended area we touch is routed to the child view.
Within the scope of the Touchdelegate agent, the parent container view will receive all touch events. If the touch event occurs within the touch area of the child view itself, then the parent container view passes all touch events to the Child View processing:
Public class mainactivity extends Activity { @Override protected void onCreate(Bundle savedinstancestate) {Super. OnCreate (Savedinstancestate); Setcontentview (R.layout.activity_main);//Get The parent viewView Parentview = Findviewbyid (r.id.parent_layout); Parentview.post (NewRunnable () {//Post in the parent's message queue to make sure the parent //lays out it children before call Gethitrect () @Override Public void Run() {//The bounds for the delegate view (an ImageButton //In this example)Rect Delegatearea =NewRect (); ImageButton MyButton = (ImageButton) Findviewbyid (R.id.button); Mybutton.setenabled (true); Mybutton.setonclicklistener (NewView.onclicklistener () {@Override Public void OnClick(View view) {Toast.maketext (mainactivity). This,"Touch occurred within ImageButton touch region.", Toast.length_short). Show (); } });// the hit rectangle for the ImageButtonMybutton.gethitrect (Delegatearea);//Extend the Touch area of the ImageButton beyond its bounds //On the right and bottom.Delegatearea.right + = -; Delegatearea.bottom + = -;//Instantiate a touchdelegate. //"Delegatearea" is the bounds in local coordinates of //The containing view to is mapped to the delegate view. //"MyButton" is the child view that should receive motion //Events.Touchdelegate touchdelegate =NewTouchdelegate (Delegatearea, MyButton);//sets the touchdelegate on the parent view, such that touches //within the touch delegate bounds is routed to the child. if(View.class.isInstance (Mybutton.getparent ())) {(View) mybutton.getparent ()). Settouchdelegate (Touchdelegate); } } }); }}
Android Official Development Document Training series: ViewGroup Event management for gesture processing