blow your mind
The BYM series aims to share not only technology but also ideas, not just being a porter of code.
1. Background
The company’s business needs to make a search function imitated baidu, Baidu map’s search results list sliding effect is quite smooth, so I also want one. Then this article/funny
2
A. onTouchEvent and MotionEvent
OnTouchEvent is a familiar event that handles all gestures received by the View, along with dispatchTouchEvent and onInterceptTouchEvent.
@Override
public boolean onTouchEvent(MotionEvent ev) {
return super.onTouchEvent(ev);
}
Copy the code
A MotionEvent is an event object generated when we click on the screen (with mouse, hand, pen, trackball) that contains absolute or relative motion. Common MovtionEvent actions are shown in the following table
Action | note |
---|---|
MotionEvent.ACTION_MASK | Action mask, used for multi-touch |
MotionEvent.ACTION_DOWN | Gestures are produced when the screen is pressed, and can also be used to detect the status of the button |
MotionEvent.ACTION_UP | Generated at the end of the gesture, which contains the final position |
MotionEvent.ACTION_MOVE | The position through which the gesture moves |
MotionEvent.ACTION_CANCEL | Generated when the gesture is interrupted |
MotionEvent.ACTION_OUTSIDE | The action generated by moving outside the View scope only provides the initial position |
MotionEvent.ACTION_POINTER_DOWN | Multi-touch press gesture |
MotionEvent.ACTION_POINTER_UP | Lifting gestures for multi-touch |
MotionEvent.ACTION_HOVER_MOVE | The gesture that changed without triggering down is passed to onGenericMotionEvent() |
MotionEvent.ACTION_SCROLL | Relative vertical or horizontal scroll offset, scroll gesture (action passed to child view), event passed to onGenericMotionEvent() |
MotionEvent.ACTION_HOVER_ENTER | Carriage return, event passed to onGenericMotionEvent() |
MotionEvent.ACTION_HOVER_EXIT | Exit the action and pass the event to onGenericMotionEvent() |
MotionEvent.ACTION_BUTTON_PRESS | The button was clicked, this is not a touch event, so the event is passed onGenericMotionEvent() |
MotionEvent.ACTION_BUTTON_RELEASE | The button is released, this is not a Touch event, so the event is passed onGenericMotionEvent() |
MotionEvent.ACTION_POINTER_INDEX_MASK | The index of the multi-touch point, getPointerId gets the identity and getX gets the actual location |
b. setTranslationY
Set the vertical position of this view relative to its {@link#getTop () top} position. This effectively locates the late layout of the object, as well as where the object’s layout is placed.
I mean, actually set the relative distance of the view on the y axis.
public void setTranslationY(float translationY) {
if(translationY ! = getTranslationY()) {// Check whether the setting is the same as the current position
invalidateViewProperty(true.false);
//RenderNode contains View properties
mRenderNode.setTranslationY(translationY);
invalidateViewProperty(false.true); invalidateParentIfNeededAndWasQuickRejected(); notifySubtreeAccessibilityStateChangedIfNeeded(); }}/** * Fast invalidation of view property changes (alpha, translationXY, etc.). * We don't want to set any flags or handle all cases handled by the default invalidation method > * Instead, we just want to arrange a traversal in the ViewRootImpl with the appropriate dirty Rect. * This method calls the quick-fail methods in the ViewGroup, which iterate through the hierarchy and convert the Dirty Rect as needed. * * This method also handles normal invalid logic if the display list property is not used in this view. * This backup method uses the invalidateParent and forceRedraw flags to handle these situations used in various property setting methods@paramInvalidateParent Force a call to invalidateParentCaches () * if the display list attribute is not used in this view@paramForceRedraw If the display list property is not used in this view, mark the view as drawn to force propagation of invalid */
@UnsupportedAppUsage
void invalidateViewProperty(boolean invalidateParent, boolean forceRedraw) {
if(! isHardwareAccelerated()// Whether hardware acceleration is supported| |! mRenderNode.hasDisplayList()// Whether there is buffered data to draw|| (mPrivateFlags & PFLAG_DRAW_ANIMATION) ! =0) {// Whether the view is drawing
if (invalidateParent) {// Whether to refresh the parent controlinvalidateParentCaches(); Know the parent view cache, do not call the parent control's invalidate method}if (forceRedraw) {
mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation
}
invalidate(false);//invalidate(Boolean invalidateCache)
} else {
damageInParent();// Tell the superview to break the View boundary.}}Copy the code
-
Display List is a Buffer that caches drawing commands. The essence of Display List is a Buffer that records the sequence of drawing commands to be executed.
-
Display List is the basic drawing element of the view. It contains the primitive attributes of the element (position, size, Angle, transparency, etc.) corresponding to the drawXxx() method of the Canvas.
-
View information transfer process: Canvas(Java API) – > OpenGL(C/C++ Lib) – > Driver – > GPU
C. getY () and getRawY ()
- GetRawX () and getRawY() return the position of the touch point relative to the screen,
- GetX () and getY() return the position of the touch point relative to the View.
3. The train of thought
- Detour 1: Try to set layoutparams.margintop to change position, but view refresh won’t work
- Detour 2: Use ValueAnimation to modify translateY but find deraution.
- Blind cat meets dead mouse: directly use the setTranslateY method, change the position of the view, record the point position when down, judge whether the position exceeds the upper limit and lower limit when moving, judge the direction of gesture when up, and automatically setTranslateY to the next position specified.
4. The source code
/ * * *@authoer create by markfrain
* @githubhttps://github.com/furuiCQ * Gao Huai see physical and naive * time: 5/8/21 * description: BaiduRecyclView * /
public class BaiduRecycleView extends RecyclerView {
float lastY;
float translateY;
float lastDiff = 0f;
float minVerticalY = 20;
int topTranslateY = 10, centerTranslateY = 300, bottomTranslateY = 540;
public BaiduRecycleView(@NonNull Context context) {
super(context);
init();
}
public BaiduRecycleView(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public BaiduRecycleView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init(a) {
translateY = DpUtils.dp2px(getContext(), centerTranslateY);
}
@Override
public boolean onTouchEvent(MotionEvent e) {
switch (e.getAction()) {
case MotionEvent.ACTION_DOWN:
lastY = e.getRawY();
return true;
case MotionEvent.ACTION_UP:
float rawY = lastY - e.getRawY();
if (translateY < DpUtils.dp2px(getContext(), centerTranslateY)) {
translateY = DpUtils.dp2px(getContext(), rawY > 0 ? topTranslateY : centerTranslateY);
setTranslationY(translateY);
} else if (translateY < DpUtils.dp2px(getContext(), bottomTranslateY)) {
translateY = DpUtils.dp2px(getContext(), rawY > 0 ? centerTranslateY : bottomTranslateY);
setTranslationY(translateY);
}
return true;
case MotionEvent.ACTION_MOVE:
rawY = lastY - e.getRawY();
float distance = lastDiff == 0f ? lastDiff : rawY - lastDiff;
lastDiff = rawY;
if (rawY > minVerticalY || rawY < -minVerticalY) {
if (translateY - distance < DpUtils.dp2px(getContext(), topTranslateY)) {
translateY = DpUtils.dp2px(getContext(), topTranslateY);
setTranslationY(DpUtils.dp2px(getContext(), topTranslateY));
} else if (translateY - distance > DpUtils.dp2px(getContext(), bottomTranslateY)) {
translateY = DpUtils.dp2px(getContext(), bottomTranslateY);
setTranslationY(DpUtils.dp2px(getContext(), bottomTranslateY));
} else{ translateY -= distance; setTranslationY(translateY); }}return false;
}
return super.onTouchEvent(e); }}Copy the code
5. Effect display
6. AnyWay
If you have a better, cooler, leaner implementation code, you are welcome to implement it in your spare time, and I’m sure you can gain some knowledge of your own. If you are blue, you can change your mind. If you are blue, you can change your mind.
7. References
- The Android source code
- Android rendering — Display List