android Launcher的滑动效果怎么实现?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了android Launcher的滑动效果怎么实现?相关的知识,希望对你有一定的参考价值。

android launcher的滑动效果立方体、叠加、旋转、平移、淡入淡出是怎么实现的?

滑动功能主要分两步:
1、在onInterceptTouchEvent中进行拦截。
2、在onTouchEvent中进行滑动。

1,onInterceptTouchEvent(MotionEvent en)
在这个方法中,决定了什么时候截获MotionEvent来实现滑动,避免了子View的其他事件的影响(如点击事件)。
[java] view plaincopy
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以记录更行速度值。
acquireVelocityTrackerAndAddMovement(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 plaincopy
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;
参考技术A 这个很简单啊,你看过launcher源码吗?在workspace中重写getChildStaticTransformation(View child, Transformation t) 在这个方法里就可以对child做动画了 matrix camera 都能取到 参考技术B android.graphics包下的camera类可用于这类特效

Android实现左右滑动效果

  本示例演示在Android中实现图片左右滑动效果。

 

  关于滑动效果,在Android中用得比较多,本示例实现的滑动效果是使用ViewFlipper来实现的,当然也可以使用其它的View来实现。接下来就让我们开始实现这种效果。为了方便大家理解,我们先来看一下效果图:

 

  主要效果图如下图:

 

    

 

  接下来我们看一下程序结构图:

 

  

 

  MainActivity文件中代码:

复制代码
package com.android.flip;

import android.app.Activity;
import android.os.Bundle;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.GestureDetector.OnGestureListener;
import android.view.animation.AnimationUtils;
import android.widget.ImageView;
import android.widget.ViewFlipper;

/**
 * Android实现左右滑动效果
 * @Description: Android实现左右滑动效果

 * @File: MainActivity.java

 * @Package com.android.flip

 * @Author Hanyonglu

 * @Date 2012-02-12 上午10:44:04

 * @Version V1.0
 */public class MainActivity extends Activity implements OnGestureListener {
    private ViewFlipper flipper;
    private GestureDetector detector;
    
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        detector = new GestureDetector(this);
        flipper = (ViewFlipper) this.findViewById(R.id.ViewFlipper1);

        flipper.addView(addImageView(R.drawable.one));
        flipper.addView(addImageView(R.drawable.two));
        flipper.addView(addImageView(R.drawable.three));
        flipper.addView(addImageView(R.drawable.four));
        flipper.addView(addImageView(R.drawable.five));
    }
    
    private View addImageView(int id) {
        ImageView iv = new ImageView(this);
        iv.setImageResource(id);
        return iv;
    }
    
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // TODO Auto-generated method stubreturn this.detector.onTouchEvent(event);
    }
    
    @Override
    public boolean onDown(MotionEvent e) {
        // TODO Auto-generated method stubreturn false;
    }
    
    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
            float velocityY) {
        if (e1.getX() - e2.getX() > 120) {
            this.flipper.setInAnimation(AnimationUtils.loadAnimation(this, R.anim.push_left_in));
            this.flipper.setOutAnimation(AnimationUtils.loadAnimation(this, R.anim.push_left_out));
            this.flipper.showNext();
            return true;
        } else if (e1.getX() - e2.getX() < -120) {
            this.flipper.setInAnimation(AnimationUtils.loadAnimation(this, R.anim.push_right_in));
            this.flipper.setOutAnimation(AnimationUtils.loadAnimation(this, R.anim.push_right_out));
            this.flipper.showPrevious();
            return true;
        }
        
        return false;
    }
    
    @Override
    public void onLongPress(MotionEvent e) {
        // TODO Auto-generated method stub        
    }
    
    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
            float distanceY) {
        // TODO Auto-generated method stubreturn false;
    }
    
    @Override
    public void onShowPress(MotionEvent e) {
        // TODO Auto-generated method stub        
    }
    
    @Override
    public boolean onSingleTapUp(MotionEvent e) {
        // TODO Auto-generated method stubreturn false;
    }
}
复制代码

 

  布局界面相对比较简单,我们只需要加入ViewFlipper就可以,代码如下: 

复制代码
<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation
="vertical"
    android:layout_width
="fill_parent"
    android:layout_height
="fill_parent"
    
>

    <ViewFlipper android:id="@+id/ViewFlipper1"
        android:layout_width
="fill_parent" 
        android:layout_height
="fill_parent">
    </ViewFlipper>

</LinearLayout> 

复制代码

 

  为了使其滑动时有一定的特效,我们需要加入Animation效果,说到Animation,我们先看下如何在Android中实现自定义Animation。自定义的Animation是以XML格式定义的,定义好的XML文件存放在res/anim中。

 

  一般的Animation有以下四种类型:

  1. Alpha:渐变透明度动画效果

  2. Scale:渐变尺寸伸缩动画效果

  3. Translate:画面转换位置移动动画效果

  4. Rotate:画面转换位置移动动画效果

 

  push_left_in.xml文件中代码:

复制代码
<?xml version="1.0" encoding="utf-8"?>  

<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate android:fromXDelta="100%p" android:toXDelta="0"
        android:duration="500" />
    <alpha android:fromAlpha="0.1" android:toAlpha="1.0"
        android:duration="500" />
</set>

复制代码

 

 

  push_left_out.xml文件中代码: 

复制代码
 <?xml version="1.0" encoding="utf-8"?> 
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate android:fromXDelta="0" android:toXDelta="-100%p"
        android:duration
="500" />
    <alpha android:fromAlpha="1.0" android:toAlpha="0.1"
        android:duration
="500" />

</set>  

复制代码

 

  push_right_in.xml文件中代码:

复制代码
<?xml version="1.0" encoding="utf-8"?> 

<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate android:fromXDelta="-100%p" android:toXDelta="0"
        android:duration="500" />
    <alpha android:fromAlpha="0.1" android:toAlpha="1.0"
        android:duration="500" />
</set>

复制代码

 

   push_right_out.xml文件中代码:

复制代码
<?xml version="1.0" encoding="utf-8"?> 

<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate android:fromXDelta="0" android:toXDelta="100%p"
        android:duration="500" />
    <alpha android:fromAlpha="1.0" android:toAlpha="0.1"
        android:duration="500" />

</set>  

复制代码

 

  如果大家想实现带指引效果的左右滑动,请访问博文:http://www.cnblogs.com/hanyonglu/archive/2012/04/07/2435589.html 

 

  如果想实现带渐显按钮的左右滑动效果,请访问博文:http://www.cnblogs.com/hanyonglu/archive/2012/02/13/2350171.html

 

  下载地址:点击下载

 

  最后,希望转载的朋友能够尊重作者的劳动成果,加上转载地址:http://www.cnblogs.com/hanyonglu/archive/2012/02/13/2349827.html 谢谢。 

  

  结束。^_^






以上是关于android Launcher的滑动效果怎么实现?的主要内容,如果未能解决你的问题,请参考以下文章

android开发中,怎么实现上下滑动,不是ScrollView,我要的是一次滑动整个页面,跟横向滑动效果一样。。

xamarin android开发 怎么实现左,右滑动翻页的效果的

android怎么实现页面的左右滑动

Android QQ 左右滑动菜单弹出效果怎么实现

Android RecyclerView实现横向滑动翻页

Android 左右滑动+上下滑动 怎么实现