博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android 滑动效果
阅读量:5155 次
发布时间:2019-06-13

本文共 26469 字,大约阅读时间需要 88 分钟。

转自:http://blog.csdn.net/sunboy_2050/article/details/7483176

感谢原作者.

=====================================================================================================

自定义控件,较常用ViewViewGroup、Scroller三个类,其继承关系如下:

 

 

本示例自定义控件,实现一个Gallery效果,并添加了一个显示View个数和位置的bar条,效果图:

 

 

自定义控件,包含通过继承实现的自定义控件和自定义控件属性两部分,即控件和属性

1自定义属性

自定义属性,分为定义属性、解析属性设置属性三部分,具体步骤:

首先,在res/valus/attrs.xml属性资源文件中,定义控件属性

  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <resources>  
  3.     <declare-styleable name="com.myapps.widget.Pager">  
  4.         <attr name="pageWidth" format="dimension" />  
  5.     </declare-styleable>  
  6.     <declare-styleable name="com.myapps.widget.PagerBar">  
  7.         <attr name="barColor" format="color" />  
  8.         <attr name="highlightColor" format="color" />  
  9.         <attr name="fadeDelay" format="integer" />  
  10.         <attr name="fadeDuration" format="integer" />  
  11.         <attr name="roundRectRadius" format="dimension" />  
  12.     </declare-styleable>  
  13. </resources>  
然后,在自定义控件的代码中,解析自定义的属性,如在PagerBar.java:
  1. // 自定义属性  
  2.         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.com_myapps_widget_PagerBar);  
  3.         int barBackColor = a.getColor(R.styleable.com_myapps_widget_PagerBar_barColor, DEFAULT_BAR_BACKCOLOR);              // bar背景色  
  4.         int barForeColor = a.getColor(R.styleable.com_myapps_widget_PagerBar_highlightColor, DEFAULT_BAR_FORECOLOR);    // bar前景色  
  5.         fadeDelay = a.getInteger(R.styleable.com_myapps_widget_PagerBar_fadeDelay, DEFAULT_FADE_DELAY);             // bar消失延迟时间  
  6.         fadeDuration = a.getInteger(R.styleable.com_myapps_widget_PagerBar_fadeDuration, DEFAULT_FADE_DURATION);    // bar消失动画时间  
  7.         ovalRadius = a.getDimension(R.styleable.com_myapps_widget_PagerBar_roundRectRadius, 2f);  
  8.         a.recycle();  
// 自定义属性		TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.com_myapps_widget_PagerBar);		int barBackColor = a.getColor(R.styleable.com_myapps_widget_PagerBar_barColor, DEFAULT_BAR_BACKCOLOR);				// bar背景色		int barForeColor = a.getColor(R.styleable.com_myapps_widget_PagerBar_highlightColor, DEFAULT_BAR_FORECOLOR);	// bar前景色		fadeDelay = a.getInteger(R.styleable.com_myapps_widget_PagerBar_fadeDelay, DEFAULT_FADE_DELAY);				// bar消失延迟时间		fadeDuration = a.getInteger(R.styleable.com_myapps_widget_PagerBar_fadeDuration, DEFAULT_FADE_DURATION);	// bar消失动画时间		ovalRadius = a.getDimension(R.styleable.com_myapps_widget_PagerBar_roundRectRadius, 2f);		a.recycle();
最后,在布局文件中设置属性,如在main.xml
  1. <com.homer.mycontrol.PagerBar  
  2.     android:id="@+id/control"  
  3.     android:layout_width="fill_parent"  
  4.     android:layout_height="4dip"  
  5.     android:layout_margin="8dip"  
  6.     myapps:roundRectRadius="2dip" />  <!-- 自定义圆角 -->  

其中,在布局中间main.xml中,需要注意:

xmlns:myapps="http://schemas.android.com/apk/res/com.homer.mycontrol"

定义属性时,在declare-styleable的name中,需要包含com.myapps.widget.PagerBar,表示自定义的控件PageBar是widget子类,myapps是xmlns解析标记

解析属性时,在TypedArray中,需要包含R.styleable.com_myapps_widget_PagerBar,横线替换了圆点.

定义属性时,在com.homer.mycontrol.PagerBar中,需要包含myapps:roundRectRadius="2dip",加上myapps解析标记

2自定义控件PagerBar

自定义PagerBar,在图片下方用来显示图片滑到了第几页,即上面效果图(图2图3)中的下部银白色细条,具体实现:

  1. public PagerBar(Context context, AttributeSet attrs, int defStyle) {  
  2.     super(context, attrs, defStyle);  
  3.     // 自定义属性  
  4.     TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.com_myapps_widget_PagerBar);  
  5.     int barBackColor = a.getColor(R.styleable.com_myapps_widget_PagerBar_barColor, DEFAULT_BAR_BACKCOLOR);              // bar背景色  
  6.     int barForeColor = a.getColor(R.styleable.com_myapps_widget_PagerBar_highlightColor, DEFAULT_BAR_FORECOLOR);    // bar前景色  
  7.     fadeDelay = a.getInteger(R.styleable.com_myapps_widget_PagerBar_fadeDelay, DEFAULT_FADE_DELAY);             // bar消失延迟时间  
  8.     fadeDuration = a.getInteger(R.styleable.com_myapps_widget_PagerBar_fadeDuration, DEFAULT_FADE_DURATION);    // bar消失动画时间  
  9.     ovalRadius = a.getDimension(R.styleable.com_myapps_widget_PagerBar_roundRectRadius, 2f);  
  10.     a.recycle();  
  11.     barBackPaint = new Paint();  
  12.     barBackPaint.setColor(barBackColor);  
  13.     barForePaint = new Paint();  
  14.     barForePaint.setColor(barForeColor);  
  15.     fadeOutAnimation = new AlphaAnimation(1f, 0f);  
  16.     fadeOutAnimation.setDuration(fadeDuration);  
  17.     fadeOutAnimation.setRepeatCount(0);  
  18.     fadeOutAnimation.setInterpolator(new LinearInterpolator());  
  19.     fadeOutAnimation.setFillEnabled(true);  
  20.     fadeOutAnimation.setFillAfter(true);  
  21. public int getNumPages() {  
  22.     return numPages;  
  23. public void setNumPages(int numPages) {  
  24.     if (numPages <= 0) {  
  25.         throw new IllegalArgumentException("numPages must be positive");  
  26.     this.numPages = numPages;  
  27.     invalidate();       // 重绘View  
  28.     fadeOut();          // 设置bar消失效果  
  29. /** bar消失动画 */  
  30. private void fadeOut() {  
  31.     if (fadeDuration > 0) {  
  32.         clearAnimation();  
  33.         fadeOutAnimation.setStartTime(AnimationUtils.currentAnimationTimeMillis() + fadeDelay); //延迟fadeDelay后动画开始  
  34.         setAnimation(fadeOutAnimation);  
  35. /**  @return  0 to numPages-1 */  
  36. public int getCurrentPage() {  
  37.     return currentPage;  
  38. /** @param currentPage  0 to numPages-1  */  
  39. public void setCurrentPage(int currentPage) {  
  40.     if (currentPage < 0 || currentPage >= numPages) {  
  41.         throw new IllegalArgumentException("currentPage parameter out of bounds");  
  42.     if (this.currentPage != currentPage) {  
  43.         this.currentPage = currentPage;  
  44.         this.position = currentPage * getPageWidth();   // bar前景色滑动条的起始位置(像素值)  
  45.         invalidate();  
  46.         fadeOut();  
  47. /** 获取View的宽度,即bar的宽度 */  
  48. public int getPageWidth() {  
  49.     return getWidth() / numPages;   // getWidth()是PagerBar的宽度(减去了margin左右距离后)  
  50. /**  @param position     can be -pageWidth to pageWidth*(numPages+1)  */  
  51. public void setPosition(int position) {  
  52.     if (this.position != position) {  
  53.         this.position = position;  
  54.         invalidate();  
  55.         fadeOut();  
  56. @Override  
  57. protected void onDraw(Canvas canvas) {  
  58.     canvas.drawRoundRect(new RectF(0, 0, getWidth(), getHeight()), ovalRadius, ovalRadius, barBackPaint);   // 绘制bar背景  
  59.     canvas.drawRoundRect(new RectF(position, 0, position + (getWidth() / numPages), getHeight()), ovalRadius, ovalRadius, barForePaint);    // 绘制bar前景  
public PagerBar(Context context, AttributeSet attrs, int defStyle) {		super(context, attrs, defStyle);		// 自定义属性		TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.com_myapps_widget_PagerBar);		int barBackColor = a.getColor(R.styleable.com_myapps_widget_PagerBar_barColor, DEFAULT_BAR_BACKCOLOR);				// bar背景色		int barForeColor = a.getColor(R.styleable.com_myapps_widget_PagerBar_highlightColor, DEFAULT_BAR_FORECOLOR);	// bar前景色		fadeDelay = a.getInteger(R.styleable.com_myapps_widget_PagerBar_fadeDelay, DEFAULT_FADE_DELAY);				// bar消失延迟时间		fadeDuration = a.getInteger(R.styleable.com_myapps_widget_PagerBar_fadeDuration, DEFAULT_FADE_DURATION);	// bar消失动画时间		ovalRadius = a.getDimension(R.styleable.com_myapps_widget_PagerBar_roundRectRadius, 2f);		a.recycle();		barBackPaint = new Paint();		barBackPaint.setColor(barBackColor);		barForePaint = new Paint();		barForePaint.setColor(barForeColor);		fadeOutAnimation = new AlphaAnimation(1f, 0f);		fadeOutAnimation.setDuration(fadeDuration);		fadeOutAnimation.setRepeatCount(0);		fadeOutAnimation.setInterpolator(new LinearInterpolator());		fadeOutAnimation.setFillEnabled(true);		fadeOutAnimation.setFillAfter(true);	}	public int getNumPages() {		return numPages;	}	public void setNumPages(int numPages) {		if (numPages <= 0) {			throw new IllegalArgumentException("numPages must be positive");		}		this.numPages = numPages;		invalidate();		// 重绘View		fadeOut();			// 设置bar消失效果	}	/** bar消失动画 */	private void fadeOut() {		if (fadeDuration > 0) {			clearAnimation();			fadeOutAnimation.setStartTime(AnimationUtils.currentAnimationTimeMillis() + fadeDelay);	//延迟fadeDelay后动画开始			setAnimation(fadeOutAnimation);		}	}	/**  @return  0 to numPages-1 */	public int getCurrentPage() {		return currentPage;	}	/** @param currentPage  0 to numPages-1  */	public void setCurrentPage(int currentPage) {		if (currentPage < 0 || currentPage >= numPages) {			throw new IllegalArgumentException("currentPage parameter out of bounds");		}		if (this.currentPage != currentPage) {			this.currentPage = currentPage;			this.position = currentPage * getPageWidth();	// bar前景色滑动条的起始位置(像素值)			invalidate();			fadeOut();		}	}	/** 获取View的宽度,即bar的宽度 */	public int getPageWidth() {		return getWidth() / numPages;	// getWidth()是PagerBar的宽度(减去了margin左右距离后)	}	/**  @param position     can be -pageWidth to pageWidth*(numPages+1)  */	public void setPosition(int position) {		if (this.position != position) {			this.position = position;			invalidate();			fadeOut();		}	}	@Override	protected void onDraw(Canvas canvas) {		canvas.drawRoundRect(new RectF(0, 0, getWidth(), getHeight()), ovalRadius, ovalRadius, barBackPaint);	// 绘制bar背景		canvas.drawRoundRect(new RectF(position, 0, position + (getWidth() / numPages), getHeight()), ovalRadius, ovalRadius, barForePaint);	// 绘制bar前景	}}

3自定义控件Pager

自定义控件Pager,继承自ViewGroup,用来显示图片的,类似于Gallery,实现主要部分包含:

A自定义属性解析

BPager容器控件Scroller滑动页设置与控制

C、容器状态保存(onSaveInstanceState)

D容器事件监听接口

详细实现如下:

A自定义属性解析

  1. public Pager(Context context, AttributeSet attrs, int defStyle) {  
  2.     super(context, attrs, defStyle);  
  3.     // 自定义属性  
  4.     TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.com_myapps_widget_Pager);  
  5.     pageWidthSpec = a.getDimensionPixelSize(R.styleable.com_myapps_widget_Pager_pageWidth, SPEC_UNDEFINED);  
  6.     a.recycle();  
public Pager(Context context, AttributeSet attrs, int defStyle) {		super(context, attrs, defStyle);		// 自定义属性		TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.com_myapps_widget_Pager);		pageWidthSpec = a.getDimensionPixelSize(R.styleable.com_myapps_widget_Pager_pageWidth, SPEC_UNDEFINED);		a.recycle();	}
B
Pager容器控件Scroller滑动页设置与控制
  1. public void setCurrentPage(int currentPage) {  
  2.     mCurrentPage = Math.max(0, Math.min(currentPage, getChildCount()));     // 非常好  
  3.     scrollTo(getScrollXForPage(mCurrentPage), 0);  
  4.     invalidate();   // 重绘View  
  5. int getCurrentPage() {  
  6.     return mCurrentPage;  
  7. public void setPageWidth(int pageWidth) {  
  8.     this.pageWidthSpec = pageWidth;  
  9. public int getPageWidth() {  
  10.     return pageWidth;  
  11. /** 获取whichPage的Pager起始x位置,whichPage从0开始计 */  
  12. private int getScrollXForPage(int whichPage) {  
  13.     return (whichPage * pageWidth) - pageWidthPadding();  
  14. /** 返回View的 paddingwidth 一半(1/2)*/  
  15. int pageWidthPadding() {  
  16.     return ((getMeasuredWidth() - pageWidth) / 2);  
  17. @Override  
  18. public void computeScroll() {       // update  mScrollX and mScrollY  of View  
  19.     if (mScroller.computeScrollOffset()) {  
  20.         scrollTo(mScroller.getCurrX(), mScroller.getCurrY());  
  21.         postInvalidate();           // invalidate the View from a non-UI thread  
  22.     } else if (mNextPage != INVALID_SCREEN) {  
  23.         mCurrentPage = mNextPage;  
  24.         mNextPage = INVALID_SCREEN;  
  25.         clearChildrenCache();  
  26. @Override  
  27. protected void dispatchDraw(Canvas canvas) {    // draw the child views  
  28.     final long drawingTime = getDrawingTime();  // 绘制childView  
  29.     final int count = getChildCount();  
  30.     for (int i = 0; i < count; i++) {  
  31.         drawChild(canvas, getChildAt(i), drawingTime);  
  32.     for (OnScrollListener mListener : mListeners) { // 自定义接口  
  33.         int adjustedScrollX = getScrollX() + pageWidthPadding();  
  34.         mListener.onScroll(adjustedScrollX);  
  35.         if (adjustedScrollX % pageWidth == 0) { // scroll finished  
  36.             mListener.onViewScrollFinished(adjustedScrollX / pageWidth);  
  37. @Override  
  38. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  39.     super.onMeasure(widthMeasureSpec, heightMeasureSpec);  
  40.     pageWidth = (pageWidthSpec == SPEC_UNDEFINED) ? getMeasuredWidth() : pageWidthSpec;  
  41.     pageWidth = Math.min(pageWidth, getMeasuredWidth());  
  42.     final int count = getChildCount();  
  43.     for (int i = 0; i < count; i++) {  
  44.         widthMeasureSpec = MeasureSpec.makeMeasureSpec(pageWidth, MeasureSpec.EXACTLY);  
  45.         getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec);  
  46.     if (mFirstLayout) { // 第一次显示Pager时,page的位置  
  47.         scrollTo(getScrollXForPage(mCurrentPage), mScroller.getCurrY());  
  48.         mFirstLayout = false;  
  49. @Override  
  50. protected void onLayout(boolean changed, int left, int top, int right, int bottom) {  
  51.     int childLeft = 0;  
  52.     final int count = getChildCount();  // 绘制childView  
  53.     for (int i = 0; i < count; i++) {  
  54.         final View child = getChildAt(i);  
  55.         if (child.getVisibility() != View.GONE) {  
  56.             final int childWidth = child.getMeasuredWidth();  
  57.             child.layout(childLeft, 0, childLeft + childWidth, child.getMeasuredHeight());  
  58.             childLeft += childWidth;  
public void setCurrentPage(int currentPage) {		mCurrentPage = Math.max(0, Math.min(currentPage, getChildCount()));		// 非常好		scrollTo(getScrollXForPage(mCurrentPage), 0);		invalidate();	// 重绘View	}	int getCurrentPage() {		return mCurrentPage;	}	public void setPageWidth(int pageWidth) {		this.pageWidthSpec = pageWidth;	}	public int getPageWidth() {		return pageWidth;	}	/** 获取whichPage的Pager起始x位置,whichPage从0开始计 */	private int getScrollXForPage(int whichPage) {		return (whichPage * pageWidth) - pageWidthPadding();	}	/** 返回View的 paddingwidth 一半(1/2)*/	int pageWidthPadding() {		return ((getMeasuredWidth() - pageWidth) / 2);	}	@Override	public void computeScroll() {		// update  mScrollX and mScrollY  of View		if (mScroller.computeScrollOffset()) {			scrollTo(mScroller.getCurrX(), mScroller.getCurrY());			postInvalidate();			// invalidate the View from a non-UI thread		} else if (mNextPage != INVALID_SCREEN) {			mCurrentPage = mNextPage;			mNextPage = INVALID_SCREEN;			clearChildrenCache();		}	}	@Override	protected void dispatchDraw(Canvas canvas) {	// draw the child views				final long drawingTime = getDrawingTime();	// 绘制childView		final int count = getChildCount();		for (int i = 0; i < count; i++) {			drawChild(canvas, getChildAt(i), drawingTime);		}		for (OnScrollListener mListener : mListeners) {	// 自定义接口			int adjustedScrollX = getScrollX() + pageWidthPadding();			mListener.onScroll(adjustedScrollX);			if (adjustedScrollX % pageWidth == 0) {	// scroll finished				mListener.onViewScrollFinished(adjustedScrollX / pageWidth);			}		}	}	@Override	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {		super.onMeasure(widthMeasureSpec, heightMeasureSpec);		pageWidth = (pageWidthSpec == SPEC_UNDEFINED) ? getMeasuredWidth() : pageWidthSpec;		pageWidth = Math.min(pageWidth, getMeasuredWidth());		final int count = getChildCount();		for (int i = 0; i < count; i++) {			widthMeasureSpec = MeasureSpec.makeMeasureSpec(pageWidth, MeasureSpec.EXACTLY);			getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec);		}		if (mFirstLayout) {	// 第一次显示Pager时,page的位置			scrollTo(getScrollXForPage(mCurrentPage), mScroller.getCurrY());			mFirstLayout = false;		}	}	@Override	protected void onLayout(boolean changed, int left, int top, int right, int bottom) {		int childLeft = 0;		final int count = getChildCount();	// 绘制childView		for (int i = 0; i < count; i++) {			final View child = getChildAt(i);			if (child.getVisibility() != View.GONE) {				final int childWidth = child.getMeasuredWidth();				child.layout(childLeft, 0, childLeft + childWidth, child.getMeasuredHeight());				childLeft += childWidth;			}		}	}
  1. @Override  
  2. public boolean onInterceptTouchEvent(MotionEvent ev) {  
  3.     final int action = ev.getAction();  
  4.     if ((action == MotionEvent.ACTION_MOVE) && (mTouchState != TOUCH_STATE_REST)) { // 正在滑动中  
  5.         return true;  
  6.     final float x = ev.getX();  
  7.     final float y = ev.getY();  
  8.     switch (action) {  
  9.     case MotionEvent.ACTION_MOVE:  
  10.         if (mTouchState == TOUCH_STATE_REST) {  
  11.             checkStartScroll(x, y);  
  12.         break;  
  13.     case MotionEvent.ACTION_DOWN:  
  14.         mLastMotionX = x;  
  15.         mLastMotionY = y;  
  16.         mAllowLongPress = true;  
  17.         mTouchState = mScroller.isFinished() ? TOUCH_STATE_REST : TOUCH_STATE_SCROLLING;    // scroll 完成后,重置状态  
  18.         break;  
  19.     case MotionEvent.ACTION_CANCEL:  
  20.     case MotionEvent.ACTION_UP:  
  21.         clearChildrenCache();  
  22.         mTouchState = TOUCH_STATE_REST;  
  23.         break;  
  24.     return mTouchState != TOUCH_STATE_REST;  
  25. @Override  
  26. public boolean onTouchEvent(MotionEvent ev) {  
  27.     if (mVelocityTracker == null) {  
  28.         mVelocityTracker = VelocityTracker.obtain();  
  29.     mVelocityTracker.addMovement(ev);  
  30.     final int action = ev.getAction();  
  31.     final float x = ev.getX();  
  32.     final float y = ev.getY();  
  33.     switch (action) {  
  34.     case MotionEvent.ACTION_DOWN:  
  35.         if (!mScroller.isFinished()) {  
  36.             mScroller.abortAnimation();  
  37.         mLastMotionX = x;  
  38.         break;  
  39.     case MotionEvent.ACTION_MOVE:  
  40.         if (mTouchState == TOUCH_STATE_REST) {  
  41.             checkStartScroll(x, y);  
  42.         } else if (mTouchState == TOUCH_STATE_SCROLLING) {  // scrolling 状态时,重绘view  
  43.             int deltaX = (int) (mLastMotionX - x);  
  44.             mLastMotionX = x;  
  45.             if (getScrollX() < 0 || getScrollX() > getChildAt(getChildCount() - 1).getLeft()) {  
  46.                 deltaX /= 2;  
  47.             scrollBy(deltaX, 0);  
  48.         break;  
  49.     case MotionEvent.ACTION_UP:  
  50.         if (mTouchState == TOUCH_STATE_SCROLLING) {  
  51.             final VelocityTracker velocityTracker = mVelocityTracker;  
  52.             velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);  
  53.             int velocityX = (int) velocityTracker.getXVelocity();  
  54.             if (velocityX > SNAP_VELOCITY && mCurrentPage > 0) {  
  55.                 snapToPage(mCurrentPage - 1);  
  56.             } else if (velocityX < -SNAP_VELOCITY && mCurrentPage < getChildCount() - 1) {  
  57.                 snapToPage(mCurrentPage + 1);  
  58.             } else {  
  59.                 snapToDestination();  
  60.             if (mVelocityTracker != null) {  
  61.                 mVelocityTracker.recycle();  
  62.                 mVelocityTracker = null;  
  63.         mTouchState = TOUCH_STATE_REST;  
  64.         break;  
  65.     case MotionEvent.ACTION_CANCEL:  
  66.         mTouchState = TOUCH_STATE_REST;  
  67.     return true;  
  68. /** 检查scroll状态,并设置绘制scroll缓存 */  
  69. private void checkStartScroll(float x, float y) {  
  70.     final int xDiff = (int) Math.abs(x - mLastMotionX);  
  71.     final int yDiff = (int) Math.abs(y - mLastMotionY);  
  72.     boolean xMoved = xDiff > mTouchSlop;  
  73.     boolean yMoved = yDiff > mTouchSlop;  
  74.     if (xMoved || yMoved) {  
  75.         if (xMoved) {  
  76.             mTouchState = TOUCH_STATE_SCROLLING;        // 设置为scrolling 状态  
  77.             enableChildrenCache();  
  78.         if (mAllowLongPress) {  
  79.             mAllowLongPress = false;  
  80.             final View currentScreen = getChildAt(mCurrentPage);  
  81.             currentScreen.cancelLongPress();    // Cancels a pending long press  
  82. void enableChildrenCache() {  
  83.     setChildrenDrawingCacheEnabled(true);       // Enables or disables the drawing cache for each child of this viewGroup  
  84.     setChildrenDrawnWithCacheEnabled(true); // Tells the ViewGroup to draw its children using their drawing cache  
  85. void clearChildrenCache() {  
  86.     setChildrenDrawnWithCacheEnabled(false);  
  87. private void snapToDestination() {  
  88.     final int startX = getScrollXForPage(mCurrentPage);  
  89.     int whichPage = mCurrentPage;  
  90.     if (getScrollX() < startX - getWidth() / 8) {  
  91.         whichPage = Math.max(0, whichPage - 1);  
  92.     } else if (getScrollX() > startX + getWidth() / 8) {  
  93.         whichPage = Math.min(getChildCount() - 1, whichPage + 1);  
  94.     snapToPage(whichPage);  
  95. void snapToPage(int whichPage) {  
  96.     enableChildrenCache();  
  97.     boolean changingPages = whichPage != mCurrentPage;  
  98.     mNextPage = whichPage;  
  99.     View focusedChild = getFocusedChild();  
  100.     if (focusedChild != null && changingPages && focusedChild == getChildAt(mCurrentPage)) {  
  101.         focusedChild.clearFocus();  
  102.     final int newX = getScrollXForPage(whichPage);  
  103.     final int delta = newX - getScrollX();  
  104.     mScroller.startScroll(getScrollX(), 0, delta, 0, Math.abs(delta) * 2);  
  105.     invalidate();  
  106. /** 向左滑动 */  
  107. public void scrollLeft() {  
  108.     if (mNextPage == INVALID_SCREEN && mCurrentPage > 0 && mScroller.isFinished()) {  
  109.         snapToPage(mCurrentPage - 1);  
  110. /** 向右滑动 */  
  111. public void scrollRight() {  
  112.     if (mNextPage == INVALID_SCREEN && mCurrentPage < getChildCount() - 1 && mScroller.isFinished()) {  
  113.         snapToPage(mCurrentPage + 1);  
@Override	public boolean onInterceptTouchEvent(MotionEvent ev) {		final int action = ev.getAction();		if ((action == MotionEvent.ACTION_MOVE) && (mTouchState != TOUCH_STATE_REST)) {	// 正在滑动中			return true;		}		final float x = ev.getX();		final float y = ev.getY();		switch (action) {		case MotionEvent.ACTION_MOVE:			if (mTouchState == TOUCH_STATE_REST) {				checkStartScroll(x, y);			}			break;		case MotionEvent.ACTION_DOWN:			mLastMotionX = x;			mLastMotionY = y;			mAllowLongPress = true;			mTouchState = mScroller.isFinished() ? TOUCH_STATE_REST : TOUCH_STATE_SCROLLING;	// scroll 完成后,重置状态			break;		case MotionEvent.ACTION_CANCEL:		case MotionEvent.ACTION_UP:			clearChildrenCache();			mTouchState = TOUCH_STATE_REST;			break;		}		return mTouchState != TOUCH_STATE_REST;	}	@Override	public boolean onTouchEvent(MotionEvent ev) {		if (mVelocityTracker == null) {			mVelocityTracker = VelocityTracker.obtain();		}		mVelocityTracker.addMovement(ev);		final int action = ev.getAction();		final float x = ev.getX();		final float y = ev.getY();		switch (action) {		case MotionEvent.ACTION_DOWN:			if (!mScroller.isFinished()) {				mScroller.abortAnimation();			}			mLastMotionX = x;			break;					case MotionEvent.ACTION_MOVE:			if (mTouchState == TOUCH_STATE_REST) {				checkStartScroll(x, y);			} else if (mTouchState == TOUCH_STATE_SCROLLING) {	// scrolling 状态时,重绘view				int deltaX = (int) (mLastMotionX - x);				mLastMotionX = x;				if (getScrollX() < 0 || getScrollX() > getChildAt(getChildCount() - 1).getLeft()) {					deltaX /= 2;				}				scrollBy(deltaX, 0);			}			break;					case MotionEvent.ACTION_UP:			if (mTouchState == TOUCH_STATE_SCROLLING) {				final VelocityTracker velocityTracker = mVelocityTracker;				velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);				int velocityX = (int) velocityTracker.getXVelocity();				if (velocityX > SNAP_VELOCITY && mCurrentPage > 0) {					snapToPage(mCurrentPage - 1);				} else if (velocityX < -SNAP_VELOCITY && mCurrentPage < getChildCount() - 1) {					snapToPage(mCurrentPage + 1);				} else {					snapToDestination();				}				if (mVelocityTracker != null) {					mVelocityTracker.recycle();					mVelocityTracker = null;				}			}			mTouchState = TOUCH_STATE_REST;			break;		case MotionEvent.ACTION_CANCEL:			mTouchState = TOUCH_STATE_REST;		}		return true;	}	/** 检查scroll状态,并设置绘制scroll缓存 */	private void checkStartScroll(float x, float y) {		final int xDiff = (int) Math.abs(x - mLastMotionX);		final int yDiff = (int) Math.abs(y - mLastMotionY);		boolean xMoved = xDiff > mTouchSlop;		boolean yMoved = yDiff > mTouchSlop;		if (xMoved || yMoved) {			if (xMoved) {				mTouchState = TOUCH_STATE_SCROLLING;		// 设置为scrolling 状态				enableChildrenCache();			}			if (mAllowLongPress) {				mAllowLongPress = false;				final View currentScreen = getChildAt(mCurrentPage);				currentScreen.cancelLongPress();	// Cancels a pending long press			}		}	}	void enableChildrenCache() {		setChildrenDrawingCacheEnabled(true);		// Enables or disables the drawing cache for each child of this viewGroup		setChildrenDrawnWithCacheEnabled(true);	// Tells the ViewGroup to draw its children using their drawing cache	}	void clearChildrenCache() {		setChildrenDrawnWithCacheEnabled(false);	}	private void snapToDestination() {		final int startX = getScrollXForPage(mCurrentPage);		int whichPage = mCurrentPage;		if (getScrollX() < startX - getWidth() / 8) {			whichPage = Math.max(0, whichPage - 1);		} else if (getScrollX() > startX + getWidth() / 8) {			whichPage = Math.min(getChildCount() - 1, whichPage + 1);		}		snapToPage(whichPage);	}	void snapToPage(int whichPage) {		enableChildrenCache();		boolean changingPages = whichPage != mCurrentPage;		mNextPage = whichPage;		View focusedChild = getFocusedChild();		if (focusedChild != null && changingPages && focusedChild == getChildAt(mCurrentPage)) {			focusedChild.clearFocus();		}		final int newX = getScrollXForPage(whichPage);		final int delta = newX - getScrollX();		mScroller.startScroll(getScrollX(), 0, delta, 0, Math.abs(delta) * 2);		invalidate();	}	/** 向左滑动 */	public void scrollLeft() {		if (mNextPage == INVALID_SCREEN && mCurrentPage > 0 && mScroller.isFinished()) {			snapToPage(mCurrentPage - 1);		}	}	/** 向右滑动 */	public void scrollRight() {		if (mNextPage == INVALID_SCREEN && mCurrentPage < getChildCount() - 1 && mScroller.isFinished()) {			snapToPage(mCurrentPage + 1);		}	}

C容器状态保存(onSaveInstanceState)

  1. /** 保存状态 */  
  2. public static class SavedState extends BaseSavedState {  
  3.     int currentScreen = -1;  
  4.     SavedState(Parcelable superState) {  
  5.         super(superState);  
  6.     private SavedState(Parcel in) {  
  7.         super(in);  
  8.         currentScreen = in.readInt();  
  9.     public static final Parcelable.Creator<SavedState> CREATOR = new Parcelable.Creator<SavedState>() {  
  10.         public SavedState createFromParcel(Parcel in) { // get data written by Parcelable.writeToParcel()     
  11.             return new SavedState(in);  
  12.         public SavedState[] newArray(int size) {            // create  array of the Parcelable   
  13.             return new SavedState[size];  
  14.     @Override  
  15.     public void writeToParcel(Parcel out, int flags) {      // set data to parcel  
  16.         super.writeToParcel(out, flags);  
  17.         out.writeInt(currentScreen);  
  18. @Override  
  19. protected Parcelable onSaveInstanceState() {        // 保存状态  
  20.     final SavedState state = new SavedState(super.onSaveInstanceState());  
  21.     state.currentScreen = mCurrentPage;     // save InstanceState  
  22.     return state;  
  23. @Override  
  24. protected void onRestoreInstanceState(Parcelable state) {   // 恢复状态  
  25.     SavedState savedState = (SavedState) state;  
  26.     super.onRestoreInstanceState(savedState.getSuperState());   // get InstanceState  
  27.     if (savedState.currentScreen != INVALID_SCREEN) {  
  28.         mCurrentPage = savedState.currentScreen;      
/** 保存状态 */	public static class SavedState extends BaseSavedState {		int currentScreen = -1;		SavedState(Parcelable superState) {			super(superState);		}		private SavedState(Parcel in) {			super(in);			currentScreen = in.readInt();		}		public static final Parcelable.Creator
CREATOR = new Parcelable.Creator
() { public SavedState createFromParcel(Parcel in) { // get data written by Parcelable.writeToParcel() return new SavedState(in); } public SavedState[] newArray(int size) { // create array of the Parcelable return new SavedState[size]; } }; @Override public void writeToParcel(Parcel out, int flags) { // set data to parcel super.writeToParcel(out, flags); out.writeInt(currentScreen); } } @Override protected Parcelable onSaveInstanceState() { // 保存状态 final SavedState state = new SavedState(super.onSaveInstanceState()); state.currentScreen = mCurrentPage; // save InstanceState return state; } @Override protected void onRestoreInstanceState(Parcelable state) { // 恢复状态 SavedState savedState = (SavedState) state; super.onRestoreInstanceState(savedState.getSuperState()); // get InstanceState if (savedState.currentScreen != INVALID_SCREEN) { mCurrentPage = savedState.currentScreen; } }

D容器事件监听接口

  1. public void addOnScrollListener(OnScrollListener listener) {  
  2.     mListeners.add(listener);  
  3. public void removeOnScrollListener(OnScrollListener listener) {  
  4.     mListeners.remove(listener);  
  5. /** 自定义接口 */  
  6. public static interface OnScrollListener {  
  7.     void onScroll(int scrollX);  
  8.     void onViewScrollFinished(int currentPage);  
public void addOnScrollListener(OnScrollListener listener) {		mListeners.add(listener);	}	public void removeOnScrollListener(OnScrollListener listener) {		mListeners.remove(listener);	}	/** 自定义接口 */	public static interface OnScrollListener {		void onScroll(int scrollX);		void onViewScrollFinished(int currentPage);	}

 

 
 
 
 
 

转载于:https://www.cnblogs.com/elefish/archive/2013/02/01/2889035.html

你可能感兴趣的文章
常问面试题
查看>>
《构建之法》课程总结及建议
查看>>
echarts使用
查看>>
SQL2005触发器和存储过程
查看>>
poj 2186 Popular Cows 有向图强连通分量 tarjan
查看>>
hdu 2545 并查集
查看>>
[BZOJ4568][SCOI2016]幸运数字(倍增LCA,点分治+线性基)
查看>>
尤金·卡巴斯基:卡巴斯基实验室调查内网遭黑客攻击事件
查看>>
android之Handler Runnable实现倒计时
查看>>
putty修改编码
查看>>
安全版字符串操作函数
查看>>
数据库msqlserver的几种类型及解决MSSQLServer服务启动不了的问题
查看>>
CSS轮廓 边距 填充 分组和嵌套
查看>>
JAVA多线程--线程阻塞与唤醒
查看>>
JavaSE语法基础总结
查看>>
python自动化测试之mysql5.0版本数据库查询数据时出现乱码问题分析
查看>>
线性表9 - 数据结构和算法14
查看>>
循环移位
查看>>
Spring mvc4 + ActiveMQ 整合
查看>>
Python基础(8)素数输出
查看>>