自定义ViewGroup 实现拖动跟快速滚动的效果

  之前做到个项目要类似listView或者GridView中的控件移动的效果(主屏上所有程序列表上的效果):
1:子控件跟着手指移动
2:快速拨动一下,根据拨动的速度 滑动过去
3:拖过头,放手后弹回去

   但是用listView或者GridView又不好实现项目要求的其他效果..于是继承viewGroup实现以上效果。

   既然要获取拨动速度,并以此滑动。首先想到了OnGestureListener 这个接口,实现这个接口并实现其onFling方法.

  还要控制拖动。重写onTouchEvent方法,并在其中控制内容控件的拖动,反弹等效果

这时候基本已经完成了。。。。测试了一下了,发现了一个问题,当手指点在viewGroup上

进行 拖动是没问题的,但是在子控件上就不行了,这是事件响应的问题 那么还要做如面的处

理:实现onInterceptTouchEvent方法,判断是拖动事件时 ,将事件传递下去。

import java.util.List;
import android.content.Context;
import android.graphics.Color;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.GestureDetector.OnGestureListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Scroller;
import android.widget.Toast;
import android.widget.ImageView.ScaleType;

public class MyViewGroup extends ViewGroup implements OnGestureListener {

	private float mLastMotionY;// 最后点击的点
	private GestureDetector detector;
	int move = 0;// 移动距离
	int MAXMOVE = 850;// 最大允许的移动距离
	private Scroller mScroller;
	int up_excess_move = 0;// 往上多移的距离
	int down_excess_move = 0;// 往下多移的距离
	private final static int TOUCH_STATE_REST = 0;
	private final static int TOUCH_STATE_SCROLLING = 1;
	private int mTouchSlop;
	private int mTouchState = TOUCH_STATE_REST;
	Context mContext;
	

	public MyViewGroup(Context context) {
		super(context);
		mContext = context;
		// TODO Auto-generated constructor stub
		setBackgroundResource(R.drawable.pic);
		mScroller = new Scroller(context);
		detector = new GestureDetector(this);

		final ViewConfiguration configuration = ViewConfiguration.get(context);
		// 获得可以认为是滚动的距离
		mTouchSlop = configuration.getScaledTouchSlop();

		// 添加子View
		for (int i = 0; i < 48; i++) {
			final Button 	MButton = new Button(context);
			MButton.setText("" + (i + 1));
			MButton.setOnClickListener(new OnClickListener() {
				
				public void onClick(View v) {
					// TODO Auto-generated method stub
					Toast.makeText(mContext, MButton.getText(), Toast.LENGTH_SHORT).show(); 
				}
			});
			addView(MButton);
		}
	}

	@Override
	public void computeScroll() {
		if (mScroller.computeScrollOffset()) {
			// 返回当前滚动X方向的偏移
			scrollTo(0, mScroller.getCurrY());
			postInvalidate();
		}
	}

	@Override
	public boolean onInterceptTouchEvent(MotionEvent ev) {
		final int action = ev.getAction();

		final float y = ev.getY();
		switch (ev.getAction())
		{
		case MotionEvent.ACTION_DOWN:

			mLastMotionY = y;
			mTouchState = mScroller.isFinished() ? TOUCH_STATE_REST
					: TOUCH_STATE_SCROLLING;
			break;
		case MotionEvent.ACTION_MOVE:
			final int yDiff = (int) Math.abs(y - mLastMotionY);
			boolean yMoved = yDiff > mTouchSlop;
			// 判断是否是移动
			if (yMoved) {
				mTouchState = TOUCH_STATE_SCROLLING;
			}
			break;
		case MotionEvent.ACTION_UP:
			mTouchState = TOUCH_STATE_REST;
			break;
		}
		return mTouchState != TOUCH_STATE_REST;
	}

	@Override
	public boolean onTouchEvent(MotionEvent ev) {

		// final int action = ev.getAction();

		final float y = ev.getY();
		switch (ev.getAction())
		{
		case MotionEvent.ACTION_DOWN:
			if (!mScroller.isFinished()) {
				mScroller.forceFinished(true);
				move = mScroller.getFinalY();
			}
			mLastMotionY = y;
			break;
		case MotionEvent.ACTION_MOVE:
			if (ev.getPointerCount() == 1) {
				
				// 随手指 拖动的代码
				int deltaY = 0;
				deltaY = (int) (mLastMotionY - y);
				mLastMotionY = y;
				Log.d("move", "" + move);
				if (deltaY < 0) {
					// 下移
					// 判断上移 是否滑过头
					if (up_excess_move == 0) {
						if (move > 0) {
							int move_this = Math.max(-move, deltaY);
							move = move + move_this;
							scrollBy(0, move_this);
						} else if (move == 0) {// 如果已经是最顶端 继续往下拉
							Log.d("down_excess_move", "" + down_excess_move);
							down_excess_move = down_excess_move - deltaY / 2;// 记录下多往下拉的值
							scrollBy(0, deltaY / 2);
						}
					} else if (up_excess_move > 0)// 之前有上移过头
					{					
						if (up_excess_move >= (-deltaY)) {
							up_excess_move = up_excess_move + deltaY;
							scrollBy(0, deltaY);
						} else {						
							up_excess_move = 0;
							scrollBy(0, -up_excess_move);				
						}
					}
				} else if (deltaY > 0) {
					// 上移
					if (down_excess_move == 0) {
						if (MAXMOVE - move > 0) {
							int move_this = Math.min(MAXMOVE - move, deltaY);
							move = move + move_this;
							scrollBy(0, move_this);
						} else if (MAXMOVE - move == 0) {
							if (up_excess_move <= 100) {
								up_excess_move = up_excess_move + deltaY / 2;
								scrollBy(0, deltaY / 2);
							}
						}
					} else if (down_excess_move > 0) {
						if (down_excess_move >= deltaY) {
							down_excess_move = down_excess_move - deltaY;
							scrollBy(0, deltaY);
						} else {
							down_excess_move = 0;
							scrollBy(0, down_excess_move);
						}
					}
				}		
			} 
			break;
		case MotionEvent.ACTION_UP:			
			// 多滚是负数 记录到move里
			if (up_excess_move > 0) {
				// 多滚了 要弹回去
				scrollBy(0, -up_excess_move);
				invalidate();
				up_excess_move = 0;
			}
			if (down_excess_move > 0) {
				// 多滚了 要弹回去
				scrollBy(0, down_excess_move);
				invalidate();
				down_excess_move = 0;
			}
			mTouchState = TOUCH_STATE_REST;
			break;
		}
		return this.detector.onTouchEvent(ev);
	}

	int Fling_move = 0;

	public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
			float velocityY) {
		 //随手指 快速拨动的代码
		Log.d("onFling", "onFling");
		if (up_excess_move == 0 && down_excess_move == 0) {

			int slow = -(int) velocityY * 3 / 4;
			mScroller.fling(0, move, 0, slow, 0, 0, 0, MAXMOVE);
			move = mScroller.getFinalY();
			computeScroll();
		}
		return false;
	}

	public boolean onDown(MotionEvent e) {
		// TODO Auto-generated method stub
		return true;
	}

	public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
			float distanceY) {
		return false;
	}

	public void onShowPress(MotionEvent e) {
		// // TODO Auto-generated method stub
	}

	public boolean onSingleTapUp(MotionEvent e) {
		// TODO Auto-generated method stub
		return false;
	}

	public void onLongPress(MotionEvent e) {
		// TODO Auto-generated method stub
	}

	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		// TODO Auto-generated method stub
		int childTop = 0;
		int childLeft = 0;
		final int count = getChildCount();
		for (int i = 0; i < count; i++) {
			final View child = getChildAt(i);
			if (child.getVisibility() != View.GONE) {
				child.setVisibility(View.VISIBLE);
				child.measure(r - l, b - t);
				child
						.layout(childLeft, childTop, childLeft + 80,
								childTop + 80);
				if (childLeft < 160) {
					childLeft += 80;
				} else {
					childLeft = 0;
					childTop += 80;
				}
			}
		}
	}

}


import android.content.Context;
import android.view.View;
import android.view.ViewGroup;

public class Workspace extends ViewGroup {

	public Workspace(Context context) {
		super(context);
		// TODO Auto-generated constructor stub
		addView(new MyViewGroup(context));
	}

	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		// TODO Auto-generated method stub
		final int count = getChildCount();
		for (int i = 0; i < count; i++) {
			final View child = getChildAt(i);
			child.measure(r - l, b - t);
			child.layout(0, 0, 320, 480);
		}
	}

}


import android.app.Activity;
import android.os.Bundle;

public class MoveViewGroup extends Activity {
	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(new Workspace(this));

	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值