您的位置:首页 > 移动开发 > Android开发

viewgroup 实现类似viewpage效果

2013-08-28 16:17 141 查看
项目用viewpage出现了问题,决定自己用viewpage实现一个类似效果,网上有现成的例子,跑起来之后发现touch事件demo中没做处理,自己把touch事件处理加了上去 ,可能不是最好的方法 但是目前能满足需求。(顺便学习了一下android touch时间传递 )

核心代码就是一个自定义的viewgroup

package com.shixforever.viewgroupdemo;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Scroller;

public class MyScrollLayout extends ViewGroup {

private static final String TAG = "ScrollLayout";
private VelocityTracker mVelocityTracker; // 用于判断甩动手势
private static final int SNAP_VELOCITY = 600; // X轴速度基值,大于该值时进行切换
private Scroller mScroller; // 滑动控制
private int mCurScreen; // 当前页面为第几屏

private int mDefaultScreen = 0;
private float mLastMotionX;
private float lastInterceptX;
private float lastInterceptY;
private OnViewChangeListener mOnViewChangeListener;

public MyScrollLayout(Context context) {
super(context);
init(context);
}

public MyScrollLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}

private void init(Context context) {
mCurScreen = mDefaultScreen;
mScroller = new Scroller(context);
}

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {

Log.e("a", "a");
// if (changed) {
int childLeft = 0;
final int childCount = getChildCount();
Log.e("count", childCount + "");
for (int i = 0; i < childCount; i++) {
final View childView = getChildAt(i);
if (childView.getVisibility() != View.GONE) {
final int childWidth = childView.getMeasuredWidth();
childView.layout(childLeft, 0, childLeft + childWidth,
childView.getMeasuredHeight());
childLeft += childWidth;
}
}
// }
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);

Log.e("b", "b");
final int width = MeasureSpec.getSize(widthMeasureSpec);

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

scrollTo(mCurScreen * width, 0);

}

public void snapToDestination() {
final int screenWidth = getWidth();

final int destScreen = (getScrollX() + screenWidth / 2) / screenWidth;
snapToScreen(destScreen);
}

// 使屏幕移动到第whichScreen+1屏
public void snapToScreen(int whichScreen) {

if (getScrollX() != (whichScreen * getWidth())) {
final int delta = whichScreen * getWidth() - getScrollX();
mScroller.startScroll(getScrollX(), 0, delta, 0,
Math.abs(delta) * 2);
mCurScreen = whichScreen;
invalidate();

if (mOnViewChangeListener != null) {
mOnViewChangeListener.OnViewChange(mCurScreen);
}
}
}

@Override
public void computeScroll() {
if (mScroller.computeScrollOffset()) {
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
postInvalidate();
}
}

@Override
public boolean onTouchEvent(MotionEvent event) {

final int action = event.getAction();
final float x = event.getX();
final float y = event.getY();

switch (action) {
case MotionEvent.ACTION_DOWN:

Log.i("", "onTouchEvent ACTION_DOWN");
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
mVelocityTracker.addMovement(event);
}
if (!mScroller.isFinished()) {
mScroller.abortAnimation();
}
mLastMotionX = x;
break;

case MotionEvent.ACTION_MOVE:

int deltaX = (int) (mLastMotionX - x);
if (IsCanMove(deltaX)) {
if (mVelocityTracker != null) {
mVelocityTracker.addMovement(event);
}
mLastMotionX = x;
// 正向或者负向移动,屏幕跟随手指移动
scrollBy(deltaX, 0);
}
break;

case MotionEvent.ACTION_UP:

int velocityX = 0;
if (mVelocityTracker != null) {
mVelocityTracker.addMovement(event);
mVelocityTracker.computeCurrentVelocity(1000);
// 得到X轴方向手指移动速度
velocityX = (int) mVelocityTracker.getXVelocity();
}
// velocityX为正值说明手指向右滑动,为负值说明手指向左滑动
if (velocityX > SNAP_VELOCITY && mCurScreen > 0) {
// Fling enough to move left
Log.e(TAG, "snap left");
snapToScreen(mCurScreen - 1);
} else if (velocityX < -SNAP_VELOCITY
&& mCurScreen < getChildCount() - 1) {
// Fling enough to move right
Log.e(TAG, "snap right");
snapToScreen(mCurScreen + 1);
} else {
snapToDestination();
}

if (mVelocityTracker != null) {
mVelocityTracker.recycle();
mVelocityTracker = null;
}

break;
}
return true;
}

private boolean IsCanMove(int deltaX) {
// deltaX<0说明手指向右划
if (getScrollX() <= 0 && deltaX < 0) {
return false;
}
// deltaX>0说明手指向左划
if (getScrollX() >= (getChildCount() - 1) * getWidth() && deltaX > 0) {
return false;
}
return true;
}

public void SetOnViewChangeListener(OnViewChangeListener listener) {
mOnViewChangeListener = listener;
}

/**
* 判断touch事件传递
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {

final int action = ev.getAction();
boolean deliver = false;
switch (action) {
case MotionEvent.ACTION_DOWN:

if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
mVelocityTracker.addMovement(ev);
}
if (!mScroller.isFinished()) {
mScroller.abortAnimation();
}
mLastMotionX = ev.getX();
lastInterceptX = ev.getX();
lastInterceptY = ev.getY();
deliver = false;
break;

case MotionEvent.ACTION_MOVE:
float x = ev.getX();
float y = ev.getY();
float dx = x - lastInterceptX;
float dy = y - lastInterceptY;
if (Math.abs(dx) > 5 && Math.abs(dx) - Math.abs(dy) > 0) {

deliver = true;
} else {
deliver = false;
if (mVelocityTracker != null) {
mVelocityTracker.recycle();
mVelocityTracker = null;
}
}
break;

case MotionEvent.ACTION_UP:
lastInterceptX = 0;
lastInterceptY = 0;
break;
}

return deliver;
}

public int getmCurScreen() {
return mCurScreen;
}

public void setmCurScreen(int mCurScreen) {
this.mCurScreen = mCurScreen;
}
}
init方法中初始化一个Scroller
传送门 http://www.cnblogs.com/over140/archive/2010/12/16/1907528.html

http://ipjmc.iteye.com/blog/1615828

在onMeasure()方法中大致计算每个子view的宽高

onLayout()中对childview布局

在onInterceptTouchEvent() 中判断touch事件传递

和touchevent中一样用了VelocityTracker来区别是滑动还是点击

判断依据是x轴位移大于5并且x轴位移大于y轴位移

关于onInterceptTouchEvent()判断方法网上有很多介绍

代码不复杂 大家期待的demo在下面~

· http://download.csdn.net/detail/shix_foot/6027089
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Android交互效果