Now many large factory App home page is the above custom layout (classification, advertising) + TAB + viewpager (RecyclerView)

To achieve this effect, the main problem is to solve:Event distribution, slide conflict, nested slide.Three questions.

The effect before treatment

Problem: 1. Slide above simply delimit not move 2. Slide below RecyclerView slide, but did not follow the move 3. No top absorption

Effect of initial

Problem analysis

In problem 1, the top cannot slide because there is no nested slide, even though the outer layer is wrapped in a ScrollView, it still doesn’t work.

Solution:

RecyclerView point in the source code, found that he not only implemented ScrollingView, but also implemented NestedScrollingChild2

So what is NestedScrollingChild2? Scrolling for NestedScrollView. If you have a child, you need to have a father, so you need to replace the ScrollingView with NestedScrollView.

NestedScrollView this View is both the son and the father

But even if the NestedScrollView effect is the same (some versions can be paddled), I estimate that the lower level of the ViewPager (achieve RecyclerView Fragment) is not high caused by.

Problem 3 top: immediately following the top problem 1 tail, have to set ViewPager height, lazy top practice, TAB + RecyclerView = the height of the entire screen (all the height of the parent control), so it is not top. It’s actually a false top, because I slipped to the top and I couldn’t move. 1. Calculate the sliding distance and the height of the head, and then determine if it is time to stop. If it is time to stop, set the width and height 2. Make a hidden TAB above, when moving the TAB to the head, the hidden TAB will show 3. Rewrite Google’s CoordinatorLayout 4. Etc

(2) The event was consumed by RecyclerView. NestedScrolling did not block the event. (3) The RecyclerView consumed by NestedScrolling.

Problem Solving 1

First solve the simple, the TAB and RecyclerView height set up

Customize NestedScrollView, inherit NestedScrollView, and then wrap TAB and RecyclerView in a layout, take that LinearLayout, and set the height to the height of the parent control

OnFinishInflate: Once the XML layout is loaded, the onFinshInfalte method is called back, in which we can initialize controls and data.

Set height in onMeasure

Effect 1: at this time the above can delimit, also have the top, but still poor sliding RecyclerView will be the event to the father layout first delimit, the father finished the son delimit again

Dispatching events

The event

The so-called event is the event of the finger clicking on the screen. In Android, an event is a MotionEvent object. There are three kinds: single touch, multi-touch and gesture.

Single touch: ACTION_DOWN, ACTION_UP, ACTION_MOVE, ACTION_CANCEL (cancel is cancelled and intercepted by the upper layer), ACTION_DOWN starts with the finger pressed down, ACTION_UP ends with the finger lifted up, There are 0 to N ACTION_MOVE finger movements in the middle

Multi-touch: ACTION_DOWN, ACTION_UP, ACTION_MOVE, ACTION_CANCEL In addition to the four single touch, there are ACTION_POINTER_DOWN and ACTION_POINTER_UP. Click ACTION_DOWN with the first finger to start the event. The second, the third… Press the ACTION_POINTER_DOWN; Finger up, front finger up, all ACTION_POINTER_UP; When the last finger lifts ACTION_UP, the event ends.

Event distribution source code

The Activity layout structure looks like this: juejin.cn/post/697392…

  1. The starting point for event dispatch, which must be the Activity, is called dispatchTouchEvent().

  1. The Activity sends the event to getWindow().SuperDispatchTouchEvent (ev), where the window is PhoneWindow (see juejin.cn/post/697392…).

PhoneWindow in turn distributes events to the superDispatchTouchEvent of its underlying DecorView

  1. The DecorView calls super.DispatchTouchEvent (Event). The DecorView’s parent is GroupView, so it calls dispatchTouchEvent in GroupView

  1. DispatchTouchEvent in GroupView is the key method

GroupView is usually the parent, so its dispatchTouchEvent needs to be handled, whether the event is handled by me or which View it is sent to him

4.1 Determine whether some auxiliary functions are processed, whether they are processed, and determine security. It’s all right to get down there.

If ‘down’ is pressed, clean up the previous events, variables, etc. (touchTarget)

MFirstTouchTarget The first touch target in the list of touch target links. That’s the touch list of the child View, and if it’s empty then it’s in the blank space, and the ViewGroup handles it itself

② Determine the interception situation. Is the “down” or “mFirstTouchTarget” not empty?

③ Whether the subclass has set the father cannot intercept

* onInterceptTouchEvent (); * onInterceptTouchEvent ()

FLAG_DISALLOW_INTERCEPT is a method that allows you to disable the interception of your own events

RequestDisallowInterceptTouchEvent ()

5. If (! canceled && ! intercepted), then go through the son, to find the specific who

⑤ Add if the event is the starting point of traversal

6 to call the child. Through dispatchTransformedTouchEvent dispatchTouchEvent () try to consume the event all landowners if returns true son processing, so recorded mFirstTouchTarget on this list

Supplement:

⑧ So processed, distributed to the son then call the son’s onTouchEvent, if it is handled by their own, then call their own onTouchEvent

Event Distribution Summary



Nested sliding

The lifecycle of nested sliders can be learned by inheriting the NestedScrollView and then logging out all the related methods.

The NestedScrollView lifecycle is divided into three main blocks:

Make sure the son is rolling

2. OnTouchEvent son scrolling

You can still fling some distance (optimize this part) because you still have inertia.

Problem Solving 2

The point is that step 8, the son will call his father’s onNestedPreScroll before he scrolls, so I’m going to scroll onNestedPreScroll and that method passes dx dy to the internal View that moves, and if you need to consume a certain amount of dx dy, you specify it by consumed in the last argument, For example, if I want to consume half of dy, I can write consumed[1]=dy/2

It works now, but it doesn't have inertia, so it can be optimized a little bit

Problem solving 3 – Inertia

Public Boolean fling(int velocityX, int velocityY) Public Boolean fling(int velocityX, int velocityY)

So the question is exactly what is the velocity of inertia

Analysis: I know the initial speed of the finger slide. That is the initial sliding speed –> the distance that should be sliding is calculated by some algorithm. The distance you should slide – the distance you have slid = the distance left to slide by inertia. The remaining inertial sliding distance –> pushes back the velocity through that algorithm.

This inertial sliding distance algorithm Google gave, don’t understand, with the end

To calculate the inertia speed, pass childrecyclerView. fling(0, velY);

Finally also found that the following is very silky, but delimits the head RecyclerView when a little stiff, the reason is that the RecyclerView will slide the event to eat, have to set the head RecyclerView can not slide, so the custom RecyclerView, Then rewrite onTouchEvent and onInterceptTouchEvent

That's it. Is it really that silky? - dove

Event distribution source details (also below this article) juejin.cn/post/697614…