1. View basic touch, gesture, sliding events
View is an abstraction of the space of all interface layers.
The origin of the Android screen coordinate system is in the upper left corner, and the left, right, top, and bottom properties of the View are relative to the coordinates of its parent View.
1. MotionEvent and TouchSlop
MotionEvent
After the finger touches the screen, the typical event type:
ACTION_DOWN
: The finger just touches the screen;ACTION_MOVE
: Move your finger on the screen;Aciton_UP
: The moment the finger is released on the screen
Generally speaking, the normal behavior of touching the screen will trigger a series of events, such as
- Release immediately after clicking on the screen, event sequence: DOWN -> UP
- Click on the screen, slide for a while and release, event sequence: DOWN -> MOVE -> …. -> MOVE -> UP
MotionEvent provides two sets of methods for obtaining coordinates relative to the current View and coordinates relative to the screen origin:
getX()
/getY()
: Get the x and y coordinates relative to the upper left corner of the current View.getRawX()
/getRawY
: Get the x and y coordinates relative to the screen origin.
TouchSlop
TouchSlop is the minimum distance that the system can recognize as sliding, which is obtained by the following code:
ViewConfiguration.get(getApplicationContext()).getScaledTouchSlop();
When processing swipes, you can use this to filter out swipes that are too small to improve user experience.
2. VelocityTracker、GestureDetector 和 Scroller
VelocityTracker
Speed tracker, which can track the speed of the current event:@Override public boolean onTouch(View v, MotionEvent event) { if (velocityTracker1 == null) { velocityTracker1 = VelocityTracker.obtain(); } velocityTracker1.addMovement(event); //参数单位:毫秒 velocityTracker1.computeCurrentVelocity(1000); int xVelocity = (int) velocityTracker1.getXVelocity(); int yVelocity = (int) velocityTracker1.getYVelocity(); Log.d(TAG, "velocity:" + xVelocity + ", " + yVelocity); return true; }
When appropriate, it needs to be recycled:
protected void onDestroy() { velocityTracker.clear(); velocityTracker.recycle(); super.onDestroy(); }
GestureDetector
Create an
GestureDetector
object and implement an interface.GestureDetector gestureDetector = new GestureDetector(new GestureDetector.OnGestureListener() { @Override public boolean onDown(MotionEvent e) { Log.d(TAG, "由ACTION_DOWN 触发 "+e.getAction()); return false; } @Override public void onShowPress(MotionEvent e) { Log.d(TAG, "由ACTION_DOWN 触发, 触摸屏幕后,尚未松开或者拖动 "+ e.getAction()); } @Override public boolean onSingleTapUp(MotionEvent e) { Log.d(TAG, "触摸屏幕后松开,单击行为 "+ e.getAction()); return false; } @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { Log.d(TAG, "触摸屏幕并拖动 "+ e1.getAction()+" , "+e2.getAction()); return false; } @Override public void onLongPress(MotionEvent e) { Log.d(TAG, "长按行为 "+ e.getAction()); } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { Log.d(TAG, "快速滑动行为 "+e1.getAction()+" , "+e2.getAction()); return false; } });
Then take over
onTouchListener
the return:View.OnTouchListener touchListener = new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { // ... gestureDetector.setIsLongpressEnabled(false); // return true; return gestureDetector.onTouchEvent(event); } };
This allows monitoring of gesture behavior.
Double click callback interface:
OnDoubleTapListener
:GestureDetector.OnDoubleTapListener doubleTapListener = new GestureDetector.OnDoubleTapListener() { @Override public boolean onSingleTapConfirmed(MotionEvent e) { //严格单击行为。不可能是双击中的一次单击。 return false; } @Override public boolean onDoubleTap(MotionEvent e) { //双击,由2次连续的单击组成。它不可能和onSingleTapConfirmed共存。 return false; } @Override public boolean onDoubleTapEvent(MotionEvent e) { //表示发生了双击行为。 // 在双击的期间,ACTION_DOWN, ACTION_MOVE 和 ACTION_UP 都会触发此回调 return false; } };
You can
GestureDetector
inject objects withOnDoubleTapListener
:gestureDetector.setOnDoubleTapListener(doubleTapListener);
Scroller
- Elastic sliding object, so that the sliding of View has a transition effect. If we use
scrollTo
/ of ViewscrollBy
, the sliding process is completed in an instant, and the user experience is poor. Instructions:
In a custom View or ViewGroup class:
Scroller scroller ; public void smoothScrollBy(int dx, int dy) { Log.d(TAG, "startX: " + scroller.getFinalX() + " ,startY: " + scroller.getFinalY()); scroller.startScroll(scroller.getFinalX(), scroller.getFinalY(), dx, dy); invalidate(); } @Override public void computeScroll() { if (scroller.computeScrollOffset()) { scrollTo(scroller.getCurrX(), scroller.getCurrY()); postInvalidate(); } }
When you need to swipe, just call
smoothScrollBy
.scroller.startScroll
Parameter description of the method:/** * Start scrolling by providing a starting point and the distance to travel. * The scroll will use the default value of 250 milliseconds for the * duration. * * @param startX Starting horizontal scroll offset in pixels. Positive * numbers will scroll the content to the left. * @param startY Starting vertical scroll offset in pixels. Positive numbers * will scroll the content up. * @param dx Horizontal distance to travel. Positive numbers will scroll the * content to the left. * @param dy Vertical distance to travel. Positive numbers will scroll the * content up. */ public void startScroll(int startX, int startY, int dx, int dy) { startScroll(startX, startY, dx, dy, DEFAULT_DURATION); }
- When startX > 0, the start coordinate is offset to the left relative to the View
- When startY > 0, the start coordinate is offset upward relative to the View
- When dx > 0, the content of the View moves in the left direction
- When dy > 0, the content movement direction of the View is up
- Elastic sliding object, so that the sliding of View has a transition effect. If we use
3. View sliding
There are three sliding methods:
1. scrollTo
and scrollBy
:
```
/**
* Set the scrolled position of your view. This will cause a call to
* {@link #onScrollChanged(int, int, int, int)} and the view will be
* invalidated.
* @param x the x position to scroll to
* @param y the y position to scroll to
*/
public void scrollTo(int x, int y) {
if (mScrollX != x || mScrollY != y) {
int oldX = mScrollX;
int oldY = mScrollY;
mScrollX = x;
mScrollY = y;
invalidateParentCaches();
onScrollChanged(mScrollX, mScrollY, oldX, oldY);
if (!awakenScrollBars()) {
postInvalidateOnAnimation();
}
}
}
```
Note that the content in the View is moved, and the View's position in the layout does not change.
Parameter description:
- x > 0 : the content in the View moves to the left
- y > 0 : the content in the View moves upwards It is
possible to understand the parameters and the law of movement several times.
use animation
Animations can be defined using XML or set directly in code:
ObjectAnimator.ofFloat(tvTest1,"translationX",0,300).setDuration(1000).start();
On page 132 of the "Android Development Art Exploration" book, the author mentioned that the position of the View after the moving animation has ended, and its position has not changed; although the View has moved to a new position, the View can only be clicked on the area before its movement. will respond to click events.
However, it was found in the test that this problem has been fixed, and the android version is relatively new
API 27: Android 8.1 (Oreo)
.
Change the layout parameters:
Directly change the coordinates and size of the View to achieve the purpose of moving the View or changing its size:
``` private void moveView(View view) { ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) view.getLayoutParams(); params.leftMargin += 100; view.requestLayout(); //或者重新注入布局参数:setLayoutParams // view.setLayoutParams(params); } ```
Scroller
Elastic sliding: The scheme to achieve elastic sliding has been introduced in the previous section . Additionally, animations can be usedValueAnimator
:final int deltaX = -100; final ValueAnimator valueAnimator = ValueAnimator.ofInt(0, 1).setDuration(1000); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float fraction = animation.getAnimatedFraction(); llTest1.scrollTo((int) (deltaX * fraction),0); } }); //....启动动画,放在需要的地方。 valueAnimator.start();
In addition, there is a method: start a thread, and then send messages to the Handler continuously. In the
handleMessage
method, callscrollTo
or on the ViewscrollBy
to achieve the elastic sliding effect of the View. However, this is already a clever trick, excessive force and waste of unnecessary expenses.