diff options
author | Michael Kolb <kolby@google.com> | 2011-07-22 10:30:49 -0700 |
---|---|---|
committer | Michael Kolb <kolby@google.com> | 2011-07-26 16:51:07 -0700 |
commit | dcd81d37547c3116fd3843894060b6e705d2b1f7 (patch) | |
tree | 4ca88034ec791453b34092607b36e00f0dd25314 /src | |
parent | 31868118c7f2d93fb56c367b7ac46e29c75b1017 (diff) | |
download | packages_apps_Browser-dcd81d37547c3116fd3843894060b6e705d2b1f7.zip packages_apps_Browser-dcd81d37547c3116fd3843894060b6e705d2b1f7.tar.gz packages_apps_Browser-dcd81d37547c3116fd3843894060b6e705d2b1f7.tar.bz2 |
add tab dragging
Bug: 5081671
enable dragging tabs to close them
animations are not correct yet and will be fixed later
Change-Id: Ib0a4ca07706fd73464e307f2061c4246863b9ec8
Diffstat (limited to 'src')
-rw-r--r-- | src/com/android/browser/NavScreen.java | 10 | ||||
-rw-r--r-- | src/com/android/browser/NavTabGallery.java | 90 | ||||
-rw-r--r-- | src/com/android/browser/view/Gallery.java | 99 |
3 files changed, 169 insertions, 30 deletions
diff --git a/src/com/android/browser/NavScreen.java b/src/com/android/browser/NavScreen.java index ee20535..f52ef88 100644 --- a/src/com/android/browser/NavScreen.java +++ b/src/com/android/browser/NavScreen.java @@ -23,8 +23,8 @@ import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.View; -import android.view.ViewConfiguration; import android.view.View.OnClickListener; +import android.view.ViewConfiguration; import android.view.ViewGroup; import android.webkit.WebView; import android.widget.BaseAdapter; @@ -37,6 +37,8 @@ import android.widget.PopupMenu.OnMenuItemClickListener; import android.widget.RelativeLayout; import android.widget.TextView; +import com.android.browser.NavTabGallery.OnRemoveListener; + public class NavScreen extends RelativeLayout implements OnClickListener, OnMenuItemClickListener { @@ -124,6 +126,12 @@ public class NavScreen extends RelativeLayout ? LinearLayout.HORIZONTAL : LinearLayout.VERTICAL); // update state for active tab mScroller.setSelection(mUiController.getTabControl().getTabPosition(mUi.getActiveTab())); + mScroller.setOnRemoveListener(new OnRemoveListener() { + public void onRemovePosition(int pos) { + Tab tab = mAdapter.getItem(pos); + onCloseTab(tab); + } + }); mNeedsMenu = !ViewConfiguration.get(getContext()).hasPermanentMenuKey(); if (!mNeedsMenu) { mMore.setVisibility(View.GONE); diff --git a/src/com/android/browser/NavTabGallery.java b/src/com/android/browser/NavTabGallery.java index 3014eaf..0cd1f82 100644 --- a/src/com/android/browser/NavTabGallery.java +++ b/src/com/android/browser/NavTabGallery.java @@ -16,8 +16,12 @@ package com.android.browser; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ObjectAnimator; import android.content.Context; import android.util.AttributeSet; +import android.view.MotionEvent; import android.view.View; import com.android.browser.view.Gallery; @@ -27,6 +31,16 @@ import com.android.browser.view.Gallery; */ public class NavTabGallery extends Gallery { + interface OnRemoveListener { + public void onRemovePosition(int position); + } + + // after drag animation velocity in pixels/sec + private static final float MIN_VELOCITY = 1500; + + private OnRemoveListener mRemoveListener; + private boolean mBlockUpCallback; + public NavTabGallery(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @@ -39,6 +53,10 @@ public class NavTabGallery extends Gallery { super(context); } + public void setOnRemoveListener(OnRemoveListener l) { + mRemoveListener = l; + } + protected void setSelection(int ix) { super.setSelectedPositionInt(ix); } @@ -55,4 +73,76 @@ public class NavTabGallery extends Gallery { return getSelectedView(); } + @Override + protected void onOrthoDrag(View v, MotionEvent down, MotionEvent move, + float distance) { + offsetView(v, - distance); + } + + @Override + protected void onOrthoFling(View v, MotionEvent down, MotionEvent move, + float velocity) { + if (Math.abs(velocity) > MIN_VELOCITY) { + mBlockUpCallback = true; + animateOut(v, velocity); + } + } + + @Override + protected void onUp(View downView) { + if (mBlockUpCallback) { + mBlockUpCallback = false; + return; + } + if (mIsOrthoDragged && downView != null) { + // offset + int diff = calculateTop(downView, false) - (mHorizontal ? downView.getTop() + : downView.getLeft()); + if (Math.abs(diff) > (mHorizontal ? downView.getHeight() : downView.getWidth()) / 2) { + // remove it + animateOut(downView, - Math.signum(diff) * MIN_VELOCITY); + } else { + // snap back + offsetView(downView, diff); + } + } else { + super.onUp(downView); + } + } + + private void offsetView(View v, float distance) { + if (mHorizontal) { + v.offsetTopAndBottom((int) distance); + } else { + v.offsetLeftAndRight((int) distance); + } + } + + private void animateOut(View v, float velocity) { + final int position = mDownTouchPosition; + int target = 0; + if (velocity < 0) { + target = mHorizontal ? -v.getHeight() : - v.getWidth(); + } else { + target = mHorizontal ? getHeight() : getWidth(); + } + int distance = target - (mHorizontal ? v.getTop() : v.getLeft()); + long duration = (long) (Math.abs(distance) * 1000 / Math.abs(velocity)); + ObjectAnimator animator = null; + if (mHorizontal) { + animator = ObjectAnimator.ofFloat(v, TRANSLATION_Y, 0, target); + } else { + animator = ObjectAnimator.ofFloat(v, TRANSLATION_X, 0, target); + } + animator.setDuration(duration); + animator.addListener(new AnimatorListenerAdapter() { + public void onAnimationEnd(Animator a) { + if (mRemoveListener != null) { + mRemoveListener.onRemovePosition(position); + } + } + }); + animator.start(); + } + } diff --git a/src/com/android/browser/view/Gallery.java b/src/com/android/browser/view/Gallery.java index 0c73537..d9c172e 100644 --- a/src/com/android/browser/view/Gallery.java +++ b/src/com/android/browser/view/Gallery.java @@ -63,7 +63,7 @@ public class Gallery extends ViewGroup implements private RecycleBin mRecycler; - private boolean mHorizontal; + protected boolean mHorizontal; private int mFirstPosition; private int mItemCount; private boolean mDataChanged; @@ -82,8 +82,8 @@ public class Gallery extends ViewGroup implements private GestureDetector mGestureDetector; - private int mDownTouchPosition; - private View mDownTouchView; + protected int mDownTouchPosition; + protected View mDownTouchView; private FlingRunnable mFlingRunnable = new FlingRunnable(); private OnItemSelectedListener mOnItemSelectedListener; @@ -114,12 +114,14 @@ public class Gallery extends ViewGroup implements private boolean mIsFirstScroll; private boolean mIsBeingDragged; + protected boolean mIsOrthoDragged; private int mActivePointerId = INVALID_POINTER; private int mTouchSlop; private float mLastMotionCoord; + private float mLastOrthoCoord; public Gallery(Context context) { this(context, null); @@ -676,7 +678,7 @@ public class Gallery extends ViewGroup implements * This will either be the left or right edge of the view, * depending on the fromLeft paramter * @param fromLeft - * Are we posiitoning views based on the left edge? (i.e., + * Are we positioning views based on the left edge? (i.e., * building from left to right)? * @return A view that has been added to the gallery */ @@ -769,7 +771,7 @@ public class Gallery extends ViewGroup implements * Child to place * @return Where the top of the child should be */ - private int calculateTop(View child, boolean duringLayout) { + protected int calculateTop(View child, boolean duringLayout) { int myHeight = mHorizontal ? (duringLayout ? getMeasuredHeight() : getHeight()) : (duringLayout ? getMeasuredWidth() : getWidth()); @@ -805,6 +807,9 @@ public class Gallery extends ViewGroup implements if ((action == MotionEvent.ACTION_MOVE) && (mIsBeingDragged)) { return true; } + if ((action == MotionEvent.ACTION_MOVE) && (mIsOrthoDragged)) { + return true; + } switch (action & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_MOVE: { /* @@ -821,10 +826,20 @@ public class Gallery extends ViewGroup implements final int pointerIndex = ev.findPointerIndex(activePointerId); final float coord = mHorizontal ? ev.getX(pointerIndex) : ev .getY(pointerIndex); + final int diff = (int) Math.abs(coord - mLastMotionCoord); if (diff > mTouchSlop) { mIsBeingDragged = true; mLastMotionCoord = coord; + } else { + final float ocoord = mHorizontal ? ev.getY(pointerIndex) + : ev.getX(pointerIndex); + if (Math.abs(ocoord - mLastOrthoCoord) > mTouchSlop) { + mIsOrthoDragged = true; + mLastOrthoCoord = ocoord; + } + } + if (mIsBeingDragged || mIsOrthoDragged) { if (mParent != null) mParent.requestDisallowInterceptTouchEvent(true); } @@ -844,6 +859,9 @@ public class Gallery extends ViewGroup implements * flinged. */ mIsBeingDragged = !mFlingRunnable.mScroller.isFinished(); + mIsOrthoDragged = false; + final float ocoord = mHorizontal ? ev.getY() : ev.getX(); + mLastOrthoCoord = ocoord; mGestureDetector.onTouchEvent(ev); break; } @@ -851,20 +869,24 @@ public class Gallery extends ViewGroup implements case MotionEvent.ACTION_UP: /* Release the drag */ mIsBeingDragged = false; + mIsOrthoDragged = false; mActivePointerId = INVALID_POINTER; break; case MotionEvent.ACTION_POINTER_DOWN: { final int index = ev.getActionIndex(); mLastMotionCoord = mHorizontal ? ev.getX(index) : ev.getY(index); + mLastOrthoCoord = mHorizontal ? ev.getY(index) : ev.getX(index); mActivePointerId = ev.getPointerId(index); break; } case MotionEvent.ACTION_POINTER_UP: - mLastMotionCoord = ev.getX(ev.findPointerIndex(mActivePointerId)); + mLastMotionCoord = mHorizontal ? ev.getX(ev.findPointerIndex(mActivePointerId)) + : ev.getY(ev.findPointerIndex(mActivePointerId)); + mLastOrthoCoord = mHorizontal ? ev.getY(ev.findPointerIndex(mActivePointerId)) + : ev.getX(ev.findPointerIndex(mActivePointerId)); break; } - - return mIsBeingDragged; + return mIsBeingDragged || mIsOrthoDragged; } @Override @@ -874,7 +896,7 @@ public class Gallery extends ViewGroup implements int action = event.getAction(); if (action == MotionEvent.ACTION_UP) { // Helper method for lifted finger - onUp(); + onUp(mDownTouchView); } else if (action == MotionEvent.ACTION_CANCEL) { onCancel(); } @@ -902,6 +924,10 @@ public class Gallery extends ViewGroup implements if (!mSuppressSelectionChanged) mSuppressSelectionChanged = true; } + if (isOrthoMove(velocityX, velocityY)) { + onOrthoFling(mDownTouchView, e1, e2, mHorizontal ? velocityY : velocityX); + return true; + } mFlingRunnable.startUsingVelocity(mHorizontal ? (int) -velocityX : (int) -velocityY); return true; @@ -912,30 +938,43 @@ public class Gallery extends ViewGroup implements if (localLOGV) Log.v(TAG, String.valueOf(e2.getX() - e1.getX())); mParent.requestDisallowInterceptTouchEvent(true); - if (!mShouldCallbackDuringFling) { - if (mIsFirstScroll) { - if (!mSuppressSelectionChanged) - mSuppressSelectionChanged = true; - postDelayed(mDisableSuppressSelectionChangedRunnable, - SCROLL_TO_FLING_UNCERTAINTY_TIMEOUT); + if (mIsOrthoDragged && isOrthoMove(distanceX, distanceY)) { + onOrthoDrag(mDownTouchView, e1, e2, mHorizontal ? distanceY : distanceX); + } else if (mIsBeingDragged) { + if (!mShouldCallbackDuringFling) { + if (mIsFirstScroll) { + if (!mSuppressSelectionChanged) { + mSuppressSelectionChanged = true; + } + postDelayed(mDisableSuppressSelectionChangedRunnable, + SCROLL_TO_FLING_UNCERTAINTY_TIMEOUT); + } + } else { + if (mSuppressSelectionChanged) { + mSuppressSelectionChanged = false; + } } - } else { - if (mSuppressSelectionChanged) - mSuppressSelectionChanged = false; - } - trackMotionScroll(mHorizontal ? -1 * (int) distanceX : -1 - * (int) distanceY); + trackMotionScroll(mHorizontal ? -1 * (int) distanceX : -1 + * (int) distanceY); - mIsFirstScroll = false; + mIsFirstScroll = false; + } return true; } + protected void onOrthoDrag(View draggedView, MotionEvent down, + MotionEvent move, float distance) { + } + + protected void onOrthoFling(View draggedView, MotionEvent down, + MotionEvent move, float velocity) { + } + public boolean onDown(MotionEvent e) { mFlingRunnable.stop(false); mDownTouchPosition = pointToPosition((int) e.getX(), (int) e.getY()); if (mDownTouchPosition >= 0) { mDownTouchView = getChildAt(mDownTouchPosition - mFirstPosition); - mDownTouchView.setPressed(true); } // Reset the multiple-scroll tracking state mIsFirstScroll = true; @@ -946,18 +985,23 @@ public class Gallery extends ViewGroup implements /** * Called when a touch event's action is MotionEvent.ACTION_UP. */ - void onUp() { + protected void onUp(View downView) { if (mFlingRunnable.mScroller.isFinished()) { scrollIntoSlots(); } dispatchUnpress(); } + private boolean isOrthoMove(float moveX, float moveY) { + return mHorizontal && Math.abs(moveY) > Math.abs(moveX) + || !mHorizontal && Math.abs(moveX) > Math.abs(moveY); + } + /** * Called when a touch event's action is MotionEvent.ACTION_CANCEL. */ void onCancel() { - onUp(); + onUp(mDownTouchView); } public void onLongPress(MotionEvent e) { @@ -986,9 +1030,6 @@ public class Gallery extends ViewGroup implements @Override protected void dispatchSetPressed(boolean pressed) { - if (mSelectedChild != null) { - mSelectedChild.setPressed(pressed); - } } @Override @@ -1063,7 +1104,7 @@ public class Gallery extends ViewGroup implements long itemId) { } - boolean movePrevious() { + protected boolean movePrevious() { if (mItemCount > 0 && mSelectedPosition > 0) { scrollToChild(mSelectedPosition - mFirstPosition - 1); return true; |