- import android.content.Context;
- import android.graphics.Canvas;
- import android.util.AttributeSet;
- import android.util.Log;
- import android.view.GestureDetector;
- import android.view.GestureDetector.OnGestureListener;
- import android.view.MotionEvent;
- import android.view.View;
- import android.view.ViewGroup;
- import android.widget.Scroller;
- public class scollgroup extends ViewGroup implements OnGestureListener{
- public static final String tag = "CScrollView";
- public static final int TOUCH_STATUS_NORMAL = 0;
- public static final int TOUCH_STATUS_FLING = 1;
- public static final int TOUCH_STATUS_SCROLLING = 2;
- public static final int TOUCH_STATUS_MOVING = 3;
- /** 滚动一屏所花的时间*/
- private static final int SCROLL_ANIMATION_TIME = 1000;
- /** 首屏和尾屏的超屏数值*/
- private static final int SCREEN_OFFSET = 100;
- public int mStatus = TOUCH_STATUS_NORMAL;
- protected GestureDetector mGestureDetector;
- protected Scroller mScroller;
- private int mCurrentPosX = 0;
- private int mLastPosX;
- private int mCurrentScreen = 0;
- private int mDownPosX = 0;
- private IndicatorControl mIndicatorControl;
- public scollgroup(Context context, AttributeSet attrs) {
- super(context, attrs);
- mGestureDetector = new GestureDetector(this);
- mScroller = new Scroller(context);
- }
- public scollgroup(Context context) {
- super(context);
- mGestureDetector = new GestureDetector(this);
- mScroller = new Scroller(context);
- }
- /**
- * 设置指示控制器
- * @param indicatorControl 指示控制器
- */
- public void setIndicatorControl(IndicatorControl indicatorControl) {
- this.mIndicatorControl = indicatorControl;
- if(mIndicatorControl != null) {
- indicatorControl.setCount(this.getChildCount());
- }
- }
- /**
- * 计算每个子控件的位置
- */
- @Override
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- final int childCount = getChildCount();
- int left = 0;
- View child = null;
- for(int i = 0; i < childCount; i++) {
- child = getChildAt(i);
- if(child.getVisibility() == View.GONE)
- continue;
- final int width = child.getMeasuredWidth();
- child.layout(left, 0, left + width, child.getMeasuredHeight());
- left += width;
- }
- }
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- final int childCount = getChildCount();
- View child = null;
- for(int i = 0; i < childCount; i++) {
- child = getChildAt(i);
- child.measure(widthMeasureSpec, heightMeasureSpec);
- // Log.d(tag, "width = " + MeasureSpec.getSize(widthMeasureSpec) + "; height = " + MeasureSpec.getSize(heightMeasureSpec));
- }
- }
- @Override
- public boolean onInterceptTouchEvent(MotionEvent event) {
- switch(event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- Log.d(tag, "onInterceptTouchEvent => ACTION_DOWN");
- return false;
- //触屏移动时,则传递事件到OnTouch事件
- case MotionEvent.ACTION_MOVE:
- Log.d(tag, "onInterceptTouchEvent => ACTION_MOVE");
- return true;
- }
- Log.d(tag, "onInterceptTouchEvent => " + event.getAction());
- return true;
- }
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- final int x = (int)event.getX();
- mGestureDetector.onTouchEvent(event);
- switch(event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- Log.d(tag, "onTouchEvent => ACTION_DOWN");
- if(!mScroller.isFinished()) {
- mScroller.abortAnimation();
- }
- mStatus = TOUCH_STATUS_MOVING;
- mLastPosX = mCurrentPosX;
- mDownPosX = x;
- case MotionEvent.ACTION_MOVE:
- Log.d(tag, "onTouchEvent => ACTION_MOVE");
- //计算当前滚动到的坐标
- mCurrentPosX = mLastPosX + mDownPosX - x;
- //屏幕第一屏和最后一屏越界不能超过10
- mCurrentPosX = Math.max(
- Math.min(mCurrentPosX, (getChildCount() - 1)
- * getMeasuredWidth() + SCREEN_OFFSET), -SCREEN_OFFSET);
- // Log.d(tag, "mCurrentX = " + mCurrentPosX + "; mDownPosX = " + mDownPosX + "; x = " + x);
- scrollTo(mCurrentPosX, 0);
- break;
- case MotionEvent.ACTION_UP:
- Log.d(tag, "onTouchEvent => ACTION_UP");
- //计算当前滚动到的屏幕,如果已触发FLING事件,则不用计算当前屏幕,因为已在onFling事件中计算出来了
- if(mStatus != TOUCH_STATUS_FLING)
- mCurrentScreen = calculateScreen(mCurrentPosX);
- // Log.d(tag, "mCurrentScreen = " + mCurrentScreen);
- scrollTo(mCurrentScreen);
- break;
- }
- return true;
- }
- /**
- * 将控件滚动到指定Subview
- * @param screenIndex
- */
- public void scrollTo(int screenIndex) {
- int targetX = screenIndex * getMeasuredWidth();
- // Log.d(tag, "getMeasuredWidth = " + getMeasuredWidth());
- //计算执行滚动事件所花的时间
- int time = Math.abs(mCurrentPosX - screenIndex * getMeasuredWidth())
- * SCROLL_ANIMATION_TIME / getMeasuredWidth();
- mStatus = TOUCH_STATUS_SCROLLING;
- // Log.d(tag, "mCurrentPosX = " + mCurrentPosX + "; targetX -mCurrentPosX = " + (targetX -mCurrentPosX));
- mScroller.startScroll(mCurrentPosX, 0, targetX - mCurrentPosX , 0, time);
- computeScroll();
- }
- @Override
- public void computeScroll() {
- if(mStatus == TOUCH_STATUS_SCROLLING && mScroller.computeScrollOffset()) {
- scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
- mCurrentPosX = mScroller.getCurrX();
- postInvalidate();
- } else if(mStatus == TOUCH_STATUS_SCROLLING) {
- mStatus = TOUCH_STATUS_NORMAL;
- mCurrentPosX = mScroller.getCurrX();
- if(mIndicatorControl != null) {
- mIndicatorControl.setSelected(calculateScreen(mCurrentPosX));
- }
- }
- }
- /**
- * 通过当前所在坐标计算出屏幕属于哪一屏
- * @param curPos 当前坐标
- */
- private int calculateScreen(int curPos) {
- int curScreen = curPos / getMeasuredWidth();
- if((curPos - curScreen * getMeasuredWidth()) > getMeasuredWidth() / 2) {
- curScreen ++;
- }
- return Math.min(Math.max(0, curScreen), getChildCount() - 1);
- }
- @Override
- public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
- float velocityY) {
- // Log.i(tag, "Fling >> velocityX : " + velocityX + "; velocityY : " + velocityY);
- // Log.i(tag, "Fling >> event1 : " + e1.getX() + ", " + e1.getY() + "; event2 : " + e2.getX() + ", " + e2.getY());
- mStatus = TOUCH_STATUS_FLING;
- if(velocityX > 0) {
- mCurrentScreen = Math.max(mCurrentScreen - 1, 0);
- } else {
- mCurrentScreen = Math.min(mCurrentScreen + 1, getChildCount() - 1);
- }
- return false;
- }
- public void requestInvalidate(int width) {
- mCurrentPosX = width * mCurrentScreen;
- scrollTo(mCurrentPosX, 0);
- }
- @Override
- public boolean onDown(MotionEvent e) {
- // TODO Auto-generated method stub
- return false;
- }
- @Override
- public void onShowPress(MotionEvent e) {
- // TODO Auto-generated method stub
- }
- @Override
- public boolean onSingleTapUp(MotionEvent e) {
- // TODO Auto-generated method stub
- return false;
- }
- @Override
- public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
- float distanceY) {
- // TODO Auto-generated method stub
- return false;
- }
- @Override
- public void onLongPress(MotionEvent e) {
- // TODO Auto-generated method stub
- }
- /**
- * 指示器控制接口
- * @author 郑澍璋
- */
- public static interface IndicatorControl {
- /**
- * 设置指示索引的数量
- */
- public void setCount(int count);
- /**
- * 获取当前所指示的索引值
- */
- public int getCount();
- /**
- * 设置当前选中哪一项
- */
- public void setSelected(int index);
- }
- }