展会信息港展会大全

launcher修改--左右滑动屏幕切换
来源:互联网   发布日期:2015-10-02 16:11:55   浏览:3247次  

导读:在android的源代码中,屏幕之间的跳转是如何实现的呢?在workspace.java中开始。在这个类中,为实现屏幕切换主要重写了以下几个方法:onMeasure()、onLayout()、onInterceptTouchEvent()、onTouchEvent()......

在android的源代码中,屏幕之间的跳转是如何实现的呢?在workspace.java中开始。在这个类中,为实现屏幕切换主要重写了以下几个方法:onMeasure()、onLayout()、onInterceptTouchEvent()、onTouchEvent()方法,另外还是用了CustomScroller mScroller来平滑过渡各个页面之间的切换。

首先,我们看一下onMeasure()方法:

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

final int width = MeasureSpec.getSize(widthMeasureSpec);

final int widthMode = MeasureSpec.getMode(widthMeasureSpec);

if (widthMode != MeasureSpec.EXACTLY) {

throw new IllegalStateException("Workspace can only be used in EXACTLY mode.");

}

final int heightMode = MeasureSpec.getMode(heightMeasureSpec);

if (heightMode != MeasureSpec.EXACTLY) {

throw new IllegalStateException("Workspace can only be used in EXACTLY mode.");

}

// The children are given the same width and height as the workspace

final int count = getChildCount();

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

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

}

//ADW: measure wallpaper when using old rendering

if(!lwpSupport){

if (mWallpaperLoaded) {

mWallpaperLoaded = false;

mWallpaperWidth = mWallpaperDrawable.getIntrinsicWidth();

mWallpaperHeight = mWallpaperDrawable.getIntrinsicHeight();

}

final int wallpaperWidth = mWallpaperWidth;

mWallpaperOffset = wallpaperWidth > width ? (count * width - wallpaperWidth) /

((count - 1) * (float) width) : 1.0f;

}

if (mFirstLayout) {

scrollTo(mCurrentScreen * width, 0);

mScroller.startScroll(0, 0, mCurrentScreen * width, 0, 0);

if(lwpSupport)updateWallpaperOffset(width * (getChildCount() - 1));

mFirstLayout = false;

}

/*int max = 3;

int aW = getMeasuredWidth();

float w = aW / max;

maxPreviewWidth=(int) w;

maxPreviewHeight=(int) (getMeasuredHeight()*(w/getMeasuredWidth()));*/

}

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

final int width = MeasureSpec.getSize(widthMeasureSpec);

final int widthMode = MeasureSpec.getMode(widthMeasureSpec);

if (widthMode != MeasureSpec.EXACTLY) {

throw new IllegalStateException("Workspace can only be used in EXACTLY mode.");

}

final int heightMode = MeasureSpec.getMode(heightMeasureSpec);

if (heightMode != MeasureSpec.EXACTLY) {

throw new IllegalStateException("Workspace can only be used in EXACTLY mode.");

}

// The children are given the same width and height as the workspace

final int count = getChildCount();

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

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

}

//ADW: measure wallpaper when using old rendering

if(!lwpSupport){

if (mWallpaperLoaded) {

mWallpaperLoaded = false;

mWallpaperWidth = mWallpaperDrawable.getIntrinsicWidth();

mWallpaperHeight = mWallpaperDrawable.getIntrinsicHeight();

}

final int wallpaperWidth = mWallpaperWidth;

mWallpaperOffset = wallpaperWidth > width ? (count * width - wallpaperWidth) /

((count - 1) * (float) width) : 1.0f;

}

if (mFirstLayout) {

scrollTo(mCurrentScreen * width, 0);

mScroller.startScroll(0, 0, mCurrentScreen * width, 0, 0);

if(lwpSupport)updateWallpaperOffset(width * (getChildCount() - 1));

mFirstLayout = false;

}

/*int max = 3;

int aW = getMeasuredWidth();

float w = aW / max;

maxPreviewWidth=(int) w;

maxPreviewHeight=(int) (getMeasuredHeight()*(w/getMeasuredWidth()));*/

}

在这里,得到屏幕的宽高, 然后再枚举其中所有的子view,设置它们的布局(使他们的高和父控件一样),这样每一个子view就是充满屏幕可以滑动显示的其中一页。

下面是 onLayout()方法:

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

int childLeft = 0;

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();

child.layout(childLeft, 0, childLeft + childWidth, child.getMeasuredHeight());

childLeft += childWidth;

}

}

//ADW:updateWallpaperoffset

if(lwpSupport){

if(mWallpaperScroll)

updateWallpaperOffset();

else

centerWallpaperOffset();

}

}

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

int childLeft = 0;

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();

child.layout(childLeft, 0, childLeft + childWidth, child.getMeasuredHeight());

childLeft += childWidth;

}

}

//ADW:updateWallpaperoffset

if(lwpSupport){

if(mWallpaperScroll)

updateWallpaperOffset();

else

centerWallpaperOffset();

}

}

onLayout方法中,横向画出每一个子view,view的高与屏幕高一致,宽度为getChildCount()-1个屏幕宽度的view。

再看一下onInterceptTouchEvent()方法:

public boolean onInterceptTouchEvent(MotionEvent ev) {

if(mStatus==SENSE_OPEN){

if(ev.getAction()==MotionEvent.ACTION_DOWN){

findClickedPreview(ev.getX(),ev.getY());

}

return true;

}

//Wysie: If multitouch event is detected

if (multiTouchController.onTouchEvent(ev)) {

return false;

}

if (mLocked || mLauncher.isAllAppsVisible()) {

return true;

}

/*

* 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.

*/

/*

* Shortcut the most recurring case: the user is in the dragging

* state and he is moving his finger. We want to intercept this

* motion.

*/

final int action = ev.getAction();

if ((action == MotionEvent.ACTION_MOVE) && (mTouchState != TOUCH_STATE_REST)) {

return true;

}

final float x = ev.getX();

final float y = ev.getY();

switch (action) {

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.

*/

/*

* Locally do absolute value. mLastMotionX is set to the y value

* of the down event.

*/

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

final int yDiff = (int) Math.abs(y - mLastMotionY);

final int touchSlop = mTouchSlop;

boolean xMoved = xDiff > touchSlop;

boolean yMoved = yDiff > touchSlop;

if (xMoved || yMoved) {

// If xDiff > yDiff means the finger path pitch is smaller than 45deg so we assume the user want to scroll X axis

if (xDiff > yDiff) {

// Scroll if the user moved far enough along the X axis

mTouchState = TOUCH_STATE_SCROLLING;

enableChildrenCache();

}

// If yDiff > xDiff means the finger path pitch is bigger than 45deg so we assume the user want to either scroll Y or Y-axis gesture

else if (getOpenFolder()==null)

{

// As x scrolling is left untouched (more or less untouched;)), every gesture should start by dragging in Y axis. In fact I only consider useful, swipe up and down.

// Guess if the first Pointer where the user click belongs to where a scrollable widget is.

mTouchedScrollableWidget = isWidgetAtLocationScrollable((int)mLastMotionX,(int)mLastMotionY);

if (!mTouchedScrollableWidget)

{

// Only y axis movement. So may be a Swipe down or up gesture

if ((y - mLastMotionY) > 0){

if(Math.abs(y-mLastMotionY)>(touchSlop*2))mTouchState = TOUCH_SWIPE_DOWN_GESTURE;

}else{

if(Math.abs(y-mLastMotionY)>(touchSlop*2))mTouchState = TOUCH_SWIPE_UP_GESTURE;

}

}

}

// Either way, cancel any pending longpress

if (mAllowLongPress) {

mAllowLongPress = false;

// Try canceling the long press. It could also have been scheduled

// by a distant descendant, so use the mAllowLongPress flag to block

// everything

final View currentScreen = getChildAt(mCurrentScreen);

currentScreen.cancelLongPress();

}

}

break;

case MotionEvent.ACTION_DOWN:

// Remember location of down touch

mLastMotionX = x;

mLastMotionY = y;

mAllowLongPress = true;

/*

* If being flinged and user touches the screen, initiate drag;

* otherwise don't. mScroller.isFinished should be false when

* being flinged.

*/

mTouchState = mScroller.isFinished() ? TOUCH_STATE_REST : TOUCH_STATE_SCROLLING;

break;

case MotionEvent.ACTION_CANCEL:

case MotionEvent.ACTION_UP:

if (mTouchState != TOUCH_STATE_SCROLLING && mTouchState != TOUCH_SWIPE_DOWN_GESTURE && mTouchState != TOUCH_SWIPE_UP_GESTURE) {

final CellLayout currentScreen = (CellLayout) getChildAt(mCurrentScreen);

if (!currentScreen.lastDownOnOccupiedCell()) {

getLocationOnScreen(mTempCell);

// Send a tap to the wallpaper if the last down was on empty space

if(lwpSupport)

mWallpaperManager.sendWallpaperCommand(getWindowToken(),

"android.wallpaper.tap",

mTempCell[0] + (int) ev.getX(),

mTempCell[1] + (int) ev.getY(), 0, null);

}

}

// Release the drag

clearChildrenCache();

mTouchState = TOUCH_STATE_REST;

mAllowLongPress = false;

break;

}

/*

* The only time we want to intercept motion events is if we are in the

* drag mode.

*/

return mTouchState != TOUCH_STATE_REST;

}

public boolean onInterceptTouchEvent(MotionEvent ev) {

if(mStatus==SENSE_OPEN){

if(ev.getAction()==MotionEvent.ACTION_DOWN){

findClickedPreview(ev.getX(),ev.getY());

}

return true;

}

//Wysie: If multitouch event is detected

if (multiTouchController.onTouchEvent(ev)) {

return false;

}

if (mLocked || mLauncher.isAllAppsVisible()) {

return true;

}

/*

* 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.

*/

/*

* Shortcut the most recurring case: the user is in the dragging

* state and he is moving his finger.We want to intercept this

* motion.

*/

final int action = ev.getAction();

if ((action == MotionEvent.ACTION_MOVE) && (mTouchState != TOUCH_STATE_REST)) {

return true;

}

final float x = ev.getX();

final float y = ev.getY();

switch (action) {

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.

*/

/*

* Locally do absolute value. mLastMotionX is set to the y value

* of the down event.

*/

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

final int yDiff = (int) Math.abs(y - mLastMotionY);

final int touchSlop = mTouchSlop;

boolean xMoved = xDiff > touchSlop;

boolean yMoved = yDiff > touchSlop;

if (xMoved || yMoved) {

// If xDiff > yDiff means the finger path pitch is smaller than 45deg so we assume the user want to scroll X axis

if (xDiff > yDiff) {

// Scroll if the user moved far enough along the X axis

mTouchState = TOUCH_STATE_SCROLLING;

enableChildrenCache();

}

// If yDiff > xDiff means the finger path pitch is bigger than 45deg so we assume the user want to either scroll Y or Y-axis gesture

else if (getOpenFolder()==null)

{

// As x scrolling is left untouched (more or less untouched;)), every gesture should start by dragging in Y axis. In fact I only consider useful, swipe up and down.

// Guess if the first Pointer where the user click belongs to where a scrollable widget is.

mTouchedScrollableWidget = isWidgetAtLocationScrollable((int)mLastMotionX,(int)mLastMotionY);

if (!mTouchedScrollableWidget)

{

// Only y axis movement. So may be a Swipe down or up gesture

if ((y - mLastMotionY) > 0){

if(Math.abs(y-mLastMotionY)>(touchSlop*2))mTouchState = TOUCH_SWIPE_DOWN_GESTURE;

}else{

if(Math.abs(y-mLastMotionY)>(touchSlop*2))mTouchState = TOUCH_SWIPE_UP_GESTURE;

}

}

}

// Either way, cancel any pending longpress

if (mAllowLongPress) {

mAllowLongPress = false;

// Try canceling the long press. It could also have been scheduled

// by a distant descendant, so use the mAllowLongPress flag to block

// everything

final View currentScreen = getChildAt(mCurrentScreen);

currentScreen.cancelLongPress();

}

}

break;

case MotionEvent.ACTION_DOWN:

// Remember location of down touch

mLastMotionX = x;

mLastMotionY = y;

mAllowLongPress = true;

/*

* If being flinged and user touches the screen, initiate drag;

* otherwise don't.mScroller.isFinished should be false when

* being flinged.

*/

mTouchState = mScroller.isFinished() ? TOUCH_STATE_REST : TOUCH_STATE_SCROLLING;

break;

case MotionEvent.ACTION_CANCEL:

case MotionEvent.ACTION_UP:

if (mTouchState != TOUCH_STATE_SCROLLING && mTouchState != TOUCH_SWIPE_DOWN_GESTURE && mTouchState != TOUCH_SWIPE_UP_GESTURE) {

final CellLayout currentScreen = (CellLayout) getChildAt(mCurrentScreen);

if (!currentScreen.lastDownOnOccupiedCell()) {

getLocationOnScreen(mTempCell);

// Send a tap to the wallpaper if the last down was on empty space

if(lwpSupport)

mWallpaperManager.sendWallpaperCommand(getWindowToken(),

"android.wallpaper.tap",

mTempCell[0] + (int) ev.getX(),

mTempCell[1] + (int) ev.getY(), 0, null);

}

}

// Release the drag

clearChildrenCache();

mTouchState = TOUCH_STATE_REST;

mAllowLongPress = false;

break;

}

/*

* The only time we want to intercept motion events is if we are in the

* drag mode.

*/

return mTouchState != TOUCH_STATE_REST;

}

onInterceptTouchEvent()方法和下面的onTouchEvent()主要是来响应手指按下划动时所需要捕获的消息,例如划动的速度,划动的距离等。再配合使用scrollBy (int x, int y)方法得到慢速滑动小距离的时候,所需要显示的内容。最后当手指起来时,根据划动的速度与跨度来判断是向左滑动一页还是向右滑动一页,确保每次用户操作结束之后显示的都是整体的一个子view.

public boolean onTouchEvent(MotionEvent ev) {

//Wysie: If multitouch event is detected

/*if (multiTouchController.onTouchEvent(ev)) {

return false;

}*/

if (mLocked || mLauncher.isAllAppsVisible() || mSensemode) {

return true;

}

if (mVelocityTracker == null) {

mVelocityTracker = VelocityTracker.obtain();

}

mVelocityTracker.addMovement(ev);

final int action = ev.getAction();

final float x = ev.getX();

switch (action) {

case MotionEvent.ACTION_DOWN:

/*

* If being flinged and user touches, stop the fling. isFinished

* will be false if being flinged.

*/

if (!mScroller.isFinished()) {

mScroller.abortAnimation();

}

// Remember where the motion event started

mLastMotionX = x;

break;

case MotionEvent.ACTION_MOVE:

if (mTouchState == TOUCH_STATE_SCROLLING) {

// Scroll to follow the motion event

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

mLastMotionX = x;

if (deltaX < 0) {

if (mScrollX > -mScrollingBounce) {

scrollBy(Math.min(deltaX,mScrollingBounce), 0);

if(lwpSupport)updateWallpaperOffset();

if(mLauncher.getDesktopIndicator()!=null)mLauncher.getDesktopIndicator().indicate((float)getScrollX()/(float)(getChildCount()*getWidth()));

}

} else if (deltaX > 0) {

final int availableToScroll = getChildAt(getChildCount() - 1).getRight() -

mScrollX - getWidth()+mScrollingBounce;

if (availableToScroll > 0) {

scrollBy(deltaX, 0);

if(lwpSupport)updateWallpaperOffset();

if(mLauncher.getDesktopIndicator()!=null)mLauncher.getDesktopIndicator().indicate((float)getScrollX()/(float)(getChildCount()*getWidth()));

}

}

}

break;

case MotionEvent.ACTION_UP:

if (mTouchState == TOUCH_STATE_SCROLLING) {

final VelocityTracker velocityTracker = mVelocityTracker;

velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);

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

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

// Fling hard enough to move left

snapToScreen(mCurrentScreen - 1);

} else if (velocityX < -SNAP_VELOCITY && mCurrentScreen < getChildCount() - 1) {

// Fling hard enough to move right

snapToScreen(mCurrentScreen + 1);

} else {

snapToDestination();

}

if (mVelocityTracker != null) {

mVelocityTracker.recycle();

mVelocityTracker = null;

}

} else if (mTouchState == TOUCH_SWIPE_DOWN_GESTURE )

{

mLauncher.fireSwipeDownAction();

} else if (mTouchState == TOUCH_SWIPE_UP_GESTURE )

{

mLauncher.fireSwipeUpAction();

}

mTouchState = TOUCH_STATE_REST;

break;

case MotionEvent.ACTION_CANCEL:

mTouchState = TOUCH_STATE_REST;

}

return true;

}

public boolean onTouchEvent(MotionEvent ev) {

//Wysie: If multitouch event is detected

/*if (multiTouchController.onTouchEvent(ev)) {

return false;

}*/

if (mLocked || mLauncher.isAllAppsVisible() || mSensemode) {

return true;

}

if (mVelocityTracker == null) {

mVelocityTracker = VelocityTracker.obtain();

}

mVelocityTracker.addMovement(ev);

final int action = ev.getAction();

final float x = ev.getX();

switch (action) {

case MotionEvent.ACTION_DOWN:

/*

* If being flinged and user touches, stop the fling. isFinished

* will be false if being flinged.

*/

if (!mScroller.isFinished()) {

mScroller.abortAnimation();

}

// Remember where the motion event started

mLastMotionX = x;

break;

case MotionEvent.ACTION_MOVE:

if (mTouchState == TOUCH_STATE_SCROLLING) {

// Scroll to follow the motion event

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

mLastMotionX = x;

if (deltaX < 0) {

if (mScrollX > -mScrollingBounce) {

scrollBy(Math.min(deltaX,mScrollingBounce), 0);

if(lwpSupport)updateWallpaperOffset();

if(mLauncher.getDesktopIndicator()!=null)mLauncher.getDesktopIndicator().indicate((float)getScrollX()/(float)(getChildCount()*getWidth()));

}

} else if (deltaX > 0) {

final int availableToScroll = getChildAt(getChildCount() - 1).getRight() -

mScrollX - getWidth()+mScrollingBounce;

if (availableToScroll > 0) {

scrollBy(deltaX, 0);

if(lwpSupport)updateWallpaperOffset();

if(mLauncher.getDesktopIndicator()!=null)mLauncher.getDesktopIndicator().indicate((float)getScrollX()/(float)(getChildCount()*getWidth()));

}

}

}

break;

case MotionEvent.ACTION_UP:

if (mTouchState == TOUCH_STATE_SCROLLING) {

final VelocityTracker velocityTracker = mVelocityTracker;

velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);

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

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

// Fling hard enough to move left

snapToScreen(mCurrentScreen - 1);

} else if (velocityX < -SNAP_VELOCITY && mCurrentScreen < getChildCount() - 1) {

// Fling hard enough to move right

snapToScreen(mCurrentScreen + 1);

} else {

snapToDestination();

}

if (mVelocityTracker != null) {

mVelocityTracker.recycle();

mVelocityTracker = null;

}

} else if (mTouchState == TOUCH_SWIPE_DOWN_GESTURE )

{

mLauncher.fireSwipeDownAction();

} else if (mTouchState == TOUCH_SWIPE_UP_GESTURE )

{

mLauncher.fireSwipeUpAction();

}

mTouchState = TOUCH_STATE_REST;

break;

case MotionEvent.ACTION_CANCEL:

mTouchState = TOUCH_STATE_REST;

}

return true;

}

以上就是launcher中左右滑动屏幕切换源码。

赞助本站

人工智能实验室
AiLab云推荐
展开

热门栏目HotCates

Copyright © 2010-2024 AiLab Team. 人工智能实验室 版权所有    关于我们 | 联系我们 | 广告服务 | 公司动态 | 免责声明 | 隐私条款 | 工作机会 | 展会港