Custom ViewGroup supports infinite loop page turning (Response callback event) and viewgroup callback

Source: Internet
Author: User

Custom ViewGroup supports infinite loop page turning (Response callback event) and viewgroup callback

If you like my blog, please pay attention to my Weibo, please click here (http://weibo.com/kifile), thank you

Mark the source for reprinting. Thank you again.

######################################## ###############################

Custom ViewGroup supports infinite loop paging Series

Custom ViewGroup supports one of infinite loop pages (rewrite onLayout and dispatchDraw)

Custom ViewGroup supports infinite loop page turning 2 (processing touch events)

Custom ViewGroup supports infinite loop page turning 3 (responding to callback events)

######################################## ###############################


In the previous blog, I mentioned that I used a TouchHandler to handle the touch event of the view, and then notified the view to process the corresponding callback event through the callback INTERFACE IN THE TouchHandler.

Now let's analyze in detail how to handle callback events to achieve sliding and switching of the interface.

First, let's take a look at how the Android View class performs the interface location.

In the View class, two methods are available: scrollBy and scrollTo to control the display area of the current screen. At the same time, there are two internal variables: mScrollX and mScrollY to record the current displacement.

For the scrollBy method, he used the previously recorded mScrollX and mScrollY to calculate the coordinate point to which the data should be displaced, and then called the scrollTo Method for moving. The function of this method is just like its name, is used to offset the entire view.

In addition, Android provides us with a scroroller class to help us smoothly move. The scroroller class mainly uses an interpolation tool to calculate the coordinates of the current interface after a certain period of time, then, the Android system calls the invalidate method to obtain the computeScroll method, and re-obtains the interface location to make the movement appear continuous.

OK. Now we are officially starting to respond to the callback event. Let's first check the starting interface,


By default, we have a total of three identical images, which may be displayed on the screen to achieve continuous sliding.

When we press our fingers and start to move, we also hope that the interface can follow our fingers to move. For example, when our fingers slide to the left, we want to see the interface like this.


Therefore, we want a shift in the display area of the screen to achieve this effect.

In the handleTouchEvent method of TouchHandler, we have handled finger movement events. If the finger movement area exceeds a certain limit, we will get the difference value of each touch event, call the onScrollBy callback method, so we only need to inherit this interface in SerialScreenLayout and implement the method.

The implementation scheme is as follows:

@Override    public void onScrollBy(int dx, int dy) {        scrollBy(dx, 0);    }

Perform interface offset based on the input value of the interface method. Note that we only need to perform the transformation on the x axis, so we can set the offset of the y axis to 0.

In this way, when our fingers slide on the screen, the interface will move with our fingers.

Then, when our fingers are released, we don't really want the interface to stay in the previous position. Instead, we want it to be based on the displacement deviation or sliding speed of our fingers, switch to an independent View interface, as shown below:


So in the TouchHandler class, when the finger stops touching and triggers ACTION_UP, we send an onRelease callback to the View, and then identify the current position and speed in the method, to determine the position of the screen to be redirected, and then move the screen smoothly, the detailed code is as follows:

@Override    public void onRelease(int velocityX, int velocityY, boolean cancel) {        cleanPosition();        int targetPosition = mCurrPosition;        if (mDirty) {            mDirty = false;            if (Math.abs(mLastPosition - getScrollX()) > mGutterSize && Math.abs(velocityX) > mMinimumVelocity) {                if (mTmpDirectionLeft) {                    if (velocityX > 0) {                        targetPosition -= 1;                    } else {                        if (getScrollX() > mCurrPosition * mWidth) {                            targetPosition += 1;                        }                    }                } else {                    if (velocityX > 0) {                        if (getScrollX() > mCurrPosition * mWidth) {                            targetPosition -= 1;                        }                    } else {                        targetPosition += 1;                    }                }            }            scrollToPosition(targetPosition, 0);        } else if (!cancel) {            int startX = mWidth * mCurrPosition;            int deltaX = getScrollX() - startX;            if (deltaX > 0) {                if (velocityX <= 0) {                    if (Math.abs(deltaX) > mGutterSize) {                        targetPosition = mCurrPosition + 1;                    } else if (Math.abs(velocityX) > mMinimumVelocity) {                        targetPosition = mCurrPosition + 1;                    }                }            } else {                if (velocityX >= 0) {                    if (Math.abs(deltaX) > mGutterSize) {                        targetPosition = mCurrPosition - 1;                    } else if (Math.abs(velocityX) > mMinimumVelocity) {                        targetPosition = mCurrPosition - 1;                    }                }            }            scrollToPosition(targetPosition, velocityX);        }else{            scrollToPosition(targetPosition, velocityX);        }    }


In the above Code, mDirty will be discussed in the subsequent sections. Let's take a look at other sections. cancel is only true when the touch event is ACTION_CANCEL, indicating that the entire Sliding Process is canceled, so move to the previous position. Otherwise, you can determine the current speed and offset, and then select the next position for smooth displacement.

The code for smooth displacement is as follows:

private void scrollToPosition(int targetPosition, int velocityX) {        cleanPosition();        targetPosition = formatPosition(targetPosition);        if (mCurrPosition == 0 && targetPosition == getChildCount() - 1) {            targetPosition = -1;        } else if (mCurrPosition == getChildCount() - 1 && targetPosition == 0) {            targetPosition = getChildCount();        }        int startX = getScrollX();        int finalX = targetPosition * mWidth;        final int delta = Math.abs(finalX - startX);        velocityX = Math.abs(velocityX);        int duration = (int) (1.0f * DEFAULT_DURATION * delta / mWidth);        if (velocityX > mMinimumVelocity) {            final int width = mWidth;            final int halfWidth = width / 2;            final float distanceRatio = Math.min(1f, 1.0f * delta / width);            final float distance = halfWidth + halfWidth *                    distanceInfluenceForSnapDuration(distanceRatio);            int velocityDuration = 4 * Math.round(1000 * Math.abs(distance / velocityX));            duration = Math.min(duration, velocityDuration);        }        mScroller.startScroll(startX, 0, finalX - startX, 0, duration);        invalidate();        mCurrPosition = targetPosition;    }

Here, we calculate a moving time based on the sliding speed, start the mscroroller, calculate the sliding position, and then call invalidate for displacement.

In this way, when we release our fingers, the interface will be smoothly moved to the corresponding View.

At that time, a new problem emerged. Suppose our position is as follows:

When we move our fingers to the right, there will still be a blank View on the left rather than the last one. In this case, we actually solve the continuity of the middle part, however, the continuity of the edge still occurs. To solve this problem, we have created a cleanPosition () method to calculate the current position. The Code is as follows:

  private void cleanPosition() {        final int position = mCurrPosition;        final int sx = position * mWidth;        final int cx = getScrollX();        int delta = cx - sx;        if (Math.abs(delta) >= mWidth) {            //scrolled to a new page            if (delta > 0) {                mCurrPosition = cx / mWidth;            } else {                mCurrPosition = cx / mWidth - 1;            }        }        final int tmp = formatPosition(mCurrPosition);        if (tmp != mCurrPosition) {            scrollBy((tmp - mCurrPosition) * mWidth, 0);            mCurrPosition = tmp;        }    }    private int formatPosition(int position) {        if (position < 0) {            do {                position += getChildCount();            } while (position < 0);        } else if (position >= getChildCount()) {            do {                position -= getChildCount();            } while (position >= getChildCount());        }        return position;    }

When our moving range exceeds the actual display range of the View, we will translate the display range back to the normal interface through computation, our final display range is always within the basic three views, which solves the possible edge discontinuous problem.

At that time, in the actual sliding process, when we slide, if the dual fingers slide alternately, We can forcibly slide the view to the edge and there is a discontinuous problem, therefore, cleanPosition is called in the multi-touch callback method to keep the view in the correct position.

In the actual Sliding Process, a certain SLIDE may not end, and our fingers have started the next slide. Therefore, the previous onRelease judgment will cause a logical problem, because we used to determine the next position based on the sliding speed and offset, but the current sliding is not over yet, and the START offset and position are different from the previous one, so in onTouchEvent, implementation is as follows:

 @Override    public void onTouch(MotionEvent event) {        if (!mScroller.isFinished()) {            if (Math.abs(mScroller.getCurrX() - mScroller.getFinalX()) > mGutterSize) {                mDirty = true;                cleanPosition();                mLastPosition = getScrollX();                if (mScroller.getFinalX() > mScroller.getCurrX()) {                    mTmpDirectionLeft = true;                } else {                    mTmpDirectionLeft = false;                }                mScroller.abortAnimation();            }        } else {            mDirty = false;        }    }

Here, we record some relevant properties of the current slide and set the mDirty variable to true, so that we can determine whether it is suddenly interrupted during the sliding process, and then start the event, in onRelease, judge based on the current attributes and select the next position.

Here, the implementation logic of the entire SerialScreenLayout has been introduced, and its main principle is:

In onLayout, each view is ordered to enjoy a fixed space on the screen separately. In dispatchDraw, a group of images are drawn on both sides of the screen to make the display continuous, finally, the touch event is processed so that the entire custom ViewGroup can be moved, and a certain screen position can be moved after the touch is stopped.




Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.