Share the small loop function of the desktop sliding between left and right in one of my implemented source code:
One of the major functions of Launch2 in Android's native code is to support sliding between the left and right, but it seems that it does not support circular sliding. It seems easy to think about at first, that is, when obtaining the screen number
The remainder can be achieved, but in fact there will be a lot of misleading information in the source code, so I will share with you how to analyze the Launch2 source code of Android2.3.3 and implement a circular sliding desktop:
First, we can find the position of the Code :.... The source code of the entire desktop is in/package/app/Launch2/src/com/android/Lanucher2, so we need to find the code of the desktop slide, because
The sliding between the left and right sides of the desktop is implemented by the workspace. We can find the Workspace. java file. Five CellLayout files in the Workspace represent five split screens.
When you drag CellLayout between the left and right sides, the sliding effect can be achieved. Let's take a look at Workspace. java:
First, you can see:
Private int mCurrentScreen;
Private int mNextScreen = INVALID_SCREEN;
With the definitions of these two variables, we may think of the current screen value and the next screen value, because that's what I think (laugh !!!), However, in fact, mNextScreen is not the value of the next screen.
As mentioned above, it is also difficult to look at the source code. Without comments, you can't start at once.
Back to our source code, first we habitually think of OnCreate first, but Workspace. java inherits ViewGroup, not Activity, but we can find the starting point. From the perspective of its constructor
In the function, we can see initWorkspace (), which is obviously the initialization of Workspace. In the next initWorkspace () function, we can see:
MCurrentScreen = mDefaultScreen;
Launcher. setScreen (mCurrentScreen );
That is, the initial screen is 2nd (0 ~ 4), that is, the screen in the middle:
At first, we saw mCurrentScreen and mNextScreen in many places in the file. We only needed to find out how to obtain the screen number. We could just go to the next screen based on whether the sliding conditions were met, however
Some analysis and modification failed. For example: else if (mNextScreen! = INVALID_SCREEN) The result shows that the value of mNextScreen is basically the current screen value. This joke went wrong.
Therefore, we changed our mindset and needed:
First, we learned:
Android intercepts touch events. Interception occurs in onInterceptTouchEvent (), onTouchEvent () of ViewGroup, and onTouchEvent of View.
When a touch event occurs, the system generates a MotionEvent and transmits it along the View Tree. First, obtain the MotionEvent as the root node of the View Tree. The root node is usually a ViewGroup,
ViewGroup will get the MotionEvent in onInterceptTouchEvent () and decide whether to continue to pass down. When true is returned in ViewGroup. onInterceptEvent (), MotionEvent is intercepted,
The View under the View Tree cannot obtain the MotionEvent and is handed over to the onTouchEvent () method of the current ViewGroup. If the onTouchEvent returns false, the MotionEvent will be uploaded along the View Tree.
To the next layer.
The slide function is mainly divided into two steps:
1. intercepttouchevent.
2. Slide in onTouchEvent.
Therefore, we can find the onInterceptTouchEvent function, which is mainly used to determine when MotionEvent is intercepted for slide, so as to avoid the impact of other events (such as click events) of the subview ).
Public boolean onInterceptTouchEvent (MotionEvent ev ){
.......
// The user has been sliding and is sliding his finger. Directly intercept this situation and execute onTouchEvent () to continue the slide operation.
Final int action = ev. getAction ();
If (action = MotionEvent. ACTION_MOVE) & (mTouchState! = TOUCH_STATE_REST )){
Return true;
}
// Obtain the speed tracker and record the speed at each time point. And add the current MotionEvent to record the speed value of the row.
AcquireVelocityTrackerAndAddMovement (ev );
......................
When ACTION_MOVE is received,
Switch (action & MotionEvent. ACTION_MASK ){
Case MotionEvent. ACTION_MOVE :{
....................
The code above is not fully understood yet, but can be seen elsewhere:
/**
* MIsBeingDragged = false, otherwise the shortcut wowould have caught it. Check
* Whether the user has moved far enough from his original down touch.
*/
/**
* When ACTION_MOVE is received here, mTouchState is returned! = TOUCH_STATE_SCROLLING and the value of mIsBeingDragged should be false,
* Otherwise, DragLayer intercepts the MotionEvent to implement drag.
* The system has not yet moved to the sliding state. When mActivePointerId = INVALID_POINTER, that is, no touch events have been received before.
* This occurs when the Workspace is changed to an hour, that is, the Workspace is in the SPRING_LOADED state. In this case, the current event is processed as ACTION_DOWN.
* Otherwise, you can use determineScrollingStart () to slide.
*/
..............
.............................
Case MotionEvent. ACTION_DOWN :{
Final float x = ev. getX ();
Final float y = ev. getY ();
// Remember location of down touch
MLastMotionX = x; // write down the coordinates of the last touch.
MLastMotionY = y;
MAllowLongPress = true; // you can use a long press to listen.
.......................
...................
}
Now, onInterceptTouchEvent is mentioned here. If you are interested, you can analyze it in depth. Next, you can see the functions that execute various work such as calculation of sliding and interface refreshing:
Public boolean onTouchEvent (MotionEvent ev ){
.....
Mainly refer to: case MotionEvent. ACTION_UP:
If (mTouchState = TOUCH_STATE_SCROLLING ){
Final VelocityTracker velocityTracker = mVelocityTracker;
VelocityTracker. computeCurrentVelocity (1000, mMaximumVelocity );
Final int velocityX = (int) velocityTracker. getXVelocity (mActivePointerId );
Final int screenWidth = getWidth ();
Final int whichScreen = (mScrollX + (screenWidth/2)/screenWidth;
Final float scrolledPos = (float) mScrollX/screenWidth;
Log. I ("velocityX", "velocityX =" + velocityX + "whichScreen =" + whichScreen );
If (velocityX> SNAP_VELOCITY & mCurrentScreen> 0) {// when the value of velocityX is greater than SNAP_VELOCITY and the current screen value is greater than 0, it slides left to the next screen.
// Fling hard enough to move left.
// Don't fling into Ss more than one screen at a time.
Final int bound = scrolledPos <whichScreen?
MCurrentScreen-1: mCurrentScreen;
SnapToScreen (Math. min (whichScreen, bound), velocityX, true); // to the next screen on the left
} Else if (velocityX <-SNAP_VELOCITY & mCurrentScreen <getChildCount ()-1) {when the value of velocityX is greater than SNAP_VELOCITY and the current screen value is greater than 0, it slides right to the next screen.
// Fling hard enough to move right
// Don't fling into Ss more than one screen at a time.
Final int bound = scrolledPos> whichScreen?
MCurrentScreen + 1: mCurrentScreen;
SnapToScreen (Math. max (whichScreen, bound), velocityX, true); // The Next screen to the right
} Else {
SnapToScreen (whichScreen, 0, true );
}
}
MTouchState = TOUCH_STATE_REST;
MActivePointerId = INVALID_POINTER;
ReleaseVelocityTracker ();
Break;
Then we need to modify the judgment condition:
/*************************************** ********/
// Modifided by xxnan 2012-12-10
If (velocityX> SNAP_VELOCITY) {// cancel checking whether the screen value is less than 0
// Fling hard enough to move left.
// Don't fling into Ss more than one screen at a time.
Log. I ("numscreen", "numscreen =" + mCurrentScreen );
/* Final int bound = scrolledPos <whichScreen?
(MCurrentScreen + getChildCount ()-1) % getChildCount (): mCurrentScreen ;*/
// Cancel the determination to determine whether it is smaller than whichScreen, that is, the current screen value (if whichScreen = 0, it will not be done), so we need to comment out
Final int bound = (mCurrentScreen + getChildCount ()-1) % getChildCount ();
Log. I ("numscreen", "bound =" + bound );
SnapToScreen (bound, velocityX, true );
} Else if (velocityX <-SNAP_VELOCITY) {// cancel the deletion to determine whether the screen value is greater than getChildCount ()-1
// Fling hard enough to move right
// Don't fling into Ss more than one screen at a time.
/* Final int bound = scrolledPos> whichScreen?
(MCurrentScreen + 1) % getChildCount (): mCurrentScreen ;*/
Final int bound = (mCurrentScreen + 1) % getChildCount ();
SnapToScreen (bound, velocityX, true );
} Else {
SnapToScreen (whichScreen, 0, true );
}
/*************************************** ********/
This is probably the case with modifications. Although some code has been modified earlier, the remainder is obtained when the screen value is smaller than 0, and the remainder is added when getChildCount () is greater than etChildCount ()-1: for example:
Public void scrollLeft (){
ClearVacantCache ();
/* If (mScroller. isFinished ()){
If (mCurrentScreen> 0) snapToScreen (mCurrentScreen-1 );
} Else {
If (mNextScreen> 0) snapToScreen (mNextScreen-1 );
}*/
If (mScroller. isFinished ()){
If (mCurrentScreen> 0) snapToScreen (mCurrentScreen-1 );
Else
SnapToScreen (getChildCount ()-1 );
} Else {
If (mNextScreen> 0) snapToScreen (mNextScreen-1 );
}
}
Public void scrollRight (){
// Modified by xxnan
ClearVacantCache ();
/* If (mScroller. isFinished ()){
If (mCurrentScreen <getChildCount ()-1) snapToScreen (mCurrentScreen + 1 );
} Else {
If (mNextScreen <getChildCount ()-1) snapToScreen (mNextScreen + 1 );
}*/
If (mScroller. isFinished ()){
If (mCurrentScreen <getChildCount ()-1) snapToScreen (mCurrentScreen + 1 );
Else
SnapToScreen (0 );
} Else {
If (mNextScreen <getChildCount ()-1) snapToScreen (mNextScreen + 1 );
}
}
But it does not matter, mainly in the onTouchEvent function of calculation sliding and interface refreshing.