自定义ScrollView

阅读更多
以下是ScrollView的滑动效果代码,其中修复了一个事件拦截的BUG.
public class MyScrollView extends ViewGroup {
	
	
	private PageChangeListener pageChangeListener;
	public PageChangeListener getPageChangeListener() {
		return pageChangeListener;
	}

	public void setPageChangeListener(PageChangeListener pageChangeListener) {
		this.pageChangeListener = pageChangeListener;
	}

	/**
	 * 页面改变的监听者,当页面改变的时候就会回调
	 * 
	 * @author afu
	 *
	 */
	public interface PageChangeListener{
		/**
		 * 页面改变的时候回调,回传当前页面的下标
		 * @param currIndex 下标值
		 */
		public void moveTo(int currIndex);
	}
	
	/**
	 * 测量当前View
	 * 1.如果当前view是ViewGroup,就义务测量它的孩子,孩子在测量它的孩子。形成树状测量
	 * 2.测量过程,测量父类,测量孩子;
	 * 3.测量不只一次,测量多次;
	 * 4.widthMeasureSpec很大,包含了父类给这个控件的宽和父类给的模式
	 * 5.模式:1.未指定;2.指定,在一定的位置内;3.至多
	 * 
	 * onMeasure测量过程
	 * 1.父类给当前View的widthMeasureSpec保护宽和父类给的 模式,根据这两个只就可以得到width和模式
	 * 2.给孩子的宽的计算方式,宽减掉padding的值,得到孩子该有的空间
	 * 3.根据width 和父类的模式MeasureSpec, 得到新的newWith如下:
	 *  MeasureSpec.makeMeasureSpec
	 * 4.孩子再去测量还在。
	 */
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		//父类给这是控件的宽
		int width = MeasureSpec.getSize(widthMeasureSpec);
		//这个是父类给孩子的模式
		int Mode = MeasureSpec.getMode(widthMeasureSpec);
		//得到宽,父类给的宽减掉padding值,得到该给孩子多少空间
//		getWidth();
		//根据当前View的width和模式,得到该给孩子多少宽度
		int newWidth = MeasureSpec.makeMeasureSpec(width, Mode);
//		System.out.println(width+"  : "+Mode);
		//把孩子遍历出来测量-才能得到父类给孩子的大小-当前View该显示多宽
		for(int i=0;i dY){
				result = true;
			}
			
			break;
		case MotionEvent.ACTION_UP://离开
			System.out.println("onInterceptTouchEvent"+": ACTION_UP "+result);
	
			break;

		default:
			break;
		}
		System.out.println("onInterceptTouchEvent=="+ result);
		return result;
	}
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		super.onTouchEvent(event);//执行父类的方法
		System.out.println("onTouchEvent");
		detector.onTouchEvent(event);
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN://按下
			System.out.println("onTouchEvent"+": ACTION_DOWN ");
			//1.按下坐标记录
			startX = event.getX();
			break;
       case MotionEvent.ACTION_MOVE://移动
    	   System.out.println("onTouchEvent"+": ACTION_MOVE ");
			break;
       case MotionEvent.ACTION_UP://离开
    	   System.out.println("onTouchEvent"+": ACTION_UP ");
    	   //2.记录新的点的坐标
    	   float endX = event.getX();
    	   //3.计算偏移量
//    	   float dX = endX - startX;
    	   int temIndex = currIndex;
    	   if((endX - startX)>getWidth()/2){
    		   //显示上一个子页面
    		   temIndex--;
    	   }else if((startX - endX)>getWidth()/2){
    		   //显示下一个子页面
    		   temIndex++;
    	   }
    	   //移动到那个要么
    	   moveTo(temIndex);
			
			break;

		default:
			break;
		}
		return true;
	}

	/**
	 * 根据下标位置移动到对应的页面和屏蔽非法值
	 * @param temIndex 当前页面的下标
	 */
	public void moveTo(int temIndex) {
		if(temIndex < 0){
			temIndex = 0;
		}
		
		if(temIndex > getChildCount()-1){
			temIndex = getChildCount()-1;
		}
		//新的当前坐标
		currIndex = temIndex;
		if(pageChangeListener!= null){
			pageChangeListener.moveTo(currIndex);
		}
		//移动的是坐标currIndex*getWidth():就是要移动到的X轴的坐标
		//距离=末尾-起始 
		int distanceX =  currIndex*getWidth() - getScrollX();
//		scroller.startScroll(getScrollX(), 0, distanceX, 0);
		scroller.startScroll(getScrollX(), 0, distanceX, 0, Math.abs(distanceX));
		
//		scrollTo(currIndex*getWidth(), 0);
		//刷新View会导致onDraw方法执行 computeScroll();
		invalidate();
		
		
	}
	
	@Override
	public void computeScroll() {
//		super.computeScroll();
		if(scroller.computeScrollOffset()){
			float X = scroller.getCurrX();
			//根据距离去移动
//			scrollBy((int)distanceX, 0);
			//根据坐标去移动
			scrollTo((int)X, 0);
			invalidate();
			
		}
		
		
	}

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

	// 在布局文件中使用,实例化时候用到它
	public MyScrollView(Context context, AttributeSet attrs) {
		super(context, attrs);
		initView(context);
	}

	// 代码中用到
	public MyScrollView(Context context) {
		super(context);
		initView(context);
	}

}
同时,自定义了MyScroller,实现了页面跳转时的缓慢移动效果。
public class MyScroller {
	
	public MyScroller(Context context){
		
	}
	
	/**
	 * 开始滑动的X轴的起始坐标
	 */
	private float startX;
	/**
	 * 开始滑动的Y轴的起始坐标
	 */
	private float startY;
	/**
	 * 在X轴的移动的距离
	 */
	private float distanceX;
	/**
	 * 在Y轴的移动的距离
	 */
	private float distanceY;
	/**
	 * 开始移动一小段的起始时间
	 */
	private long startTime;
	/**
	 * 是否移动完成
	 * true已经移动完成了
	 * false没有已经完成
	 */
	private boolean isFinish;
	
	/**
	 * 人为指定总共距离的总共时间为500毫秒
	 */
	private long totalTime = 500;
	/**
	 * 移动到那个坐标
	 */
	private float currX;

	/**
	 * 开始滚动或者开始滚动了
	 * 还要计算起始时间和是否已经移动完成了
	 * @param startX
	 * @param startY
	 * @param distanceX
	 * @param distanceY
	 */
	public void startScroll(float startX,float startY,float distanceX,float distanceY){
		this.startX = startX;
		this.startY = startY;
		this.distanceX = distanceX;
		this.distanceY = distanceY;
		//记录开始时间
		this.startTime =SystemClock.uptimeMillis();
		this.isFinish = false;
	}
	
	/**
	 * 计算一小段一小段的距离后的坐标和这一小段花的时间
	 * @return
	 * true正在移动
	 * false已经移动结束
	 */
	public boolean computeScrollOffset(){
		if(isFinish){
			return false;
		}
		//这一小段结束的时间
		long endTime = SystemClock.uptimeMillis();
		//这一小段花的时间
		long passTime = endTime - startTime;
		if(passTime < totalTime){
			//还在移动
			//计算移动的速度(平均速度) = 距离/时间
//			float volecityX = distanceX / totalTime;
			
			this.currX = startX + passTime * distanceX / totalTime;
		}else{
			//不一定了
			this.currX = startX + distanceX;
			isFinish = true;
		}
		
		
		return true;
		
	}

	/**
	 * 得到要移动这一小段的距离
	 * @return
	 */
	public float getCurrX() {
		return currX;
	}

	public void setCurrX(float currX) {
		this.currX = currX;
	}

}
 在activity中,通过RadioButton来控制页面的变化
/**
	 * 图片资源ID
	 */
	private int[] ids = { R.drawable.a1, R.drawable.a2, R.drawable.a3,
			R.drawable.a4, R.drawable.a5, R.drawable.a6 };
	private MyScrollView msv;
	private RadioGroup rg_point_group;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		msv = (MyScrollView) findViewById(R.id.msv);
		rg_point_group = (RadioGroup) findViewById(R.id.rg_point_group);
		
		//添加子者六个页面
		for(int i=0;i 
  
 
 

 

你可能感兴趣的:(android,自定义控件,scrollview,scroller)