自定义控件--垂直滑动布局


自定义一个垂直的布局

package com.zyh.verticalscrollview;

import android.content.Context;
import android.util.AttributeSet;
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 VerticalSrcollView extends ViewGroup {

	public VerticalSrcollView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
	}

	private Context cx;

	public VerticalSrcollView(Context context) {
		super(context);
		this.cx = context;
		init();
	}

	public VerticalSrcollView(Context context, AttributeSet attrs) {
		super(context, attrs);
		this.cx = context;
		init();
	}

	private void init() {
		scroller = new Scroller(cx);
		detector = new GestureDetector(cx, new OnGestureListener() {
			public boolean onSingleTapUp(MotionEvent e) {
				return false;
			}

			public void onShowPress(MotionEvent e) {
			}

			/**
			 * 当手指正常滑动时回调
			 */
			public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
				if ((distanceY < 0 && curId == 0) || (distanceY > 0 && curId == getChildCount() - 1)) {// 首页跟末尾页超出边界
					return false;
				}
				scrollBy(0, (int) distanceY);
				return false;
			}

			public void onLongPress(MotionEvent e) {
			}

			/**
			 * 当快速滑动式回调
			 */
			public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
				System.out.println("vY:" + velocityY);
				System.out.println("cr:" + curId);
				if (velocityY > 0 && curId > 0) {
					moveToDest(curId - 1);
				} else if (velocityY < 0 && curId < getChildCount() - 1) {
					moveToDest(curId + 1);
				} else {
					moveToDest(curId);
				}
				isFling = true;
				return false;
			}

			public boolean onDown(MotionEvent e) {
				return false;
			}
		});
	}

	/**
	 * 对子view进行排列布局
	 */
	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {

		for (int i = 0; i < getChildCount(); i++) {
			View view = this.getChildAt(i);
			view.layout(0, i * getHeight(), getWidth(), (i + 1) * getHeight());
		}
	}

	/**
	 * 必须对子View进行measure
	 */
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);

		for (int i = 0; i < getChildCount(); i++) {
			View view = getChildAt(i);
			view.measure(widthMeasureSpec, heightMeasureSpec);
		}
	}

	private GestureDetector detector;
	private Scroller scroller;
	private int curId;// 当前子View的Id
	private boolean isFling = false; // 是否发生快速滑动

	@Override
	public boolean onTouchEvent(MotionEvent event) {

		detector.onTouchEvent(event);// 交给手势识别器

		switch (event.getAction()) {
			case MotionEvent.ACTION_UP:// 手指抬起
				if (!isFling) moveToDest();
				isFling = false;
				break;
			default:
				break;
		}
		return true;
	}

	/**
	 * ViewGroup的内容移动到合适位置
	 */
	private void moveToDest() {
		// 计算当前子view的id
		int destId = (getHeight() / 2 + getScrollY()) / getHeight();
		moveToDest(destId);
	}

	/**
	 * 将指定下标destId的控件移到屏幕
	 * @param destId
	 */
	private void moveToDest(int destId) {
		curId = destId;
		if (destId > getChildCount() - 1) destId = getChildCount() - 1;
		int distance = destId * getHeight() - getScrollY();// 需要移动的距离
		// scrollBy(0, distance);
		scroller.startScroll(0, getScrollY(), 0, distance);
		invalidate();// 刷新视图,执行computeScroll()
	}

	@Override
	public void computeScroll() {
		if (scroller.computeScrollOffset()) {
			scrollTo(0, scroller.getCurrY());
			invalidate();
		}
	}

	public void setOnPageScrollListener(IPageChangeListener changeListener) {
		this.pageChangeListener = changeListener;
	}

	private IPageChangeListener pageChangeListener;

	/**
	 * 页面滑动监听器
	 * @author zyh
	 */
	public interface IPageChangeListener {
		public void changeTo(int pageId);
	}
}