android 桌面滑动,如果写一个android桌面滑动切换屏幕的控件(一)

首先这个控件应该是继承ViewGroup:

初始化:

public class MyGroup extends ViewGroup{

private Scroller mScroller;

private float mOriMotionX;

private float mLastMotionX;

private VelocityTracker mVelocityTracker;

private int mTouchState = TOUCH_STATE_REST;

private static final int TOUCH_STATE_REST = 0;

private int mTouchSlop;

private int mMaximumVelocity;

private static final int TOUCH_STATE_SCROLLING = 1;

private float mLastDownX;

private static final int DEFAULT_VALUE = 1000;

private int mNextScreen = -1;

private boolean mFlagLimitUp = false;

private static final int SNAP_VELOCITY = 700;

private int mCurrentScreen;

public MyGroup(Context context, AttributeSet attrs) {

super(context, attrs);

initWorkspace();

}

private void initWorkspace() {

mScroller = new Scroller(getContext());

setCurrentScreen(0);

final ViewConfiguration configuration = ViewConfiguration

.get(getContext());

mTouchSlop = configuration.getScaledTouchSlop();//这个是定义控件在scroll的最小像素距离

mMaximumVelocity = configuration.getScaledMaximumFlingVelocity(); //速率,fling的一个以每秒滑动多少像素的值

}

先重写onmeasure:

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

final int width = MeasureSpec.getSize(widthMeasureSpec);

final int count = getChildCount();

for (int i = 0; i < count; i++) {

getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec);

}

}

onLayout:

@Override

protected void onLayout(boolean changed, int left, int top, int right, int bottom) {

int paddingleft = 0;

int paddingTop = 0;

int childLeft = paddingleft;

final int count = getChildCount();

for (int i = 0; i < count; i++) {

final View child = getChildAt(i);

if (child.getVisibility() != View.GONE) {

final int childWidth = child.getMeasuredWidth();

final int childHeight = child.getMeasuredHeight() ;

child.layout(childLeft, paddingTop, childLeft + childWidth,

childHeight + paddingTop);

childLeft += child.getMeasuredWidth(); //下个child的左边距和第一个child的左边距之间的距离正好是第一个child的width

}

}

}

然后写View的touch事件:

onInterceptTouchEvent只有返回false事件才会传递给控件里的view,就是view的ontouch事件才可以捕捉

View里的onTouchEvent返回为true,才能执行多次touch事件,事件才能得了传递

@Override

public boolean onInterceptTouchEvent(MotionEvent ev) {

final int action = ev.getAction();

//如果为move事件,mTouchState为TOUCH_STATE_REST为静止状态,这个是防止子控件在滑动时又用手指去滑,这种情况下不响应这个事件

if ((action == MotionEvent.ACTION_MOVE)

&& (mTouchState != TOUCH_STATE_REST)) {

return true;

}

final float x = ev.getX();

switch (action) {

case MotionEvent.ACTION_MOVE:

final int xDiff = (int) Math.abs(x - mLastMotionX);

final int touchSlop = mTouchSlop;

boolean xMoved = xDiff > touchSlop;

//如果xMoved为true表示手指在滑动

if (xMoved) {

mTouchState = TOUCH_STATE_SCROLLING;

}

break;

case MotionEvent.ACTION_DOWN:

mLastMotionX = x;

//mScroller.isFinished() 为true表示滑动结束了,这时候我们把状态置为TOUCH_STATE_REST

mTouchState = mScroller.isFinished() ? TOUCH_STATE_REST

: TOUCH_STATE_SCROLLING;

break;

case MotionEvent.ACTION_CANCEL:

case MotionEvent.ACTION_UP:

mTouchState = TOUCH_STATE_REST;

break;

default:

break;

}

//如果不是在静止状态,都返回true,这样事件就不会传递给onTouchEvent了

return mTouchState != TOUCH_STATE_REST;

}

在滑动的时候返回true的原因是这时候不需要响应里面控件的ontouch事件

@Override

public boolean onTouchEvent(MotionEvent ev) {

if (mVelocityTracker == null) {

mVelocityTracker = VelocityTracker.obtain();

}

mVelocityTracker.addMovement(ev);

int mScrollX = this.getScrollX(); //mScrollX表示X轴上的距离,往左滑动为正,这个时候屏幕向右移动

final int action = ev.getAction();

final float x = ev.getX();

final float y = ev.getY();

switch (action) {

case MotionEvent.ACTION_DOWN:

mOriMotionX = x;

mLastMotionX = x;

if (!mScroller.isFinished()) {

mScroller.abortAnimation();

}

mOriMotionX = x;

mLastMotionX = x;

mLastDownX = x;

return true;

case MotionEvent.ACTION_MOVE:

System.out.println("====action move mScrollX="+mScrollX);

final int buffer = getWidth() / 2; //这个表示在第一页或是最后一页还可以滑动半个屏幕

//如果是往后滑动,屏幕向前,那么mLastMotionX是比x大的,deltaX是正的

int deltaX = (int) (mLastMotionX - x);

mLastMotionX = x;

System.out.println("=====deltaX="+deltaX);

//deltaX<0表示往前滑动

if (deltaX < 0) {

//这个是往右滑动,屏幕向左移动

scrollBy(Math.max(-mScrollX - buffer, deltaX), 0);

}else{

int availableToScroll = 0;

if (getChildCount() > 0) { //此时Workspace上可能未加任何item,count == 0

System.out.println("====rihgt="+(getChildAt(

getChildCount() - 1).getRight())+"avail="+(getChildAt(

getChildCount() - 1).getRight()- mScrollX - getWidth()

));

//getChildAt(getChildCount() - 1).getRight()为所有的view加一起的宽度,这里加了3个view,一个view为1080,则这个值为3240

availableToScroll = getChildAt(

getChildCount() - 1).getRight()

- mScrollX - getWidth();

//availableToScroll + buffer可以滑动的最大距离,deltax为滑动的距离

scrollBy(Math.min(availableToScroll + buffer, deltaX), 0);

}

}

return true;

case MotionEvent.ACTION_UP:

final VelocityTracker velocityTracker = mVelocityTracker;

velocityTracker.computeCurrentVelocity(DEFAULT_VALUE,

mMaximumVelocity);

int velocityX = (int) velocityTracker.getXVelocity();

//velocityX为手指滑动的速率,我们会跟给定值SNAP_VELOCITY做比较

if (velocityX > SNAP_VELOCITY && mCurrentScreen > 0) {

// 这个时候是手指往前滑动,屏幕是向后移动

snapToScreen(mCurrentScreen - 1);

} else if (velocityX < -SNAP_VELOCITY

&& mCurrentScreen < getChildCount() - 1) {

// move right

snapToScreen(mCurrentScreen + 1);

} else {

snapToDestination(mLastMotionX < mOriMotionX);

}

if (mVelocityTracker != null) {

mVelocityTracker.recycle();

mVelocityTracker = null;

}

mTouchState = TOUCH_STATE_REST;

if (Math.abs(mLastDownX - x) > 10) {

return true;

}

return false;

case MotionEvent.ACTION_CANCEL:

mTouchState = TOUCH_STATE_REST;

return false;

default:

break;

}

return true;

}

/**滑动的距离,离屏宽几分之一时,就开始执行换屏动作。*/

/**

* snapToDestination.

* mLastMotionX < mOriMotionX (mLastMotion < mOriMotionX)表示这个是手向后滑动,但屏幕是往前的,反之是向前

* forward为true为往前划动,这时将scrollX加上三分之二的屏幕的宽度

* scrollX / screenWidth 来决定当前在哪个屏幕

* @param forward 是前进还是后退.

*/

public void snapToDestination(boolean forward) {

final int screenWidth = getWidth();

int scrollX = getScrollX();

if (forward) {

scrollX += screenWidth - screenWidth / 3;

} else {

scrollX += screenWidth / 3;

}

System.out.println("======screenWidth="+screenWidth+"scrollX / screenWidth="+(scrollX / screenWidth));

snapToScreen(scrollX / screenWidth);

}

/**

* 如果计算要滑动的距离:(whichScreen * getWidth())为滑动后的X坐标,this.getScrollX()为当前的坐标,两者相减为滑动的距离

* Math.abs(delta) * 2为滑动的持续时间

*/

public void snapToScreen(int whichScreen) {

whichScreen = Math.max(0, Math.min(whichScreen, getChildCount() - 1));

boolean changingScreens = whichScreen != mCurrentScreen;

mNextScreen = whichScreen;

int mScrollX = this.getScrollX();

final int newX = whichScreen * getWidth();

final int delta = newX - mScrollX;

System.out.println("====snapToScreen delta="+delta);

mScroller.startScroll(mScrollX, 0, delta, 0, Math.abs(delta) * 2);

//invalidate非常重要,不然你移动一点页面不能回复原状

invalidate();

}

原文:http://blog.csdn.net/baidu_nod/article/details/38441937

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值