summaryrefslogtreecommitdiffstats
path: root/core/java/android
diff options
context:
space:
mode:
authorDianne Hackborn <hackbod@google.com>2010-10-18 17:02:43 -0700
committerDianne Hackborn <hackbod@google.com>2010-11-03 19:11:19 -0700
commit079e23575024e103358c982152afb7a720ae1a8a (patch)
treebb87037321dfc3be8fcf7c64737fa0fdca3ceb5c /core/java/android
parent079fd674fb9005771dd383a1a483d7dc5072b5b3 (diff)
downloadframeworks_base-079e23575024e103358c982152afb7a720ae1a8a.zip
frameworks_base-079e23575024e103358c982152afb7a720ae1a8a.tar.gz
frameworks_base-079e23575024e103358c982152afb7a720ae1a8a.tar.bz2
Add new fade in/out feature for drawable containers.
This is used to allow list view's pressed and activated indicators to fade in an out, though of course it can be used elsewhere as well. There is a lot of complexity in supporting this in list view. The two main things that are being dealt with: - When recycling views, we need to make sure that the view's drawable state doesn't get animated from an old row's state. The recycler now keeps track of which position a view was last in, and if it is reused at a new position there is a new View/Drawable API to tell it to jump to its current state instead of animating. - For the pressed indicator to fade out, we need to keep displaying it after it is hidden. There are new variables and code to keep track of this state, and tweaks in various places to be able to remember the last selected position and continue updating the drawable bounds as needed. Change-Id: Ic96aa1a3c05e519665abf3098892ff2cc4f0ef2f
Diffstat (limited to 'core/java/android')
-rw-r--r--core/java/android/util/StateSet.java1
-rw-r--r--core/java/android/view/View.java10
-rw-r--r--core/java/android/widget/AbsListView.java123
-rw-r--r--core/java/android/widget/AdapterView.java1
-rw-r--r--core/java/android/widget/GridView.java13
-rw-r--r--core/java/android/widget/ListView.java29
6 files changed, 128 insertions, 49 deletions
diff --git a/core/java/android/util/StateSet.java b/core/java/android/util/StateSet.java
index f3d8159..21d8e45 100644
--- a/core/java/android/util/StateSet.java
+++ b/core/java/android/util/StateSet.java
@@ -38,6 +38,7 @@ import com.android.internal.R;
public class StateSet {
public static final int[] WILD_CARD = new int[0];
+ public static final int[] NOTHING = new int[] { 0 };
/**
* Return whether the stateSetOrSpec is matched by all StateSets.
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index fd7f4a4..340678d 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -8620,6 +8620,16 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
}
/**
+ * Call {@link Drawable#jumpToCurrentState() Drawable.jumpToCurrentState()}
+ * on all Drawable objects associated with this view.
+ */
+ public void jumpDrawablesToCurrentState() {
+ if (mBGDrawable != null) {
+ mBGDrawable.jumpToCurrentState();
+ }
+ }
+
+ /**
* Sets the background color for this view.
* @param color the color of the background
*/
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 4e90ecd..7629673 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -36,6 +36,7 @@ import android.util.AttributeSet;
import android.util.Log;
import android.util.LongSparseArray;
import android.util.SparseBooleanArray;
+import android.util.StateSet;
import android.view.ActionMode;
import android.view.Gravity;
import android.view.HapticFeedbackConstants;
@@ -254,6 +255,17 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
Drawable mSelector;
/**
+ * Set to true if we would like to have the selector showing itself.
+ * We still need to draw and position it even if this is false.
+ */
+ boolean mSelectorShowing;
+
+ /**
+ * The current position of the selector in the list.
+ */
+ int mSelectorPosition = INVALID_POSITION;
+
+ /**
* Defines the selector's location and dimension at drawing time
*/
Rect mSelectorRect = new Rect();
@@ -1324,6 +1336,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
setSelectedPositionInt(INVALID_POSITION);
// Do this before setting mNeedSync since setNextSelectedPosition looks at mNeedSync
setNextSelectedPositionInt(INVALID_POSITION);
+ mSelectorPosition = INVALID_POSITION;
mNeedSync = true;
mSyncRowId = ss.firstId;
mSyncPosition = ss.position;
@@ -1416,6 +1429,8 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
setSelectedPositionInt(INVALID_POSITION);
setNextSelectedPositionInt(INVALID_POSITION);
mSelectedTop = 0;
+ mSelectorShowing = false;
+ mSelectorPosition = INVALID_POSITION;
mSelectorRect.setEmpty();
invalidate();
}
@@ -1708,7 +1723,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
}
if (child != scrapView) {
- mRecycler.addScrapView(scrapView);
+ mRecycler.addScrapView(scrapView, position);
if (mCacheColorHint != 0) {
child.setDrawingCacheBackgroundColor(mCacheColorHint);
}
@@ -1734,7 +1749,11 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
return child;
}
- void positionSelector(View sel) {
+ void positionSelector(int position, View sel) {
+ if (position != INVALID_POSITION) {
+ mSelectorPosition = position;
+ }
+
final Rect selectorRect = mSelectorRect;
selectorRect.set(sel.getLeft(), sel.getTop(), sel.getRight(), sel.getBottom());
positionSelector(selectorRect.left, selectorRect.top, selectorRect.right,
@@ -1743,7 +1762,9 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
final boolean isChildViewEnabled = mIsChildViewEnabled;
if (sel.isEnabled() != isChildViewEnabled) {
mIsChildViewEnabled = !isChildViewEnabled;
- refreshDrawableState();
+ if (mSelectorShowing) {
+ refreshDrawableState();
+ }
}
}
@@ -1822,7 +1843,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
}
private void drawSelector(Canvas canvas) {
- if (shouldShowSelector() && mSelectorRect != null && !mSelectorRect.isEmpty()) {
+ if (!mSelectorRect.isEmpty()) {
final Drawable selector = mSelector;
selector.setBounds(mSelectorRect);
selector.draw(canvas);
@@ -1866,7 +1887,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
mSelectionRightPadding = padding.right;
mSelectionBottomPadding = padding.bottom;
sel.setCallback(this);
- sel.setState(getDrawableState());
+ updateSelectorState();
}
/**
@@ -1891,7 +1912,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
Drawable selector = mSelector;
Rect selectorRect = mSelectorRect;
if (selector != null && (isFocused() || touchModeDrawsInPressedState())
- && selectorRect != null && !selectorRect.isEmpty()) {
+ && !selectorRect.isEmpty()) {
final View v = getChildAt(mSelectedPosition - mFirstPosition);
@@ -1926,12 +1947,20 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
mScrollDown = down;
}
+ void updateSelectorState() {
+ if (mSelector != null) {
+ if (shouldShowSelector()) {
+ mSelector.setState(getDrawableState());
+ } else {
+ mSelector.setState(StateSet.NOTHING);
+ }
+ }
+ }
+
@Override
protected void drawableStateChanged() {
super.drawableStateChanged();
- if (mSelector != null) {
- mSelector.setState(getDrawableState());
- }
+ updateSelectorState();
}
@Override
@@ -2141,7 +2170,6 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
} else {
mTouchMode = TOUCH_MODE_DONE_WAITING;
}
-
}
}
}
@@ -2316,10 +2344,10 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
mLayoutMode = LAYOUT_NORMAL;
if (!mDataChanged) {
- layoutChildren();
child.setPressed(true);
- positionSelector(child);
setPressed(true);
+ layoutChildren();
+ positionSelector(mMotionPosition, child);
final int longPressTimeout = ViewConfiguration.getLongPressTimeout();
final boolean longClickable = isLongClickable();
@@ -2566,7 +2594,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
setSelectedPositionInt(mMotionPosition);
layoutChildren();
child.setPressed(true);
- positionSelector(child);
+ positionSelector(mMotionPosition, child);
setPressed(true);
if (mSelector != null) {
Drawable d = mSelector.getCurrent();
@@ -2576,16 +2604,17 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
}
postDelayed(new Runnable() {
public void run() {
+ mTouchMode = TOUCH_MODE_REST;
child.setPressed(false);
setPressed(false);
if (!mDataChanged) {
post(performClick);
}
- mTouchMode = TOUCH_MODE_REST;
}
}, ViewConfiguration.getPressedStateDuration());
} else {
mTouchMode = TOUCH_MODE_REST;
+ updateSelectorState();
}
return true;
} else if (!mDataChanged && mAdapter.isEnabled(motionPosition)) {
@@ -2593,6 +2622,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
}
}
mTouchMode = TOUCH_MODE_REST;
+ updateSelectorState();
break;
case TOUCH_MODE_SCROLL:
final int childCount = getChildCount();
@@ -3507,7 +3537,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
count++;
int position = firstPosition + i;
if (position >= headerViewsCount && position < footerViewsStart) {
- mRecycler.addScrapView(child);
+ mRecycler.addScrapView(child, position);
if (ViewDebug.TRACE_RECYCLER) {
ViewDebug.trace(child,
@@ -3528,7 +3558,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
count++;
int position = firstPosition + i;
if (position >= headerViewsCount && position < footerViewsStart) {
- mRecycler.addScrapView(child);
+ mRecycler.addScrapView(child, position);
if (ViewDebug.TRACE_RECYCLER) {
ViewDebug.trace(child,
@@ -3563,8 +3593,15 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
if (!inTouchMode && mSelectedPosition != INVALID_POSITION) {
final int childIndex = mSelectedPosition - mFirstPosition;
if (childIndex >= 0 && childIndex < getChildCount()) {
- positionSelector(getChildAt(childIndex));
+ positionSelector(mSelectedPosition, getChildAt(childIndex));
+ }
+ } else if (mSelectorPosition != INVALID_POSITION) {
+ final int childIndex = mSelectorPosition - mFirstPosition;
+ if (childIndex >= 0 && childIndex < getChildCount()) {
+ positionSelector(INVALID_POSITION, getChildAt(childIndex));
}
+ } else {
+ mSelectorRect.setEmpty();
}
mBlockLayoutRequests = false;
@@ -3616,7 +3653,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
setSelectedPositionInt(INVALID_POSITION);
setNextSelectedPositionInt(INVALID_POSITION);
mSelectedTop = 0;
- mSelectorRect.setEmpty();
+ mSelectorShowing = false;
}
}
@@ -3876,6 +3913,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
mNextSelectedPosition = INVALID_POSITION;
mNextSelectedRowId = INVALID_ROW_ID;
mNeedSync = false;
+ mSelectorPosition = INVALID_POSITION;
checkSelectionChanged();
}
@@ -4562,6 +4600,13 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
@ViewDebug.ExportedProperty(category = "list")
boolean forceAdd;
+ /**
+ * The position the view was removed from when pulled out of the
+ * scrap heap.
+ * @hide
+ */
+ int scrappedFromPosition;
+
public LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
}
@@ -4741,23 +4786,12 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
* @return A view from the ScrapViews collection. These are unordered.
*/
View getScrapView(int position) {
- ArrayList<View> scrapViews;
if (mViewTypeCount == 1) {
- scrapViews = mCurrentScrap;
- int size = scrapViews.size();
- if (size > 0) {
- return scrapViews.remove(size - 1);
- } else {
- return null;
- }
+ return retrieveFromScrap(mCurrentScrap, position);
} else {
int whichScrap = mAdapter.getItemViewType(position);
if (whichScrap >= 0 && whichScrap < mScrapViews.length) {
- scrapViews = mScrapViews[whichScrap];
- int size = scrapViews.size();
- if (size > 0) {
- return scrapViews.remove(size - 1);
- }
+ return retrieveFromScrap(mScrapViews[whichScrap], position);
}
}
return null;
@@ -4768,7 +4802,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
*
* @param scrap The view to add
*/
- void addScrapView(View scrap) {
+ void addScrapView(View scrap, int position) {
AbsListView.LayoutParams lp = (AbsListView.LayoutParams) scrap.getLayoutParams();
if (lp == null) {
return;
@@ -4784,6 +4818,8 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
return;
}
+ lp.scrappedFromPosition = position;
+
if (mViewTypeCount == 1) {
scrap.dispatchStartTemporaryDetach();
mCurrentScrap.add(scrap);
@@ -4810,7 +4846,9 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
for (int i = count - 1; i >= 0; i--) {
final View victim = activeViews[i];
if (victim != null) {
- int whichScrap = ((AbsListView.LayoutParams) victim.getLayoutParams()).viewType;
+ final AbsListView.LayoutParams lp
+ = (AbsListView.LayoutParams) victim.getLayoutParams();
+ int whichScrap = lp.viewType;
activeViews[i] = null;
@@ -4826,6 +4864,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
scrapViews = mScrapViews[whichScrap];
}
victim.dispatchStartTemporaryDetach();
+ lp.scrappedFromPosition = mFirstActivePosition + i;
scrapViews.add(victim);
if (hasListener) {
@@ -4911,4 +4950,22 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
}
}
}
+
+ static View retrieveFromScrap(ArrayList<View> scrapViews, int position) {
+ int size = scrapViews.size();
+ if (size > 0) {
+ // See if we still have a view for this position.
+ for (int i=0; i<size; i++) {
+ View view = scrapViews.get(i);
+ if (((AbsListView.LayoutParams)view.getLayoutParams())
+ .scrappedFromPosition == position) {
+ scrapViews.remove(i);
+ return view;
+ }
+ }
+ return scrapViews.remove(size - 1);
+ } else {
+ return null;
+ }
+ }
}
diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java
index f5afb94..f16efbd 100644
--- a/core/java/android/widget/AdapterView.java
+++ b/core/java/android/widget/AdapterView.java
@@ -18,7 +18,6 @@ package android.widget;
import android.content.Context;
import android.database.DataSetObserver;
-import android.os.Handler;
import android.os.Parcelable;
import android.os.SystemClock;
import android.util.AttributeSet;
diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java
index 46c7d33..936a97d 100644
--- a/core/java/android/widget/GridView.java
+++ b/core/java/android/widget/GridView.java
@@ -1009,7 +1009,7 @@ public class GridView extends AbsListView {
childHeight = child.getMeasuredHeight();
if (mRecycler.shouldRecycleViewType(p.viewType)) {
- mRecycler.addScrapView(child);
+ mRecycler.addScrapView(child, -1);
}
}
@@ -1148,7 +1148,7 @@ public class GridView extends AbsListView {
if (dataChanged) {
for (int i = 0; i < childCount; i++) {
- recycleBin.addScrapView(getChildAt(i));
+ recycleBin.addScrapView(getChildAt(i), firstPosition+i);
}
} else {
recycleBin.fillActiveViews(childCount, firstPosition);
@@ -1215,11 +1215,11 @@ public class GridView extends AbsListView {
recycleBin.scrapActiveViews();
if (sel != null) {
- positionSelector(sel);
+ positionSelector(INVALID_POSITION, sel);
mSelectedTop = sel.getTop();
} else if (mTouchMode > TOUCH_MODE_DOWN && mTouchMode < TOUCH_MODE_SCROLL) {
View child = getChildAt(mMotionPosition - mFirstPosition);
- if (child != null) positionSelector(child);
+ if (child != null) positionSelector(mMotionPosition, child);
} else {
mSelectedTop = 0;
mSelectorRect.setEmpty();
@@ -1391,6 +1391,11 @@ public class GridView extends AbsListView {
if (mCachingStarted) {
child.setDrawingCacheEnabled(true);
}
+
+ if (recycled && (((AbsListView.LayoutParams)child.getLayoutParams()).scrappedFromPosition)
+ != position) {
+ child.jumpDrawablesToCurrentState();
+ }
}
/**
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index b5e103f..e0119e9 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -581,7 +581,7 @@ public class ListView extends AbsListView {
final boolean scroll = scrollYDelta != 0;
if (scroll) {
scrollListItemsBy(-scrollYDelta);
- positionSelector(child);
+ positionSelector(INVALID_POSITION, child);
mSelectedTop = child.getTop();
invalidate();
}
@@ -1086,7 +1086,7 @@ public class ListView extends AbsListView {
if (recycleOnMeasure() && mRecycler.shouldRecycleViewType(
((LayoutParams) child.getLayoutParams()).viewType)) {
- mRecycler.addScrapView(child);
+ mRecycler.addScrapView(child, -1);
}
}
@@ -1203,7 +1203,7 @@ public class ListView extends AbsListView {
// Recycle the view before we possibly return from the method
if (recyle && recycleBin.shouldRecycleViewType(
((LayoutParams) child.getLayoutParams()).viewType)) {
- recycleBin.addScrapView(child);
+ recycleBin.addScrapView(child, -1);
}
returnedHeight += child.getMeasuredHeight();
@@ -1507,7 +1507,7 @@ public class ListView extends AbsListView {
// already cached in mHeaderViews;
if (dataChanged) {
for (int i = 0; i < childCount; i++) {
- recycleBin.addScrapView(getChildAt(i));
+ recycleBin.addScrapView(getChildAt(i), firstPosition+i);
if (ViewDebug.TRACE_RECYCLER) {
ViewDebug.trace(getChildAt(i),
ViewDebug.RecyclerTraceType.MOVE_TO_SCRAP_HEAP, index, i);
@@ -1610,19 +1610,19 @@ public class ListView extends AbsListView {
if (focused != null) {
focused.clearFocus();
}
- positionSelector(sel);
+ positionSelector(INVALID_POSITION, sel);
} else {
sel.setSelected(false);
mSelectorRect.setEmpty();
}
} else {
- positionSelector(sel);
+ positionSelector(INVALID_POSITION, sel);
}
mSelectedTop = sel.getTop();
} else {
if (mTouchMode > TOUCH_MODE_DOWN && mTouchMode < TOUCH_MODE_SCROLL) {
View child = getChildAt(mMotionPosition - mFirstPosition);
- if (child != null) positionSelector(child);
+ if (child != null) positionSelector(mMotionPosition, child);
} else {
mSelectedTop = 0;
mSelectorRect.setEmpty();
@@ -1703,7 +1703,7 @@ public class ListView extends AbsListView {
if (!mDataChanged) {
- // Try to use an exsiting view for this position
+ // Try to use an existing view for this position
child = mRecycler.getActiveView(position);
if (child != null) {
if (ViewDebug.TRACE_RECYCLER) {
@@ -1820,6 +1820,11 @@ public class ListView extends AbsListView {
if (mCachingStarted && !child.isDrawingCacheEnabled()) {
child.setDrawingCacheEnabled(true);
}
+
+ if (recycled && (((AbsListView.LayoutParams)child.getLayoutParams()).scrappedFromPosition)
+ != position) {
+ child.jumpDrawablesToCurrentState();
+ }
}
@Override
@@ -2288,6 +2293,7 @@ public class ListView extends AbsListView {
}
View selectedView = getSelectedView();
+ int selectedPos = mSelectedPosition;
int nextSelectedPosition = lookForSelectablePositionOnScreen(direction);
int amountToScroll = amountToScroll(direction, nextSelectedPosition);
@@ -2305,6 +2311,7 @@ public class ListView extends AbsListView {
setSelectedPositionInt(nextSelectedPosition);
setNextSelectedPositionInt(nextSelectedPosition);
selectedView = getSelectedView();
+ selectedPos = nextSelectedPosition;
if (mItemsCanFocus && focusResult == null) {
// there was no new view found to take focus, make sure we
// don't leave focus with the old selection
@@ -2345,7 +2352,7 @@ public class ListView extends AbsListView {
if (needToRedraw) {
if (selectedView != null) {
- positionSelector(selectedView);
+ positionSelector(selectedPos, selectedView);
mSelectedTop = selectedView.getTop();
}
if (!awakenScrollBars()) {
@@ -2841,7 +2848,7 @@ public class ListView extends AbsListView {
AbsListView.LayoutParams layoutParams = (LayoutParams) first.getLayoutParams();
if (recycleBin.shouldRecycleViewType(layoutParams.viewType)) {
detachViewFromParent(first);
- recycleBin.addScrapView(first);
+ recycleBin.addScrapView(first, mFirstPosition);
} else {
removeViewInLayout(first);
}
@@ -2872,7 +2879,7 @@ public class ListView extends AbsListView {
AbsListView.LayoutParams layoutParams = (LayoutParams) last.getLayoutParams();
if (recycleBin.shouldRecycleViewType(layoutParams.viewType)) {
detachViewFromParent(last);
- recycleBin.addScrapView(last);
+ recycleBin.addScrapView(last, mFirstPosition+lastIndex);
} else {
removeViewInLayout(last);
}