① android Launcher的滑动效果怎么实现
滑动功能主要分两步:
1、在onInterceptTouchEvent中进行拦截。
2、在onTouchEvent中进行滑动。
1,onInterceptTouchEvent(MotionEvent en)
在这个方法中,决定了什么时候截获MotionEvent来实现滑动,避免了子View的其他事件的影响(如点击事件)。
[java] view plain
public boolean onInterceptTouchEvent(MotionEvent ev) {
/**
* This method JUST determines whether we want to intercept the motion.
* If we return true, onTouchEvent will be called and we do the actual
* scrolling there.
**/
//获取速度跟踪器,记录各个时刻的速度。并且添加当前的MotionEvent以记录更行速度值。
(ev);
......
/**
* Shortcut the most recurring case: the user is in the dragging
* state and he is moving his finger. We want to intercept this
* motion.
* 最常见的需要拦截的情况:用户已经进入滑动状态,并且正在滑动手指。
* 对这种情况直接进行拦截,执行onTouchEvent()继续执行滑动操作。
**/
final int action = ev.getAction();
if ((action == MotionEvent.ACTION_MOVE) &&
(mTouchState == TOUCH_STATE_SCROLLING)) {
return true;
}
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_MOVE: {
/**
* mIsBeingDragged == false, otherwise the shortcut would have caught it. Check
* whether the user has moved far enough from his original down touch.
*/
/**
* 当在这里接受到ACTION_MOVE时,说明mTouchState!=TOUCH_STATE_SCROLLING并且mIsBeingDragged的值应该为false,
* 否则DragLayer就应该截获了MotionEvent用于实现拖拽。
* 此时还没有进入滑动状态,当mActivePointerId == INVALID_POINTER时,也就是在此之前没有接收到任何touch事件。
* 这种情况发生在Workspace变小时,也就是之前Workspace处于SPRING_LOADED状态。当出现这种情况时直接把当前的事件当作ACTION_DOWN进行处理。
* 反之,则通过determineScrollingStart()尝试能够进入滑动状态。
*/
if (mActivePointerId != INVALID_POINTER) {
determineScrollingStart(ev);
break;
}
// if mActivePointerId is INVALID_POINTER, then we must have missed an ACTION_DOWN
// event. in that case, treat the first occurence of a move event as a ACTION_DOWN
// i.e. fall through to the next case (don't break)
// (We sometimes miss ACTION_DOWN events in Workspace because it ignores all events
// while it's small- this was causing a crash before we checked for INVALID_POINTER)
}
case MotionEvent.ACTION_DOWN: {
final float x = ev.getX();
final float y = ev.getY();
// Remember location of down touch
//记录按下的x的坐标值
mDownMotionX = x;
//记录前次发生touch时的坐标
mLastMotionX = x;
mLastMotionY = y;
//因为在ScrollBy时只能使用int,而记录的x和y都是float,会产生误差,故这里用mLastMotionXRemainder记录余数
//用于消除误差
mLastMotionXRemainder = 0;
//x方向上的总位移
mTotalMotionX = 0;
mActivePointerId = ev.getPointerId(0);
//设置mAllowLongPress=true,允许LongClick事件发生。LongClick事件定义在Launcher中
//处理的内容包括启动对shortcut的拖拽或弹出壁纸选择的对话框,若mAllowLongPress=false,
//则不会响应以上事件。
mAllowLongPress = true;
/**
* If being flinged and user touches the screen, initiate drag;
* otherwise don't. mScroller.isFinished should be false when
* being flinged.
* 当屏幕处于flinged状态(快速滑动)时,若此时用户触摸了屏幕,需要使滑动停止。
* 并且初始化拖拽的条件
**/
final int xDist = Math.abs(mScroller.getFinalX() - mScroller.getCurrX());
final boolean finishedScrolling = (mScroller.isFinished() || xDist < mTouchSlop);
if (finishedScrolling) {
mTouchState = TOUCH_STATE_REST;
mScroller.abortAnimation();
} else {
mTouchState = TOUCH_STATE_SCROLLING;
}
// check if this can be the beginning of a tap on the side of the pages
// to scroll the current page
if (mTouchState != TOUCH_STATE_PREV_PAGE && mTouchState != TOUCH_STATE_NEXT_PAGE) {
if (getChildCount() > 0) {
if (hitsPreviousPage(x, y)) {
mTouchState = TOUCH_STATE_PREV_PAGE;
} else if (hitsNextPage(x, y)) {
mTouchState = TOUCH_STATE_NEXT_PAGE;
}
}
}
break;
}
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
mTouchState = TOUCH_STATE_REST;
mAllowLongPress = false;
mActivePointerId = INVALID_POINTER;
releaseVelocityTracker();
break;
case MotionEvent.ACTION_POINTER_UP:
onSecondaryPointerUp(ev);
releaseVelocityTracker();
break;
}
/**
* The only time we want to intercept motion events is if we are in the
* drag mode.
* 只有进入了滑动状态,才进行拦截,进入onTouchEvent执行滑动操作。当mTouchState != TOUCH_STATE_REST
* 时,就说明没有进入滑动状态。
**/
return mTouchState != TOUCH_STATE_REST;
}
2,onTouchEvent(MotionEvent en)
在这个方法中,执行各种关于滑动的工作的计算,界面的刷新等工作。
[java] view plain
public boolean onTouchEvent(MotionEvent ev) {
......
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
/*
* If being flinged and user touches, stop the fling. isFinished
* will be false if being flinged.
*/
/**
* 如果Workspace此时已经被“掷出去”(靠惯性滑动)。
* 此时发生ACTION_DOWN则需要停止滑动。
*/
if (!mScroller.isFinished()) {
mScroller.abortAnimation();
}
// Remember where the motion event started
mDownMotionX = mLastMotionX = ev.getX();
mLastMotionXRemainder = 0;
mTotalMotionX = 0;
mActivePointerId = ev.getPointerId(0);
if (mTouchState == TOUCH_STATE_SCROLLING) {
pageBeginMoving();
}
break;
case MotionEvent.ACTION_MOVE:
if (mTouchState == TOUCH_STATE_SCROLLING) {
......
if (Math.abs(deltaX) >= 1.0f) {
......
if (!mDeferScrollUpdate) {
//调用scrollBy滑动桌面
scrollBy((int) deltaX, 0);
......
} else {
......
}
mLastMotionX = x;
mLastMotionXRemainder = deltaX - (int) deltaX;
} else {
awakenScrollBars();
}
} else {
/**
* 如果条件满足,则进入滑动状态,开始滑动。
*/
determineScrollingStart(ev);
}
break;
case MotionEvent.ACTION_UP:
if (mTouchState == TOUCH_STATE_SCROLLING) {
......
boolean isSignificantMove = Math.abs(deltaX) > MIN_LENGTH_FOR_MOVE;
boolean returnToOriginalPage = false;
final int pageWidth = getScaledMeasuredWidth(getPageAt(mCurrentPage));
if (Math.abs(deltaX) > pageWidth * RETURN_TO_ORIGINAL_PAGE_THRESHOLD &&
Math.signum(velocityX) != Math.signum(deltaX)) {
returnToOriginalPage = true;
}
boolean isFling = mTotalMotionX > MIN_LENGTH_FOR_FLING &&
Math.abs(velocityX) > snapVelocity;
int finalPage;
//判断拿起手指之后应该进入哪个分屏
if (((isSignificantMove && deltaX > 0 && !isFling) ||
(isFling && velocityX > 0)) && mCurrentPage > 0) {
finalPage = returnToOriginalPage ? mCurrentPage : mCurrentPage - 1;
snapToPageWithVelocity(finalPage, velocityX);
} else if (((isSignificantMove && deltaX < 0 && !isFling) ||
(isFling && velocityX < 0)) &&
mCurrentPage < getChildCount() - 1) {
finalPage = returnToOriginalPage ? mCurrentPage : mCurrentPage + 1;
snapToPageWithVelocity(finalPage, velocityX);
} else {
snapToDestination();
}
} else if (mTouchState == TOUCH_STATE_PREV_PAGE) {
//直接进入前一屏
int nextPage = Math.max(0, mCurrentPage - 1);
if (nextPage != mCurrentPage) {
snapToPage(nextPage);
} else {
snapToDestination();
}
} else if (mTouchState == TOUCH_STATE_NEXT_PAGE) {
//直接进入后一屏
int nextPage = Math.min(getChildCount() - 1, mCurrentPage + 1);
if (nextPage != mCurrentPage) {
snapToPage(nextPage);
} else {
snapToDestination();
}
} else {
onUnhandledTap(ev);
}
mTouchState = TOUCH_STATE_REST;
mActivePointerId = INVALID_POINTER;
releaseVelocityTracker();
break;
case MotionEvent.ACTION_CANCEL:
if (mTouchState == TOUCH_STATE_SCROLLING) {
snapToDestination();
}
mTouchState = TOUCH_STATE_REST;
mActivePointerId = INVALID_POINTER;
releaseVelocityTracker();
break;
case MotionEvent.ACTION_POINTER_UP:
onSecondaryPointerUp(ev);
break;
}
return true;
}
② android怎么实现滑动效果
工具/原料
ViewFlipper类和OnGestureListener接口
animation动画效果translate和alpha
方法/步骤
1、设置布局文件,其中使用到ViewFlipper控件,内容如下:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/background"
android:paddingBottom="@dimen/activity_optopns_vertical_margin"
android:paddingLeft="@dimen/activity_options_horizontal_margin"
android:paddingRight="@dimen/activity_options_horizontal_margin"
android:paddingTop="@dimen/activity_optopns_vertical_margin"
tools:context=".ImageFlipperActivity" >
<RelativeLayout
android:id="@id/rl_image_flipper_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<Button
android:id="@+id/btn_image_flipper_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_marginBottom="10dp"
android:background="@drawable/custom_button"
android:text="@string/back"
android:textColor="@color/textColor"
android:textSize="16sp"
android:visibility="visible" />
<TextView
android:id="@id/tv_image_flipper_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="@string/image_flipper"
android:textColor="@color/textColor"
android:textSize="30sp"
android:textStyle="bold" />
</RelativeLayout>
<LinearLayout
android:id="@id/ll_image_flipper_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/rl_image_flipper_title"
android:layout_marginBottom="20dp"
android:layout_marginTop="20dp"
android:gravity="center"
android:orientation="vertical" >
<ViewFlipper
android:id="@id/vf_image_flipper"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
</RelativeLayout>
2、从左边进入的动画文件,其内容如下:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >
<!-- translate:画面转换位置移动动画效果 -->
<translate
android:ration="500"
android:fromXDelta="100%p"
android:toXDelta="0" />
<!-- alpha:渐变透明度动画效果 -->
<alpha
android:ration="500"
android:fromAlpha="0.1"
android:toAlpha="1.0" />
</set>
3、从左边退出的动画文件,其内容如下:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >
<translate
android:ration="500"
android:fromXDelta="0"
android:toXDelta="-100%p" />
<alpha
android:ration="500"
android:fromAlpha="1.0"
android:toAlpha="0.1" />
</set>
4、从右边进入的动画文件,其内容如下:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >
<translate
android:ration="500"
android:fromXDelta="-100%p"
android:toXDelta="0" />
<alpha
android:ration="500"
android:fromAlpha="0.1"
android:toAlpha="1.0" />
</set>
5、从右边退出的动画文件,其内容如下:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >
<translate
android:ration="500"
android:fromXDelta="0"
android:toXDelta="100%p" />
<alpha
android:ration="500"
android:fromAlpha="1.0"
android:toAlpha="0.1" />
</set>
6、加载布局文件和动画文件的类,其源码内容为:
/**
*
*/
package com.i114gbox.aglieguy;
import android.content.Context;
import android.os.Bundle;
import android.view.GestureDetector;
import android.view.GestureDetector.OnGestureListener;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.animation.AnimationUtils;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ViewFlipper;
import com.i114gbox.sdk.activity.I114gBoxActivity;
import com.i114gbox.sdk.utils.I114gBoxCollectActivityUtils;
import com.i114gbox.sdk.utils.I114gBoxLogUtils;
import com.i114gbox.sdk.utils.I114gBoxResourceUtils;
/**
* 图片滑动Activity
*
* @author SJC
*
*/
public class ImageFlipperActivity extends I114gBoxActivity implements
OnGestureListener {
private static String TAG = "ImageFlipperActivity";
private Context ctx = null;
private GestureDetector gestureDetector;// 手势监听
private ViewFlipper viewFlipper;// 视图轮播
@Override
protected void onCreate(Bundle savedInstanceState) {
I114gBoxLogUtils.d(TAG, "The onCreate method execute.");
super.onCreate(savedInstanceState);
I114gBoxCollectActivityUtils.getInstance().addActivity(this);// 收集Activity
ctx = this;
setContentView(I114gBoxResourceUtils.getLayoutId(ctx,
"activity_image_flipper"));
gestureDetector = new GestureDetector(this);
viewFlipper = (ViewFlipper) findViewById(I114gBoxResourceUtils.getId(
ctx, "vf_image_flipper"));
viewFlipper.addView(addImageView(I114gBoxResourceUtils.getDrawableId(
ctx, "flipper_01")));
viewFlipper.addView(addImageView(I114gBoxResourceUtils.getDrawableId(
ctx, "flipper_02")));
viewFlipper.addView(addImageView(I114gBoxResourceUtils.getDrawableId(
ctx, "flipper_03")));
viewFlipper.addView(addImageView(I114gBoxResourceUtils.getDrawableId(
ctx, "flipper_04")));
viewFlipper.addView(addImageView(I114gBoxResourceUtils.getDrawableId(
ctx, "flipper_05")));
viewFlipper.addView(addImageView(I114gBoxResourceUtils.getDrawableId(
ctx, "flipper_06")));
// viewFlipper.addView(addImageView(R.drawable.one));
// viewFlipper.addView(addImageView(R.drawable.two));
// viewFlipper.addView(addImageView(R.drawable.three));
// viewFlipper.addView(addImageView(R.drawable.four));
// viewFlipper.addView(addImageView(R.drawable.five));
Button backButton = (Button) findViewById(I114gBoxResourceUtils.getId(
ctx, "btn_image_flipper_back"));
backButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
}
/** 添加ImageView控件 **/
private View addImageView(int id) {
ImageView imageView = new ImageView(this);
imageView.setImageResource(id);
return imageView;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
I114gBoxLogUtils.d(TAG, "The onTouchEvent method execute.");
return gestureDetector.onTouchEvent(event);
}
@Override
public boolean onDown(MotionEvent e) {
I114gBoxLogUtils.d(TAG, "The onDown method execute.");
return false;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
I114gBoxLogUtils.d(TAG, "The onFling method execute.");
I114gBoxLogUtils.i(TAG, "e1.x:" + e1.getX() + "|" + "e2.x:" + e2.getX()
+ "|" + "velocityX:" + velocityX + "|" + "velocityY:"
+ velocityY);
if (e1.getX() - e2.getX() > 120) {
this.viewFlipper.setInAnimation(AnimationUtils.loadAnimation(ctx,
R.anim.push_left_in));// 进入屏幕的动画
this.viewFlipper.setOutAnimation(AnimationUtils.loadAnimation(ctx,
R.anim.push_left_out));// 离开屏幕的动画
this.viewFlipper.showNext();// 手动显示下一个视图
return true;
} else if (e1.getX() - e2.getX() < -120) {
this.viewFlipper.setInAnimation(AnimationUtils.loadAnimation(ctx,
R.anim.push_right_in));
this.viewFlipper.setOutAnimation(AnimationUtils.loadAnimation(ctx,
R.anim.push_right_out));
this.viewFlipper.showPrevious();// 手动显示前一个视图
return true;
}
return false;
}
@Override
public void onLongPress(MotionEvent e) {
I114gBoxLogUtils.d(TAG, "The onLongPress method execute.");
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
float distanceY) {
I114gBoxLogUtils.d(TAG, "The onScroll method execute.");
I114gBoxLogUtils.i(TAG, "e1.X:" + e1.getX() + "|" + "e2.X:" + e2.getX()
+ "|" + "distanceX:" + distanceX + "|" + "distanceY:"
+ distanceY);
return false;
}
@Override
public void onShowPress(MotionEvent e) {
I114gBoxLogUtils.d(TAG, "The onShowPress method execute.");
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
I114gBoxLogUtils.d(TAG, "The onSingleTapUp method execute.");
return false;
}
}
③ android平台中页面切换时如果要用触摸屏左右滑动,怎么实现
左右滑动切换是通过viewPager来实现的,完整代码查看附件。
ViewPager的数据是通过PageAdapter来装载的:
1.调用adapter.notifyDataSetChanged(); 刷新控件,但是要覆盖PagerAdapter的getItemPosition方法,并返回return POSITION_NONE;
2.利用PagerAdapter的工作机制,就是PagerAdapter的执行顺序,PagerAdapter作为ViewPager的适配器,无论ViewPager有多少页,PagerAdapter在初始化时也只初始化开始的2个View,即调用2次instantiateItem方法。而接下来每当ViewPager滑动时,PagerAdapter都会调用destroyItem方法将距离该页2个步幅以上的那个View销毁,以此保证PagerAdapter最多只管辖3个View,且当前View是3个中的中间一个,如果当前View缺少两边的View,那么就instantiateItem,如里有超过2个步幅的就destroyItem。
3.每当Adapter调用instantiateItem时,运用View.setTag方法将该View标识。当需要更新这个View的数据时,通过调用ViewPager.findViewWithTag方法找到相应的View,然后更新View中的数据。
④ android 左右滑屏怎么实现 哪位大神教教我
代码如下:
package kexc.scroll;
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.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.Scroller;
/**
* 仿Launcher中的WorkSapce,可以左右滑动切换屏幕的类
*
*/
public class ScrollLayout extends ViewGroup {
/*
* onMeasure方法在控件的父元素正要放置它的子控件时调用。它会问一个问题,“你想要用多大地方啊?”,然后传入两个参数——
* widthMeasureSpec和heightMeasureSpec。它们指明控件可获得的空间以及关于这个空间描述的元数据。
* 比返回一个结果要好的方法是你传递View的高度和宽度到setMeasuredDimension方法里。
* 一个MeasureSpec包含一个尺寸和模式。
* 有三种可能的模式:
* UNSPECIFIED:父布局没有给子布局任何限制,子布局可以任意大小。
* EXACTLY:父布局决定子布局的确切大小。不论子布局多大,它都必须限制在这个界限里。
* AT_MOST:子布局可以根据自己的大小选择任意大小。
*/
/*
* VelocityTracker类
*
* 功能: 根据触摸位置计算每像素的移动速率。
*
* 常用方法有:
*
* public void addMovement (MotionEvent ev) 功能:添加触摸对象MotionEvent , 用于计算触摸速率。
* public void computeCurrentVelocity (int units)
* 功能:以每像素units单位考核移动速率。额,其实我也不太懂,赋予值1000即可。 参照源码 该units的意思如下: 参数 units :
* The units you would like the velocity in. A value of 1 provides pixels
* per millisecond, 1000 provides pixels per second, etc. public float
* getXVelocity () 功能:获得X轴方向的移动速率。
*/
/*
* ViewConfiguration类
*
* 功能: 获得一些关于timeouts(时间)、sizes(大小)、distances(距离)的标准常量值 。
*
* 常用方法:
*
* public int getScaledEdgeSlop()
*
* 说明:获得一个触摸移动的最小像素值。也就是说,只有超过了这个值,才代表我们该滑屏处理了。
*
* public static int getLongPressTimeout()
*
* 说明:获得一个执行长按事件监听(onLongClickListener)的值。也就是说,对某个View按下触摸时,只有超过了
*
* 这个时间值在,才表示我们该对该View回调长按事件了;否则,小于这个时间点松开手指,只执行onClick监听
*/
private static final String TAG = "ScrollLayout";
private Scroller mScroller;
private VelocityTracker mVelocityTracker;
private int mCurScreen;//当前屏幕
private int mDefaultScreen = 0;
//两种状态: 是否处于滑屏状态
private static final int TOUCH_STATE_REST = 0;//静止状态
private static final int TOUCH_STATE_SCROLLING = 1;//滑屏状态
private static final int SNAP_VELOCITY = 600; //最小的滑动速率
private int mTouchState = TOUCH_STATE_REST;
private int mTouchSlop;// change 多少像素算是发生move操作
private float mLastMotionX;
private float mLastMotionY;
public ScrollLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
// TODO Auto-generated constructor stub
}
public ScrollLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
mScroller = new Scroller(context);
mCurScreen = mDefaultScreen;
//初始化一个最小滑动距离
mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
}
/**
* 生成view
*/
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// TODO Auto-generated method stub
if (changed) {
int childLeft = 0;
final int childCount = getChildCount();
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) {
Log.e(TAG, "onMeasure");
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
final int width = MeasureSpec.getSize(widthMeasureSpec);
final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
if (widthMode != MeasureSpec.EXACTLY) {
throw new IllegalStateException(
"ScrollLayout only canmCurScreen run at EXACTLY mode!");
}
final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
if (heightMode != MeasureSpec.EXACTLY) {
throw new IllegalStateException(
"ScrollLayout only can run at EXACTLY mode!");
}
// The children are given the same width and height as the scrollLayout
final int count = getChildCount();
for (int i = 0; i < count; i++) {
getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec);
}
// Log.e(TAG, "moving to screen "+mCurScreen);
scrollTo(mCurScreen * width, 0);
}
/**
* According to the position of current layout scroll to the destination
* page.
*/
public void snapToDestination() {
// 判断是否超过下一屏的中间位置,如果达到就抵达下一屏,否则保持在原屏幕
// 这样的一个简单公式意思是:假设当前滑屏偏移值即 scrollCurX 加上每个屏幕一半的宽度,除以每个屏幕的宽度就是
// 我们目标屏所在位置了。 假如每个屏幕宽度为320dip, 我们滑到了500dip处,很显然我们应该到达第二屏,索引值为1
// 即(500 + 320/2)/320 = 1
final int screenWidth = getWidth();
final int destScreen = (getScrollX() + screenWidth / 2) / screenWidth;
snapToScreen(destScreen);
}
public void snapToScreen(int whichScreen) {
// get the valid layout page
whichScreen = Math.max(0, Math.min(whichScreen, getChildCount() - 1));
if (getScrollX() != (whichScreen * getWidth())) {
final int delta = whichScreen * getWidth() - getScrollX();
mScroller.startScroll(getScrollX(), 0, delta, 0,
Math.abs(delta) * 5);
mCurScreen = whichScreen;
onScreenChangeListener.onScreenChange(mCurScreen);
invalidate(); // Redraw the layout
}
}
public void setToScreen(int whichScreen) {
whichScreen = Math.max(0, Math.min(whichScreen, getChildCount() - 1));
mCurScreen = whichScreen;
scrollTo(whichScreen * getWidth(), 0);
}
public int getCurScreen() {
return mCurScreen;
}
/**
* 控制view跟随手指滑动 由父视图调用用来请求子视图根据偏移值 mScrollX,mScrollY重新绘制
*/
@Override
public void computeScroll() {
// 如果返回true,表示动画还没有结束
// 因为前面startScroll,所以只有在startScroll完成时 才会为false
if (mScroller.computeScrollOffset()) {
// 产生了动画效果,根据当前值 每次滚动一点
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
postInvalidate();
}
}
/*
* 其中:onInterceptTouchEvent()主要功能是控制触摸事件的分发,例如是子视图的点击事件还是滑动事件。
* 其他所有处理过程均在onTouchEvent()方法里实现了。 1、屏幕的滑动要根据手指的移动而移动 ----
* 主要实现在onTouchEvent()方法中
*