1. Learn brain maps
2. View Foundation
2.1 what isView
?
Q1: How do you understand View?
View
Is an abstraction of a control at the interface layer, representing a control.- is
android
Visual presentation.- Yes All controls are base classes and can be individual controls
View
It can be a set of controlsViewGroup
.
Q2: The importance of View?
View is a very important concept in Android, although View does not belong to the four components, but its role is as important as the four components, in the development, Activity assumes the visual function, Android provides a lot of basic controls, when we are not satisfied with the function of these basic controls, you can use custom controls, The control of the customization needs to have a deep understanding of the View system.
2.2 View
Position parameter of
In Android system, there are two kinds of coordinate system, namely Android coordinate system and View coordinate system.
2.2.1 Android
Coordinate system
- Take the upper-left corner of the screen as the origin of the coordinates
- To the right of the origin is the positive X-axis
- Down from the origin is the positive Y direction
Note: The coordinates obtained using the getRawX() and getRawY() methods are those of the Android coordinate system
2.2.2 View
Coordinate system
Q1: What determines the position of a View?
Four vertices: top, left, right, and bottom
Note: These coordinates are relative to the parent container, and are relative coordinates
Top = getTop(), Left = getLeft(),Right = getRight(),Bottom=getBottom()
Since android 3.0, x, Y, translationX, translationY parameters have been added.
x
,y
:View
The coordinates of the top left cornertranslationX
,translationY
: The offset of the upper-left corner relative to the parent container
Note: During the translation of View, top and left represent the position information of the original upper left corner, and the values changed are x, Y, translationX, translationY.
Q2: What is the difference between getX() and getY() and getRawX() and getRawY()?
GetX and getY are view coordinates and are distances relative to the control
GetRawX and getRawY are absolute coordinates, which are distances from the entire screen
Q3: How does a View get its width and height?
width
=getRight()
–getLeft()
=getWidth()
height
=getBottom()
–getTop()
=getHeight()
2.2.3 View
The touch of
2.2.3.1 MotionEvent
The sequence of events that occurs when a finger touches a screen.
ACTION_DOWN
— Fingers just touching the screenACTION_MOVE
— Moving your finger across the screenACTION_UP
— The moment your finger is released from the screen
Under normal circumstances, the following two situations occur when you touch the screen
- Tap the screen and release, DOWN -> UP
- Click the screen to slide and then release, DOWN->MOVE->… ->MOVE->UP
2.2.3.2 TouchSlop
TouchSlop is the minimum distance the system can recognize to be considered a slide, and is a constant.
Q1: How do I get this constant?
ViewConfiguration. Get (getContext ()). GetScaledTouchSlop ().
Q2: What does this constant mean?
When dealing with slides, this constant can be used for filtering, and when two slide events slide less than this constant, they are not considered slides.
2.2.3.3 VelocityTracker
Speed tracking, used to track finger speed in the sliding process, including horizontal and vertical speed.
Q: How do I use VelocityTracker?
1. Track the speed of the current click event in the View’s onTouchEvent method
VelocityTracker velocityTracker = VelocityTracker.obtain();
velocityTracker.addMovement(event);
Copy the code
2. Obtain the current speed
velocityTracker.computeCurrentVelocity(1000);
int xVelocity = (int)velocityTracker.getXVelocity();
int yVelocity = (int)velocityTracker.getYVelocity();
Copy the code
Note:
Speed before need to calculation speed, namely getXVelocity () and getYVelocity () method must first before calling velocityTracker.com puteCurrentVelocity (1000);
The speed here refers to the number of pixels the hand slides over a period of time. The velocity can be either positive or negative, because in the Android coordinate system, if you slide your finger against the positive direction of the coordinate, the velocity will be negative, and plus or minus here refers to the direction.
Speed = (finishing position – starting position)/time period
3. Use clear to reset and reclaim memory
When velocityTracker is not needed, clear is used to reclaim it.
velocityTracker.clear();
velocityTracker.recycle();
Copy the code
2.2.3.4 GestureDetector
Gesture detection is used to help detect user behaviors such as clicking, sliding, long pressing, and double clicking.
Q: How to use GestureDetector?
1. Create a GestureDetector object and implement the OnGestureDetector interface
GestureDetector mGestureDetector = new GestureDetector(this,this); / / to solve long. According to the phenomenon of screen can't drag mGestureDetector setIsLongpressEnabled (false);Copy the code
2. Add in the View onTouchEvent method
boolean consume = mGestureDetector.onTouchEvent(event);
return consume;
Copy the code
3. Optionally implement the OnGestureListener and OnDoubleTapListener methods
Suggestion: If only listening for the sliding operation, it is recommended to implement in onTouchEvent; If you want to listen for double-clicking, use a GestureDetector.
2.2.3.5 Scroller
Elastic sliding object, used to realize the elastic sliding of View
Q: How do I use Scroller? Typical code is fixed as follows.
Scroller scroller = new Scroller(mContext); Private void smoothScrollTo(int destX,int destY){int scrollX = getScrollX(); int delta = destX -scrollX; Scroll. startScroll(scrollX,0,delta,0,1000); invalidate; } @Override Public void computeScroll(){ if(mScroller.computeScrollOffset()){ ScrollTo(mScroll.getCurrX(),mScroller.getCurrY()); postInvalidate(); }}Copy the code
3. View sliding
Slide in Android development has an important role, master the method of slide is the basis of the implementation of custom controls.
Basic idea of View sliding:
When the touch event is transmitted to the View, the system writes down the coordinate of the touch point. When the finger moves, the system writes down the coordinate of the touch after moving and calculates the offset, and modifies the coordinate of the View by the offset.
3.1 7 ways to slide View
3.2.1 layout()
The onLayout() method is used to set the position of the view, so you can control the coordinates of the view by modifying the left, top, right, and bottom attributes of the view.
- Use:
Public Boolean onTouchEvent(MotionEvent) {public Boolean onTouchEvent(MotionEvent) {public Boolean onTouchEvent(MotionEvent) {int x = (int) event.getx (); int y = (int) event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: lastX = x; lastY = y; break; ACTION_MOVE: // Calculate the distance moved int offsetX = x-lastx; int offsetY = y - lastY; Layout (getLeft()+offsetX, getTop()+offsetY, getRight()+offsetX, getBottom()+offsetY); / / layout () method to break; } return true; }Copy the code
3.2.2 offsetLeftAndRight()
withoffsetTopAndBottom()
The layout() method is the same as the layout() method, but offsetLeftAndRight() and offsetTopAndBottom() set the left, right, and up deviation values.
Use:
Public Boolean onTouchEvent(MotionEvent) {public Boolean onTouchEvent(MotionEvent) {public Boolean onTouchEvent(MotionEvent) {int x = (int) event.getx (); int y = (int) event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: lastX = x; lastY = y; break; ACTION_MOVE: // Calculate the distance moved int offsetX = x-lastx; int offsetY = y - lastY; // offsetLeftAndRight offsetLeftAndRight(offsetX); // offsetTopAndBottom offsetTopAndBottom(offsetY); break; } return true; }Copy the code
3.2.3 LayoutParams
(Change layout parameters)
LayoutParams saves the layout parameters of a View. You can change the layout parameters of a View by LayoutParams.
- Use:
Public Boolean onTouchEvent(MotionEvent) {public Boolean onTouchEvent(MotionEvent) {public Boolean onTouchEvent(MotionEvent) {int x = (int) event.getx (); int y = (int) event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: lastX = x; lastY = y; break; ACTION_MOVE: // Calculate the distance moved int offsetX = x-lastx; int offsetY = y - lastY; LinearLayout.LayoutParams layoutParams= (LinearLayout.LayoutParams) getLayoutParams(); layoutParams.leftMargin = getLeft() + offsetX; layoutParams.topMargin = getTop() + offsetY; setLayoutParams(layoutParams); break; } return true; }Copy the code
If the parent LinearLayout is according to the code, as shown on the parent controls if RelativeLayout, is to use RelativeLayout. LayoutParams, besides using layout LayoutParams, Can also use ViewGroup. MarginLayoutParams to implement
ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) getLayoutParams(); Copy the code
3.2.4 animation
Idea: by animation allows a View of translation, and translation is a kind of sliding, the main operation is to View the translationX and translationY attributes.
There are two types of animation available on Android: View animation and property animation.
-
View animation uses:
1. Create a new anim folder in the res directory and create translate.
LinearLayout.LayoutParams layoutParams= (LinearLayout.LayoutParams) getLayoutParams();
layoutParams.leftMargin = getLeft() + offsetX;
layoutParams.topMargin = getTop() + offsetY;
setLayoutParams(layoutParams);
Copy the code
2. Reference in Java code:
mCustomView.setAnimation(AnimationUtils.loadAnimation(this, R.anim.translate));
Copy the code
Note: View animations do not change the View’s position parameters.
If we animate a Button as shown above, clicking on the Button will not trigger a click event when the Button is shifted 300 pixels away from its current position, but clicking on the Button’s original position will trigger a click event. That’s the difference between tween animation and property animation
-
Property animation uses:
CustomView moves 300 pixels right along the X-axis in 1000 ms:
ObjectAnimator. OfFloat (mCustomView, "translationX", 0300). SetDuration (1000). The start ();Copy the code
3.2.5 scrollTo
/scrollBy
ScollTo (x,y) means to move to a specific coordinate point, while scollBy(dx,dy) means to move in increments of dx,dy. ScollBy will eventually call scollTo. ScollTo and scollBy move the contents of a View, or all of its child views if used in a ViewGroup.
- Use:
Public Boolean onTouchEvent(MotionEvent) {public Boolean onTouchEvent(MotionEvent) {public Boolean onTouchEvent(MotionEvent) {int x = (int) event.getx (); int y = (int) event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: lastX = x; lastY = y; break; ACTION_MOVE: // Calculate the distance moved int offsetX = x-lastx; int offsetY = y - lastY; ((View)getParent()).scrollBy(-offsetX,-offsetY); break; } return true; }Copy the code
3.2.6 Scroller
When using scollTo/scollBy, this process is done instantaneously. Using Scroller to achieve the excessive effect of sliding, this process is not done instantaneously, but in a certain time interval. Scroller itself cannot realize View sliding. It needs to cooperate with View computeScroll() method to achieve elastic sliding effect.
- Use:
@Override public void computeScroll() { super.computeScroll(); if(mScroller.computeScrollOffset()){ ((View)getParent()).scrollTo(mScroller.getCurrX(),mScroller.getCurrY()); // Repeat computeScroll calls PostInvalidate(); Public void smoothScrollTo(int destX,int destY){int scrollX=getScrollX(); int delta=destX-scrollX; DestX mscroll. startScroll(scrollX,0,delta,0,2000); invalidate(); }Copy the code
Called in the View class
/ / using insensitive to move smoothly mCustomView smoothScrollTo (400, 0).Copy the code
-
Source code analysis
When we construct a Scroller object and call its startScroll method, startScroll holds several parameters passed
/** * @param dx horizontal sliding distance * @param dy vertical sliding distance * @param duration sliding time */ public void startScroll(int startX, int startY, int dx, int dy, int duration) { mMode = SCROLL_MODE; mFinished = false; mDuration = duration; mStartTime = AnimationUtils.currentAnimationTimeMillis(); mStartX = startX; mStartY = startY; mFinalX = startX + dx; mFinalY = startY + dy; mDeltaX = dx; mDeltaY = dy; Mdurationframe = 1.0f/(float) mDuration; }Copy the code
Q1: In the startScroll method, there is no internal sliding, so how does startScroll make a View slide?
A: Use the invalidate method. The invalidate method will cause the View to be redrawn. During the redrawing process, the View’s Draw method will call the computeScroll method. The original computeScroll method is an empty implementation in the View. Slide through the scrollTo method, then redraw a second time using the PostInvalidat method, and so on until the slide process is complete.
The computeScroll method uses the computeScrollOffset() method
public boolean computeScrollOffset() { if (mFinished) { return false; } int timePassed = (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime); if (timePassed < mDuration) { switch (mMode) { case SCROLL_MODE: final float x = mInterpolator.getInterpolation(timePassed * mDurationReciprocal); mCurrX = mStartX + Math.round(x * mDeltaX); mCurrY = mStartY + Math.round(x * mDeltaY); break; .Copy the code
This method computes the current scrollX and scrollY values based on the elapsed time. Return true to indicate that the slide is not over, false to indicate that the slide is over.
3.2.7 Delay Policy
Core idea: achieve a progressive effect by sending a series of delayed messages.
Use: Handle/View postDelayed/ thread sleep.
Note: Timing cannot be precise because system message scheduling also takes time.
4. Event distribution mechanism
Event distribution mechanism is the core point of learning in View system. It is the theoretical basis of solving sliding conflicts. Therefore, it is very important to learn event distribution mechanism well.
This part is mainly my summary of knowledge, after reading or feel fuzzy to the event distribution mechanism of readers, recommend a detailed event distribution article to learn View event distribution, like outsiders on the black car! .
Q1: What is event distribution for click events?
When a click event MotionEvent is generated, the system sends the event to a specific View, which is called event distribution.
4.1 Main Methods
-
DispatchTouchEvent: Dispatches events. The return value is Boolean and is affected by the current onTouchEvent and the dispatchTouchEvent of the subordinate View
-
OnInterceptTouchEvent: Intercepts events. This method is only available in viewgroups, not views (excluding viewgroups). If intercepted, the onTouchEvent of the ViewGroup is executed, and the event is processed in the ViewGroup, not then distributed to the View, and only called once, so subsequent events are handed over to the ViewGroup.
-
OnTouchEvent: Performs event processing.
Pseudocode for the relationship between the three:
public boolean dispatchTouchEvent(MotionEvent event) { boolean consume = false; // The Boolean value indicates whether to consume the event if(onInterceptTouchEvent(event)){consume = onTouchEvent(event); }else {consume = child.dispatchTouchEvent(event); consume = child.dispatchTouchEvent(event); } return consume;} return consume;} return consume; }Copy the code
4.2 Event Distribution Process
Q2: What is the nature of View event distribution?
The essence of View event distribution is recursion. The process of click event top-down distribution is “recursion”, and the process of consume event bottom-up is “return”.
Q3: What are the two processes of “recursion” and “return”?
When a click event is generated, it is passed in the following order: Activity->Window->ViewGroup->… – > View. This process of top-down transmission is the process of “transmission”.
When passed to a particular View, the View’s onTouchEvent returns false, meaning that it does not consume the event, and the event will be passed up. If all elements do not handle the event, the event will eventually be passed to the Activity. This process of bottom-up transmission is the process of “return”.
Note:
In the process of recursion, the ViewGroup can directly step into the process of recursion by setting the onInterceptTouchEvent method to return true at the current level.
In ViewGroup can intercept events issued at the same time, the child can also through the getParent. RequestDisallowInterceptTouchEvent method, issued to intercept to stop at the next higher level.
Figure from the learning View event distribution, like out-of-towners on the black car!
Summary: Also refer to the link above
4.3 Source Code Analysis
The three processes of event distribution:
Activity
Distribution of events- top
View
Distribution of eventsView
Handling of eventsThe source code is not listed here, just a flow chart. Readers who need to see the source code can check out the corresponding section of The Android Development Art Explorer or check it out in the compiler.
Five, sliding conflict
In the process of using the sliding process, suppose a situation, an interface can slide inside and outside, when you slide it, how does the interface determine whether you slide the inner layer or the outer layer? This is where the slippage conflict occurs, so in this section, let’s solve the slippage conflict together.
5.1 Sliding Conflict Scenarios
- Scenario A: External sliding and internal sliding inconsistent sliding conflict, common in common in
ScrollView
andFragment
In theLisetView
The use of. - Scenario B: Sliding conflicts consistent with external sliding and internal sliding may occur in customization
View
withListView
In, the outside can slide up and down, and the inside can also slide up and down. - Scenario C: nesting of scenario AB.
5.2 Handling Rules
-
The processing rule for scenario A: Let the external View intercept the click event when the user swipes left and right, and let the internal View intercept the click event when the user swipes up and down.
Q1: How to determine whether users swipe left or up or down
The horizontal offset is subtracted from the vertical offset, and the offset is greater than 0 to determine which offset is larger. If offsetx-offsety >0, it can be judged to be sliding horizontally, which can be intercepted externally to handle the click event.
-
The processing rules for scenario B: Need to be handled according to the business logic, and specify when the external View intercepts the event and when the internal View intercepts the event.
-
Rule of scenario C: Also find a service breakthrough
5.3 Solutions
External interception
Internal interception method
5.3.1 External interception
Click events are first intercepted by the parent container. If the parent container needs to intercept the event, it is not intercepted.
Method: Override the onInterceptTouchEvent method of the parent container and intercept it internally.
Note: Once the parent container starts intercepting any event, subsequent events are handed over to it for processing.
Public Boolean onInterceptTouchEvent (MotionEvent event){Boolean intercepted = false; int x = (int) event.getX(); int y = (int) event.getY(); Switch (event.getAction()) {case motionEvent.action_down :// False must be returned for ACTION_DOWN events, Once intercepted, subsequent events cannot be passed to the child View intercepted = false; break; ACTION_MOVE:// For ACTION_MOVE events, decide whether to intercept if (parent needs the current event) {intercepted = true; } else { intercepted = flase; } break; ACTION_UP:// False must be returned for ACTION_UP events. If the onClick event of the child View is intercepted, it will not trigger intercepted = false; break; default : break; } mLastXIntercept = x; mLastYIntercept = y; return intercepted; }Copy the code
5.3.2 Internal interception
The parent container does not intercept any events. All events are passed to the child element. If the child element needs the event, it consumes it.
Methods: the need to match the requestDisallowInterceptTouchEvent method. Overwrite dispatchTouchEvent() for child View
public boolean dispatchTouchEvent ( MotionEvent event ) { int x = (int) event.getX(); int y = (int) event.getY(); switch (event.getAction) { case MotionEvent.ACTION_DOWN: parent.requestDisallowInterceptTouchEvent(true); // True prevents the parent from intercepting break; case MotionEvent.ACTION_MOVE: int deltaX = x - mLastX; int deltaY = y - mLastY; If (the parent container need such click events) {parent. RequestDisallowInterceptTouchEvent (false); // for fasle, the parent is allowed to intercept} break; case MotionEvent.ACTION_UP: break; default : break; } mLastX = x; mLastY = y; return super.dispatchTouchEvent(event); }Copy the code
Note: in addition to the child container needs to be done to deal with, the parent container will default to intercept besides ACTION_DOWN of other events, so that when the container calls the parent. RequestDisallowInterceptTouchEvent (false) approach, the parent can continue to intercept the events.
Therefore, the parent View needs to override onInterceptTouchEvent() :
public boolean onInterceptTouchEvent (MotionEvent event) { int action = event.getAction(); if(action == MotionEvent.ACTION_DOWN) { return false; } else { return true; }}Copy the code
Q1: Why can’t the parent container intercept ACTION_DOWN events?
Because the event is not affected by FLAG_DISALLOW_INTERCEPT (set by requestDisallowInterceptTouchEvent method) marked position control, so once the parent container to intercept the events, all events are not passed to the View, The inside intercept method would have failed.
Since the reference:
-
Exploring the Art of Android Development
-
Android Advanced Light
-
Advanced road | wonderful trip to the View
-
Learn View event distribution, like out-of-towners on the black car!