21 questions and answers about Android View event mechanism

21 questions and answers about Android View event mechanism

[[178693]]

1.What are the main coordinate parameters of View? What are the key points to pay attention to?

Answer: Left, Right, top, Bottom. Note that these 4 values ​​are actually the relative coordinates of the view and its parent control. They are not the absolute values ​​from the upper left corner of the screen. Please note this.

In addition, X and Y are actually coordinate values ​​relative to the parent control. The default values ​​of TranslationX and TranslationY are both 0, which are the offsets relative to the upper left corner of the parent control.

Conversion relationship:

x=left+tranX,y=top+tranY.

Many people don’t understand why this is the case. In fact, if the View moves, such as translation, you should pay attention that the values ​​​​of top and left will not change.

No matter how you drag the view, the values ​​of x, y, tranX, and tranY will change as you drag and move. Just understand this.

2. When is it better to use onTouchEvent or GestureDetector?

Answer: Use the former when there is only a sliding requirement, and use the latter when there is a double-click or other behavior.

3.What problem does Scroller solve?

Answer: The scrollTo and scrollBy of view have very poor sliding effects, which are completed instantly. However, the scroller can cooperate with the computeScroll of view to complete the gradual sliding effect. The experience is better.

4.What should I pay attention to when using ScrollTo and ScrollBy?

A: The former is absolute sliding, and the latter is relative sliding. What slides is the content of the view rather than the view itself. This is very important. For example, when a textview calls these two methods, what slides is the content of the displayed words.

Generally speaking, we use scrollBy more often. When passing values, just remember a few rules: right-left x is positive, otherwise x is negative; up-down y is negative, otherwise y is positive.

You can take a look at the source code of these two:

  1. public void scrollTo( int x, int y) {
  2.  
  3. if (mScrollX != x || mScrollY != y) {
  4.  
  5. int oldX = mScrollX;
  6.  
  7. int oldY = mScrollY;
  8.  
  9. mScrollX = x;
  10.  
  11. mScrollY = y;
  12.  
  13. invalidateParentCaches();
  14.  
  15. onScrollChanged(mScrollX, mScrollY, oldX, oldY);
  16.  
  17. if (!awakenScrollBars()) {
  18.  
  19. postInvalidateOnAnimation();
  20.  
  21. }
  22.  
  23. }
  24.  
  25. }
  26.  
  27.  
  28. public void scrollBy( int x, int y) {
  29.  
  30. scrollTo(mScrollX + x, mScrollY + y);
  31.  
  32. }

You can see there are two variables mScrollX and mScrollY. The values ​​of these two units are pixels. The former represents the distance between the left edge of the view and the left edge of the view content. The latter represents the distance between the top edge of the view and the top edge of the view content.

5. What are the consequences of using animation to implement view sliding?

A: Actually, view animation is to move the surface UI of the view, that is, the visual effect presented to the user. The animation itself cannot move the actual position of the view. Except for attribute animation. After the animation is finished, the view will eventually return to its original position. Of course, you can set the fillafter property to make the view appearance stay at the changed position after the animation is finished. So this will bring a very serious consequence. For example, your button is on the left side of the screen. Now you use an animation and set the fillafter property to move it to the right side. You will find that clicking the right button does not trigger a click event, but clicking the left button can trigger it. The reason is that the right button is only the appearance of the view, and the real button is still on the left and has not moved. If you must do this, you can put a new button in advance at the position after the right button moves. When the animation is finished, enable the right button and let the left button go.

This can avoid the above problems.

6. How many ways are there to make a view slide? What should you pay attention to? What scenarios are they applicable to?

A: There are three types:

a: scrollto, scrollby. This is the simplest, but you can only slide the content of the view but not the view itself.

b: Animation. Animation can slide the view content, but please note that non-attribute animation will affect the interaction as mentioned in question 5, so you should pay more attention when using it. However, most complex sliding effects are completed by attribute animation, which is a killer level.

c: Change layout parameters. This method is easy to understand. It is nothing more than dynamically modifying view parameters such as margin through Java code. However, it is rarely used. I personally don't use this method very often.

7.What does Scroller do? How does it work?

A: Scroller is used to make the view have a sliding gradient effect. The usage is as follows:

  1. package com.example.administrator.motioneventtest;
  2.  
  3.  
  4. import android.content.Context;
  5.  
  6. import android.util.AttributeSet;
  7.  
  8. import android.widget.Scroller;
  9.  
  10. import android.widget.TextView;
  11.  
  12.  
  13. /**
  14.  
  15. * Created by Administrator on 2016/2/2.
  16.  
  17. */
  18.  
  19. public class CustomTextView extends TextView{
  20.  
  21.  
  22. private Scroller mScroller;
  23.  
  24.  
  25.  
  26. public CustomTextView(Context context) {
  27.  
  28. super(context);
  29.  
  30. mScroller=new Scroller(context);
  31.  
  32. }
  33.  
  34.  
  35. public CustomTextView(Context context, AttributeSet attrs) {
  36.  
  37. super(context, attrs);
  38.  
  39. mScroller=new Scroller(context);
  40.  
  41.  
  42. }
  43.  
  44.  
  45. public CustomTextView(Context context, AttributeSet attrs, int defStyleAttr) {
  46.  
  47. super(context, attrs, defStyleAttr);
  48.  
  49. mScroller=new Scroller(context);
  50.  
  51.  
  52. }
  53.  
  54.  
  55. //Call this method to scroll to the target position
  56.  
  57. public void smoothScrollTo( int fx, int fy) {
  58.  
  59. int dx = fx - mScroller.getFinalX();
  60.  
  61. int dy = fy - mScroller.getFinalY();
  62.  
  63. smoothScrollBy(dx, dy);
  64.  
  65. }
  66.  
  67.  
  68. //Call this method to set the relative offset of the scroll
  69.  
  70. public void smoothScrollBy( int dx, int dy) {
  71.  
  72.  
  73. //Set the scroll offset of mScroller
  74.  
  75. mScroller.startScroll(mScroller.getFinalX(), mScroller.getFinalY(), dx, dy,4000);
  76.  
  77. invalidate(); // You must call invalidate() here to ensure that computeScroll() will be called, otherwise the interface may not be refreshed and the scrolling effect will not be seen
  78.  
  79. }
  80.  
  81.  
  82. //When using scroller, it is most important not to miss this method
  83.  
  84. @Override
  85.  
  86. public void computeScroll() {
  87.  
  88. if (mScroller.computeScrollOffset())
  89.  
  90. {
  91.  
  92. scrollTo(mScroller.getCurrX(),mScroller.getCurrY());
  93.  
  94. //Don't forget to call this method.
  95.  
  96. postInvalidate();
  97.  
  98. }
  99.  
  100. super.computeScroll();
  101.  
  102. }
  103.  
  104. }

In fact, many people should be able to search for the above code. Here we mainly talk about its principle.

  1. //The parameters are easy to understand. The first one is the sliding starting point, the middle sliding distance, and the last one is the gradient time.
  2.  
  3. //And we can see that the startScroll method just sets some parameters and there is no sliding code in it
  4.  
  5. // Going back to the previous demo, we can see that we usually call the invalidate() method immediately after calling this method
  6.  
  7. public void startScroll( int startX, int startY, int dx, int dy, int duration) {
  8.  
  9. mMode = SCROLL_MODE;
  10.  
  11. mFinished = false ;
  12.  
  13. mDuration = duration;
  14.  
  15. mStartTime = AnimationUtils.currentAnimationTimeMillis();
  16.  
  17. mStartX = startX;
  18.  
  19. mStartY = startY;
  20.  
  21. mFinalX = startX + dx;
  22.  
  23. mFinalY = startY + dy;
  24.  
  25. mDeltaX = dx;
  26.  
  27. mDeltaY = dy;
  28.  
  29. mDurationReciprocal = 1.0f / ( float ) mDuration;
  30.  
  31. }
  32.  
  33.  
  34.  
  35. //We all know that invalidate will trigger the view 's draw method
  36.  
  37. //If we follow it, we will find that the following code is called in the draw method:
  38.  
  39. //That is to say, the computeScroll method will be called, and the view itself is this method
  40.  
  41. //It is empty so it will be left to us to implement it
  42.  
  43. int sx = 0;
  44.  
  45. int sy = 0;
  46.  
  47. if (!drawingWithRenderNode) {
  48.  
  49. computeScroll();
  50.  
  51. sx = mScrollX;
  52.  
  53. sy = mScrollY;
  54.  
  55. }
  56.  
  57.  
  58.  
  59. //Then go back to our customtextview and you can see that the computeScroll method we implemented is as follows:
  60.  
  61. //You can see that in this method, we call the scrollTo method to implement sliding, and trigger the redrawing of the view again after the sliding is completed.
  62.  
  63. //Then computeScroll will be triggered again to implement a cycle.
  64.  
  65. public void computeScroll() {
  66.  
  67. if (mScroller.computeScrollOffset())
  68.  
  69. {
  70.  
  71. scrollTo(mScroller.getCurrX(),mScroller.getCurrY());
  72.  
  73. //Don't forget to call this method.
  74.  
  75. postInvalidate();
  76.  
  77. }
  78.  
  79. super.computeScroll();
  80.  
  81. }
  82.  
  83.  
  84.  
  85. //Return true means the sliding has not ended, false means it has ended
  86.  
  87. //In fact, this method is the same as the interpolator in the attribute animation. When you use the startScroll method, you will pass an event value.
  88.  
  89. //This method calculates the value of your scrollx and scrolly each time based on the value of this event
  90.  
  91. public boolean computeScrollOffset() {
  92.  
  93. if (mFinished) {
  94.  
  95. return   false ;
  96.  
  97. }
  98.  
  99.  
  100. int timePassed = ( int )(AnimationUtils.currentAnimationTimeMillis() - mStartTime);
  101.  
  102.      
  103.  
  104. if (timePassed < mDuration) {
  105.  
  106. switch (mMode) {
  107.  
  108. case SCROLL_MODE:
  109.  
  110. final float x = mInterpolator.getInterpolation(timePassed * mDurationReciprocal);
  111.  
  112. mCurrX = mStartX + Math.round(x * mDeltaX);
  113.  
  114. mCurrY = mStartY + Math.round(x * mDeltaY);
  115.  
  116. break;
  117.  
  118. case FLING_MODE:
  119.  
  120. final float t = ( float ) timePassed / mDuration;
  121.  
  122. final int   index = ( int ) (NB_SAMPLES * t);
  123.  
  124. float distanceCoef = 1.f;
  125.  
  126. float velocityCoef = 0.f;
  127.  
  128. if ( index < NB_SAMPLES) {
  129.  
  130. final float t_inf = ( float ) index / NB_SAMPLES;
  131.  
  132. final float t_sup = ( float ) ( index + 1) / NB_SAMPLES;
  133.  
  134. final float d_inf = SPLINE_POSITION[ index ];
  135.  
  136. final float d_sup = SPLINE_POSITION[ index + 1];
  137.  
  138. velocityCoef = (d_sup - d_inf) / (t_sup - t_inf);
  139.  
  140. distanceCoef = d_inf + (t - t_inf) * velocityCoef;
  141.  
  142. }
  143.  
  144.  
  145. mCurrVelocity = velocityCoef * mDistance / mDuration * 1000.0f;
  146.  
  147.                  
  148.  
  149. mCurrX = mStartX + Math.round(distanceCoef * (mFinalX - mStartX));
  150.  
  151. // Pin to mMinX <= mCurrX <= mMaxX
  152.  
  153. mCurrX = Math. min (mCurrX, mMaxX);
  154.  
  155. mCurrX = Math. max (mCurrX, mMinX);
  156.  
  157.                  
  158.  
  159. mCurrY = mStartY + Math.round(distanceCoef * (mFinalY - mStartY));
  160.  
  161. // Pin to mMinY <= mCurrY <= mMaxY
  162.  
  163. mCurrY = Math. min (mCurrY, mMaxY);
  164.  
  165. mCurrY = Math. max (mCurrY, mMinY);
  166.  
  167.  
  168. if (mCurrX == mFinalX && mCurrY == mFinalY) {
  169.  
  170. mFinished = true ;
  171.  
  172. }
  173.  
  174.  
  175. break;
  176.  
  177. }
  178.  
  179. }
  180.  
  181. else {
  182.  
  183. mCurrX = mFinalX;
  184.  
  185. mCurrY = mFinalY;
  186.  
  187. mFinished = true ;
  188.  
  189. }
  190.  
  191. return   true ;
  192.  
  193. }

8.How many methods are there for view sliding gradient effect?

A: Three. The first one is the scroller, which is also the most used one. There is an explanation in question 7. Another one is animation. I will not talk much about animation because it is not in the scope of this article. The last one, which we often use, is to use a handler to update the state of the view at a certain time interval.

The code is very simple. You can experience it yourself.

9. How to express the event delivery mechanism of view using pseudo code?

answer:

  1. /**
  2.  
  3. * For a root viewgroup, if a click event is received, its dispatchTouchEvent method will be called first.
  4.  
  5. * If the onInterceptTouchEvent of this viewgroup returns true , it means that the event is intercepted.
  6.  
  7. * The viewgroup handles it, so the viewgroup's onTouchEvent method will be called.
  8.  
  9. * Returning false means that I do not intercept this event, and then pass this event to its own child element, and then the child element's dispatchTouchEvent
  10.  
  11. * will be called, and this cycle continues until the event is processed.
  12.  
  13. *
  14.  
  15. */
  16.  
  17. public boolean dispatchTouchEvent(MotionEvent ev)
  18.  
  19. {
  20.  
  21. boolean consume = false ;
  22.  
  23. if (onInterceptTouchEvent(ev)) {
  24.  
  25. consume=onTouchEvent(ev);
  26.  
  27. } else  
  28.  
  29. {
  30.  
  31. consume=child.dispatchTouchEvent(ev);
  32.  
  33. }
  34.  
  35. return consume;
  36.  
  37. }

10. What is the priority of view's onTouchEvent, OnClickListerner and OnTouchListener's onTouch method?

A: onTouchListener has the highest priority. If the onTouch method returns false, onTouchEvent will be called. If it returns true, it will not be called. As for onClick, it has the highest priority.

11. What is the order in which click events are delivered?

Answer: Activity-Window-View. Pass from top to bottom. Of course, if the view you are touching returns false onTouchEvent, it means that it does not want to handle it. Then throw it up again. If none of them handle it,

In the end, we let the Activity handle it by itself. For example, the PM sends a task to the leader. The leader does not do it himself but gives it to architect A, and A does not do it either but gives it to programmer B. If B does it, then the task is over.

If b finds that he can't do it, he will ask a to do it. If a can't do it either, he will keep making requests upwards, and in the end it may still be done by pm.

  1. //Activity's dispatchTouchEvent method is initially handed over to window for processing
  2.  
  3. //win's superDispatchTouchEvent returns true , which means this function ends directly. Returning false means
  4.  
  5. //This event is not handled by anyone, and it is finally handled by the activity's onTouchEvent. The getwindow here is actually phonewindow
  6.  
  7. public boolean dispatchTouchEvent(MotionEvent ev) {
  8.  
  9. if (ev.getAction() == MotionEvent.ACTION_DOWN) {
  10.  
  11. onUserInteraction();
  12.  
  13. }
  14.  
  15. if (getWindow().superDispatchTouchEvent(ev)) {
  16.  
  17. return   true ;
  18.  
  19. }
  20.  
  21. return onTouchEvent(ev);
  22.  
  23. }
  24.  
  25.  
  26.  
  27. //Look at this function of phonewindow, which directly passes the event to mDecor
  28.  
  29.  
  30. @Override
  31.  
  32. public boolean superDispatchTouchEvent(MotionEvent event) {
  33.  
  34. return mDecor.superDispatchTouchEvent(event);
  35.  
  36. }
  37.  
  38.  
  39. //devorview is our rootview, which is the framelayout and the layout passed in our setContentView
  40.  
  41. // This is the subview of decorview
  42.  
  43. @Override
  44.  
  45. public final View getDecorView() {
  46.  
  47. if (mDecor == null ) {
  48.  
  49. installDecor();
  50.  
  51. }
  52.  
  53. return mDecor;
  54.  
  55. }

12.How many steps does the event consist of?

Answer: It starts with a down event and ends with an up event, and there may be an indefinite number of move events in between.

13.How does ViewGroup distribute click events?

answer:

  1. The viewgroup determines whether to enter the process of intercepting events in the two cases of actionMasked == MotionEvent.ACTION_DOWN and mFirstTouchTarget != null
  2.  
  3.  
  4. Looking at the code, we can see that if it is an ACTION_DOWN event, then we will definitely enter the process of whether to intercept the event.
  5.  
  6.  
  7. If it is not an ACTION_DOWN event, then we need to see if the condition mFirstTouchTarget != null is true.
  8.  
  9.  
  10. This part is a bit confusing but easy to understand. In fact, for an event sequence, down is the beginning of the event, so it must have entered the process of whether to intercept this event, that is, within the if brackets.
  11.  
  12.  
  13.  
  14. mFirstTouchTarget is actually a singly linked list structure that points to the child element that successfully handles the event.
  15.  
  16.  
  17. That is to say, if a child element successfully handles the event, then this value will not be NULL .
  18.  
  19.  
  20. As long as the viewgroup intercepts the event, mFirstTouchTarget is not NULL , so the brackets will not be executed, which also illustrates a conclusion:
  21.  
  22.  
  23. Once a view decides to intercept an event, the event sequence to which this event belongs can only be executed by it. And the onInterceptTouchEvent method will not be called.
  24.  
  25.  
  26. final boolean intercepted;
  27.  
  28. if (actionMasked == MotionEvent.ACTION_DOWN
  29.  
  30. || mFirstTouchTarget != null ) {
  31.  
  32. final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
  33.  
  34. if (!disallowIntercept) {
  35.  
  36. intercepted = onInterceptTouchEvent(ev);
  37.  
  38. ev.setAction( action ); // restore action   in   case it was changed
  39.  
  40. } else {
  41.  
  42. intercepted = false ;
  43.  
  44. }
  45.  
  46. } else {
  47.  
  48. // There are no touch targets and this action   is   not an initial down
  49.  
  50. // so this view   group continues to intercept touches.
  51.  
  52. intercepted = true ;
  53.  
  54. }

14. What happens if a view does not consume the down event when processing an event?

Answer: If a view's onTouchEvent returns false when a down event occurs, then the event sequence to which the down event belongs will not handle its subsequent move and up operations, and all operations will be handled by its parent view.

15.What happens if the view does not consume the move or up events?

Answer: Then the event sequence to which this event belongs will disappear, and the parent view will not handle it. Ultimately, it will be handled by the activity.

16.Does ViewGroup intercept events by default?

Answer: By default, no events are intercepted and onInterceptTouchEvent returns false.

17. Once an event is passed to a view, will the view's onTouchEvent be called?

Answer: Yes, because the view itself does not have an onInterceptTouchEvent method, so as long as the event comes to the view, it will definitely go through the onTouchEvent method.

By default, they are all consumed and return true. Unless the view is not clickable, which means both clickable and longgclikable are false.

Button's clickable is true but textview is false.

18. Does enable affect the onTouchEvent return value of the view?

A: It has no effect. As long as one of clickable and longClickable is true, onTouchEvent will return true.

19.Can requestDisallowInterceptTouchEvent interfere with the event distribution of the parent element in the child element? If so, can it interfere with all of them?

A: Of course you can, but the down event cannot interfere.

20.Will dispatchTouchEvent be called every time?

A: Yes, onInterceptTouchEvent will not.

21. What is the idea for solving the sliding conflict problem?

A. To solve the sliding conflict, the most important thing is to have a core idea. In an event sequence, which view do you want to respond to your sliding? For example, when sliding from top to bottom, which view handles this event, or from left to right?

After you figure it out with business requirements, the rest is actually easy to do. The core methods are two external interceptions, namely the parent interception, and the other is the internal interception, namely the child view interception method. Learning these two methods basically solves all sliding conflicts.

They are all variants of these two, and the core code ideas are the same.

External interception method: The idea is to rewrite the onInterceptTouchEvent of the parent container. Child elements generally do not need to be managed. It is easy to understand because this is exactly the same as the logic of Android's own event processing mechanism.

  1. @Override
  2.  
  3. public boolean onInterceptTouchEvent(MotionEvent ev) {
  4.  
  5.  
  6. boolean intercepted = false ;
  7.  
  8. int x = ( int ) ev.getX();
  9.  
  10. int y = ( int ) ev.getY();
  11.  
  12.  
  13. switch (ev.getAction()) {
  14.  
  15. //The down event must not be intercepted. If it is intercepted, the subsequent events will not be received.
  16.  
  17. case MotionEvent.ACTION_DOWN:
  18.  
  19. intercepted = false ;
  20.  
  21. break;
  22.  
  23. case MotionEvent.ACTION_MOVE:
  24.  
  25. if (your business needs) {
  26.  
  27. //If you are sure to intercept, go to your own onTouchEvent to handle the operations and effects after the interception.
  28.  
  29. intercepted = true ;
  30.  
  31. } else {
  32.  
  33. intercepted = false ;
  34.  
  35. }
  36.  
  37. break;
  38.  
  39. case MotionEvent.ACTION_UP:
  40.  
  41. //Up event, we usually return false . Generally, the parent container will not intercept it. Because up is the last step of the event. It doesn't make sense to return true here.
  42.  
  43. //The only meaning is that the parent element up is intercepted. As a result, the child element cannot receive the up event, so the child element will definitely not have an onClick event triggered.
  44.  
  45. //Small details to understand
  46.  
  47. intercepted = false ;
  48.  
  49. break;
  50.  
  51. default :
  52.  
  53. break;
  54.  
  55. }
  56.  
  57. return intercepted;
  58.  
  59. }

Internal interception method: The internal interception method is a little more complicated. When an event arrives, the parent container does not care and lets the child element decide whether to handle it. If it is consumed, it will be killed. If it is not consumed, it will be transferred to the parent container for processing.

Sub-element code:

  1. @Override
  2.  
  3. public boolean dispatchTouchEvent(MotionEvent event) {
  4.  
  5. int x = ( int ) event.getX();
  6.  
  7. int y = ( int ) event.getY();
  8.  
  9. switch (event.getAction()) {
  10.  
  11. case MotionEvent.ACTION_DOWN:
  12.  
  13. getParent().requestDisallowInterceptTouchEvent( true );
  14.  
  15. break;
  16.  
  17. case MotionEvent.ACTION_MOVE:
  18.  
  19. if (if the parent container needs this click event) {
  20.  
  21. getParent().requestDisallowInterceptTouchEvent( false );
  22.  
  23. }//Otherwise, it will be automatically handled by the onTouchEvent of your own view
  24.  
  25. break;
  26.  
  27. case MotionEvent.ACTION_UP:
  28.  
  29. break;
  30.  
  31. default :
  32.  
  33. break;
  34.  
  35. }
  36.  
  37. return super.dispatchTouchEvent(event);
  38.  
  39. }

The father container code also needs to be modified, in fact, to ensure that the father does not intercept down:

  1. @Override
  2.  
  3. public boolean onInterceptTouchEvent(MotionEvent ev) {
  4.  
  5.  
  6. if (ev.getAction() == MotionEvent.ACTION_DOWN) {
  7.  
  8. return   false ;
  9.  
  10.  
  11. }
  12.  
  13. return   true ;
  14.  
  15. }

<<:  Uncover the technical features of mini program development through programming mode

>>:  If you want to implement a refresh control yourself, you only need to master this knowledge

Recommend

The ROI dilemma of B-side enterprise marketing!

China's Internet industry has been developing...

Traditional Naval Etiquette (IV) - Gun Salute

Whenever a foreign head of state or government vi...

Many apps ignore Apple's Human Interface Guidelines details

Today we want to share some of the discoveries we...

Automating the building of Android and iOS apps with Jenkins

background As business needs evolve, the complexi...

Android performance optimization: rendering

Google recently released an online course on Andr...

Tesla Model S price increased to RMB 688,900-1,315,200

Recently, the domestic prices of Tesla's enti...

Will carrier subsidy cuts really affect Apple?

With the substantial reduction in terminal subsid...

Why does eating nuts make your saliva taste like water?

Nuts are nutritious and delicious. The reason for...

Has the former overlord of the earth really been served on our dining table?

if The ancestor of chicken is dinosaur We brought...