Android event distribution Learning application-image carousel implementation

Source: Internet
Author: User

Android event distribution Learning application-image carousel implementation

In the previous article, I wrote a learning note on the Android event distribution mechanism. Next we will use an instance application to understand the Android event distribution mechanism. Here we will implement the carousel function for an image, and finally implement automatic carousel for the film by the way.

Our image carousel is encapsulated in a ViewGroup. When we perform horizontal slide, we need to prevent the event from being distributed from ViewGroup to the Child control. ViewGroup is used to consume our current slide image. Below we paste our encapsulated ViewGroup code implementation as follows:

 

Public class ImageSwitcher extends ViewGroup {private String TAG = ImageSwitcher. class. getSimpleName (); private static final int SNAP_VELOCITY = 300; private Scroller scroller; private VelocityTracker limit; private int mTouchSlop; private float mMotionX; private int mImageWidth; private int imageCount; private int mIndex; private int mImageHeight; private int [] imageItems; private boolean forceTo Relayout; private int mTouchState = TOUCH_STATE_REST; private static final int TOUCH_STATE_REST = 0; private static final int TOUCH_STATE_SCROLLING = 1; private static final int AUTO_MSG = 0; private static final int START_MSG = 2; private static final int HANDLE_MSG = 1; private static final long PHOTO_CHANGE_TIME = 4000; private Handler mHandler = new Handler () {// automatically process the image or manually scroll through the public void handleMessage (Message msg) {switch (msg. what) {case AUTO_MSG: scrollToNext (); mHandler. sendEmptyMessageDelayed (AUTO_MSG, PHOTO_CHANGE_TIME); break; case START_MSG: mHandler. sendEmptyMessageDelayed (AUTO_MSG, PHOTO_CHANGE_TIME); break; case HANDLE_MSG: mHandler. removeMessages (AUTO_MSG); mHandler. sendEmptyMessageDelayed (AUTO_MSG, PHOTO_CHANGE_TIME); default: break ;}};/*** indicates the action of scrolling to the next image */private static final int SCROLL_NE XT = 0;/*** indicates the action to scroll to the previous image */private static final int SCROLL_PREVIOUS = 1; private static final int SCROLL_BACK = 2; public ImageSwitcher (Context context, attributeSet attrs) {super (context, attrs); scroller = new Scroller (context); mTouchSlop = ViewConfiguration. get (getContext ()). getScaledTouchSlop ();}/*** when the View is added to the Window container, it is executed: onMeasure> onLayout> onDraw> onAttachedToWindow */@ Overr Ideprotected void onAttachedToWindow () {super. onAttachedToWindow (); mHandler. sendEmptyMessage (START_MSG); // send a message to automatically scroll the image} @ Overrideprotected void onLayout (boolean changed, int l, int t, int r, int B) {if (changed | forceToRelayout) {imageCount = getChildCount (); mImageWidth = getMeasuredWidth (); mImageHeight = getMeasuredHeight (); int marginLeft = 0; scroller. abortAnimation (); // you can specify scroller as the scroll state. scrol LTo (0, 0); // reset the initial rolling position int [] items = {getIndexForItem (1), getIndexForItem (2), getIndexForItem (3 ), getIndexForItem (4), getIndexForItem (5)}; imageItems = items; for (int I = 0; I <items. length; I ++) {ImageView childView = (ImageView) getChildAt (items [I]); childView. layout (marginLeft, 0, marginLeft + mImageWidth, mImageHeight); marginLeft = marginLeft + mImageWidth;} refreshImageView (); forceToRelay Out = false ;}} private void refreshImageView () {for (int I = 0; I <imageItems. length; I ++) {ImageView childView = (ImageView) getChildAt (imageItems [I]); childView. invalidate () ;}} private int getIndexForItem (int item) {int index =-1; index = mIndex + item-3; while (index <0) {index = index + imageCount;} while (index> imageCount-1) {index = index-imageCount;} return index ;}@ Overridepublic boolean OnInterceptTouchEvent (MotionEvent ev) {int action = ev. getAction (); if (action = MotionEvent. ACTION_MOVE) & (mTouchState! = TOUCH_STATE_REST) {return true;} float xLoc = ev. getX (); switch (action) {case MotionEvent. ACTION_DOWN: mMotionX = xLoc; mTouchState = TOUCH_STATE_REST; Log. e (TAG, onInterceptTouchEvent ACTION_DOWN); break; case MotionEvent. ACTION_MOVE: Log. e (TAG, onInterceptTouchEvent ACTION_MOVE); int xDif = (int) Math. abs (mMotionX-xLoc); if (xDif> mTouchSlop) {// when we scroll horizontally to the minimum distance, we start to intercept ViewGroup events and distribute mTouchStat to sub-controls. E = TOUCH_STATE_SCROLLING;} break; case MotionEvent. ACTION_UP: Log. e (TAG, onInterceptTouchEvent ACTION_UP); mTouchState = TOUCH_STATE_REST; break; case MotionEvent. ACTION_CANCEL: Log. e (TAG, onInterceptTouchEvent ACTION_CANCEL); mTouchState = TOUCH_STATE_REST; break; default: Log. e (TAG, onInterceptTouchEvent DEFAULT); mTouchState = TOUCH_STATE_REST; break;} return mTouchState! = TOUCH_STATE_REST;} @ Overridepublic boolean onTouchEvent (MotionEvent event) {if (scroller. isFinished () {// scroller is not started or completed. The following code starts executing if (mVelocityTracker = null) {mVelocityTracker = VelocityTracker when the finger slides. obtain ();} mVelocityTracker. addMovement (event); int action = event. getAction (); float x = event. getX (); switch (action) {case MotionEvent. ACTION_DOWN: // the abscissa mMotionX = x when the record is pressed; case MotionEvent. ACTI ON_MOVE: int disX = (int) (mMotionX-x); mMotionX = x; scrollBy (disX, 0); break; case MotionEvent. ACTION_UP: mVelocityTracker. computeCurrentVelocity (1000); int velocityX = (int) mVelocityTracker. getXVelocity (); if (judeScrollToNext (velocityX) {// the next image scrollToNext ();} else if (velocityX) {// the last image scrollToPrevious ();} else {// scrollBack ();} if (mVelocityTracker! = Null) {mVelocityTracker. recycle (); mVelocityTracker = null;} mHandler. sendEmptyMessageDelayed (HANDLE_MSG, PHOTO_CHANGE_TIME); return true ;}return false;} private void scrollBack () {if (scroller. isFinished () {beginScroll (getScrollX (), 0,-getScrollX (), 0, SCROLL_BACK) ;}} private void scrollToPrevious () {if (scroller. isFinished () {setImageSwitchIndex (SCROLL_PREVIOUS); int disX =-mImageWidth-getScrollX (); beginScroll (getScrollX (), 0, disX, 0, SCROLL_PREVIOUS );}} private void scrollToNext () {if (scroller. isFinished () {setImageSwitchIndex (SCROLL_NEXT); int disX = mImageWidth-getScrollX (); beginScroll (getScrollX (), 0, disX, 0, SCROLL_NEXT );}} /*** image start sliding */private void beginScroll (int startX, int startY, int dx, int dy, final int action) {int duration = (int) (700f/mImageWidth * Math. abs (dx); scroller. startScroll (startX, startY, dx, dy, duration); invalidate (); mHandler. postDelayed (new Runnable () {@ Overridepublic void run () {if (action = SCROLL_NEXT | action = SCROLL_PREVIOUS) {forceToRelayout = true; requestLayout ();}}}, duration);} private void setImageSwitchIndex (int action) {if (action = SCROLL_NEXT) {if (mIndex <imageCount) {mIndex ++;} else {mIndex = 0 ;}} else if (action = SCROLL_PREVIOUS) {if (mIndex> 0) {mIndex --;} else {mIndex = imageCount-1 ;}}} /*** slide forward when judging * @ param velocityX * @ return */private boolean judeScrollToPrevious (int velocityX) {return velocityX> SNAP_VELOCITY | getScrollX () <-mImageWidth/2;}/*** slide backwards when judging * @ param velocityX * @ return */private boolean judeScrollToNext (int velocityX) {return velocityX <-SNAP_VELOCITY | getScrollX ()> mImageWidth/2;} @ Overridepublic void computeScroll () {if (scroller. computescroloffset () {scrollTo (scroller. getCurrX (), scroller. getCurrY (); // refresh the View. Otherwise, there may be an error in postInvalidate ();}}}

 

From code analysis, we know that when we judge the finger event, when we move ACTION_MOVE, we determine that when the horizontal movement distance can be determined to be greater than the smallest moving distance, at this time, we intercept the event of VIewGroup downstream distribution. At this time, the event will be consumed by the onTouchEvent of ViewGroup. We will process the slide of the read image in onTouchEvent.

In this Demo, we should note that our layout file is as follows:

 

  
          
           
            
             
       
        
       
      
     
    
   
  
 
We can see that we have set the clickable = true attribute for ImageView. If we remove this attribute, we cannot manually slide the image.

 

Everyone will be wondering why? Next we will answer the question based on the event Distribution Analysis of the previous Android event distribution mechanism learning notes. Through analysis, if we do not set clickable = true for ImageView, The onEventTouch of ImageView will find if (viewFlags & CLICKABLE) = CLICKABLE | (viewFlags & LONG_CLICKABLE) = LONG_CLICKABLE). When onEventTouch returns false, the dispatchTouchEvent of ImageView returns false, meaning that the ImageView control does not consume events by default. Remember that we mentioned in Android event distribution that when an event is distributed from Activity to the leaf control, the leaf control starts to trace and consume the event, I still remember the "Memory" function of the last event. When we trace back from the event distributed by the Activity until the Activity is not consumed, subsequent events will not be distributed from the root control DecorView.

Next, let's ask, if we don't set clickable = true for ImageView, is there a way to slide the image? The answer is of course there are. Method 1: Here we use a Button to replace ImageVIew; Method 2: if we do not consume the ImageView event, our event will be traced back to the ViewGroup to try to consume it, we can consume the onTouchEvent in VIewGroup. By modifying the onTouchEvent return value to true, we can achieve the consumption effect. Then our subsequent actions will remember the "loop" of event distribution and consumption, and our subsequent events will be consumed. Our method 2 is, in ViewGroup, The onTouchEvent return value is returned for consumption. Here we can comment out the onInterceptTouchEvent interception event, which also achieves the effect of the above Code. The above is the main explanation of the image carousel event processing process. The Code also includes the code for processing Image Automatic carousel.

Later, I will try to analyze more complex event distribution processes. For example, the ListView base class AbsLIstView has already added its own event distribution and interception processing, how can we intercept ListView with our own event distribution. Demo of the carousel example.

 

 

 


 

Related Article

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.