自定义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 stubsetBackgroundResource(R.drawable.pic);mScroller = new Scroller(context);detector = new GestureDetector(this);final ViewConfiguration configuration = ViewConfiguration.get(context);// 获得可以认为是滚动的距离mTouchSlop = configuration.getScaledTouchSlop();// 添加子Viewfor (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 stubToast.makeText(mContext, MButton.getText(), Toast.LENGTH_SHORT).show(); }});addView(MButton);}}@Overridepublic void computeScroll() {if (mScroller.computeScrollOffset()) {// 返回当前滚动X方向的偏移scrollTo(0, mScroller.getCurrY());postInvalidate();}}@Overridepublic 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;}@Overridepublic 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 stubreturn 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 stubreturn false;}public void onLongPress(MotionEvent e) {// TODO Auto-generated method stub}@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {// TODO Auto-generated method stubint 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 stubaddView(new MyViewGroup(context));}@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {// TODO Auto-generated method stubfinal 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. */@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(new Workspace(this));}}[img][/img][[/align][/size][size=large]align=center] 3 楼 huangzclovetingzi 2012-03-02 多谢楼主,学习了 4 楼 kaixinyou 2012-06-11 haizige_2009 写道哥们,我想问下你哈,如果是要动态更新GridView ,该怎么做呀?