Bug 1090364 - Add fading edge support to TwoWayView (r=mcomella)

This commit is contained in:
Lucas Rocha 2014-10-30 10:26:23 +00:00
Родитель d73e85faba
Коммит ca0c07d45b
1 изменённых файлов: 178 добавлений и 22 удалений

Просмотреть файл

@ -1112,6 +1112,110 @@ public class TwoWayView extends AdapterView<ListAdapter> implements
return INVALID_POSITION; return INVALID_POSITION;
} }
@Override
protected float getTopFadingEdgeStrength() {
if (!mIsVertical) {
return 0f;
}
final float fadingEdge = super.getTopFadingEdgeStrength();
final int childCount = getChildCount();
if (childCount == 0) {
return fadingEdge;
} else {
if (mFirstPosition > 0) {
return 1.0f;
}
final int top = getChildAt(0).getTop();
final int paddingTop = getPaddingTop();
final float length = (float) getVerticalFadingEdgeLength();
return (top < paddingTop ? (float) -(top - paddingTop) / length : fadingEdge);
}
}
@Override
protected float getBottomFadingEdgeStrength() {
if (!mIsVertical) {
return 0f;
}
final float fadingEdge = super.getBottomFadingEdgeStrength();
final int childCount = getChildCount();
if (childCount == 0) {
return fadingEdge;
} else {
if (mFirstPosition + childCount - 1 < mItemCount - 1) {
return 1.0f;
}
final int bottom = getChildAt(childCount - 1).getBottom();
final int paddingBottom = getPaddingBottom();
final int height = getHeight();
final float length = (float) getVerticalFadingEdgeLength();
return (bottom > height - paddingBottom ?
(float) (bottom - height + paddingBottom) / length : fadingEdge);
}
}
@Override
protected float getLeftFadingEdgeStrength() {
if (mIsVertical) {
return 0f;
}
final float fadingEdge = super.getLeftFadingEdgeStrength();
final int childCount = getChildCount();
if (childCount == 0) {
return fadingEdge;
} else {
if (mFirstPosition > 0) {
return 1.0f;
}
final int left = getChildAt(0).getLeft();
final int paddingLeft = getPaddingLeft();
final float length = (float) getHorizontalFadingEdgeLength();
return (left < paddingLeft ? (float) -(left - paddingLeft) / length : fadingEdge);
}
}
@Override
protected float getRightFadingEdgeStrength() {
if (mIsVertical) {
return 0f;
}
final float fadingEdge = super.getRightFadingEdgeStrength();
final int childCount = getChildCount();
if (childCount == 0) {
return fadingEdge;
} else {
if (mFirstPosition + childCount - 1 < mItemCount - 1) {
return 1.0f;
}
final int right = getChildAt(childCount - 1).getRight();
final int paddingRight = getPaddingRight();
final int width = getWidth();
final float length = (float) getHorizontalFadingEdgeLength();
return (right > width - paddingRight ?
(float) (right - width + paddingRight) / length : fadingEdge);
}
}
@Override @Override
protected int computeVerticalScrollExtent() { protected int computeVerticalScrollExtent() {
final int count = getChildCount(); final int count = getChildCount();
@ -1814,7 +1918,7 @@ public class TwoWayView extends AdapterView<ListAdapter> implements
final int position = lookForSelectablePosition(nextPage, forward); final int position = lookForSelectablePosition(nextPage, forward);
if (position >= 0) { if (position >= 0) {
mLayoutMode = LAYOUT_SPECIFIC; mLayoutMode = LAYOUT_SPECIFIC;
mSpecificStart = (mIsVertical ? getPaddingTop() : getPaddingLeft()); mSpecificStart = getStartEdge() + getFadingEdgeLength();
if (forward && position > mItemCount - getChildCount()) { if (forward && position > mItemCount - getChildCount()) {
mLayoutMode = LAYOUT_FORCE_BOTTOM; mLayoutMode = LAYOUT_FORCE_BOTTOM;
@ -2073,7 +2177,9 @@ public class TwoWayView extends AdapterView<ListAdapter> implements
newFocus = FocusFinder.getInstance().findNextFocus(this, oldFocus, direction); newFocus = FocusFinder.getInstance().findNextFocus(this, oldFocus, direction);
} else { } else {
if (direction == View.FOCUS_DOWN || direction == View.FOCUS_RIGHT) { if (direction == View.FOCUS_DOWN || direction == View.FOCUS_RIGHT) {
final int start = getStartEdge(); boolean fadingEdgeShowing = (mFirstPosition > 0);
final int start = getStartEdge() +
(fadingEdgeShowing ? getArrowScrollPreviewLength() : 0);
final int selectedStart; final int selectedStart;
if (selectedView != null) { if (selectedView != null) {
@ -2084,7 +2190,9 @@ public class TwoWayView extends AdapterView<ListAdapter> implements
searchPoint = Math.max(selectedStart, start); searchPoint = Math.max(selectedStart, start);
} else { } else {
final int end = getEndEdge(); final boolean fadingEdgeShowing =
(mFirstPosition + getChildCount() - 1) < mItemCount;
final int end = getEndEdge() - (fadingEdgeShowing ? getArrowScrollPreviewLength() : 0);
final int selectedEnd; final int selectedEnd;
if (selectedView != null) { if (selectedView != null) {
@ -2157,12 +2265,7 @@ public class TwoWayView extends AdapterView<ListAdapter> implements
* @return The amount to preview next items when arrow scrolling. * @return The amount to preview next items when arrow scrolling.
*/ */
private int getArrowScrollPreviewLength() { private int getArrowScrollPreviewLength() {
// FIXME: TwoWayView has no fading edge support just yet but using it return mItemMargin + Math.max(MIN_SCROLL_PREVIEW_PIXELS, getFadingEdgeLength());
// makes it convenient for defining the next item's previous length.
int fadingEdgeLength =
(mIsVertical ? getVerticalFadingEdgeLength() : getHorizontalFadingEdgeLength());
return mItemMargin + Math.max(MIN_SCROLL_PREVIEW_PIXELS, fadingEdgeLength);
} }
/** /**
@ -2958,6 +3061,30 @@ public class TwoWayView extends AdapterView<ListAdapter> implements
return (mIsVertical ? child.getMeasuredHeight() : child.getMeasuredWidth()); return (mIsVertical ? child.getMeasuredHeight() : child.getMeasuredWidth());
} }
private int getFadingEdgeLength() {
return (mIsVertical ? getVerticalFadingEdgeLength() : getHorizontalFadingEdgeLength());
}
private int getMinSelectionPixel(int start, int fadingEdgeLength, int selectedPosition) {
// First pixel we can draw the selection into.
int selectionPixelStart = start;
if (selectedPosition > 0) {
selectionPixelStart += fadingEdgeLength;
}
return selectionPixelStart;
}
private int getMaxSelectionPixel(int end, int fadingEdgeLength,
int selectedPosition) {
int selectionPixelEnd = end;
if (selectedPosition != mItemCount - 1) {
selectionPixelEnd -= fadingEdgeLength;
}
return selectionPixelEnd;
}
private boolean contentFits() { private boolean contentFits() {
final int childCount = getChildCount(); final int childCount = getChildCount();
if (childCount == 0) { if (childCount == 0) {
@ -4191,11 +4318,15 @@ public class TwoWayView extends AdapterView<ListAdapter> implements
private View moveSelection(View oldSelected, View newSelected, int delta, int start, private View moveSelection(View oldSelected, View newSelected, int delta, int start,
int end) { int end) {
final int fadingEdgeLength = getFadingEdgeLength();
final int selectedPosition = mSelectedPosition; final int selectedPosition = mSelectedPosition;
final int oldSelectedStart = getChildStartEdge(oldSelected); final int oldSelectedStart = getChildStartEdge(oldSelected);
final int oldSelectedEnd = getChildEndEdge(oldSelected); final int oldSelectedEnd = getChildEndEdge(oldSelected);
final int minStart = getMinSelectionPixel(start, fadingEdgeLength, selectedPosition);
final int maxEnd = getMaxSelectionPixel(end, fadingEdgeLength, selectedPosition);
View selected = null; View selected = null;
if (delta > 0) { if (delta > 0) {
@ -4233,10 +4364,10 @@ public class TwoWayView extends AdapterView<ListAdapter> implements
// Some of the newly selected item extends below the bottom of the list // Some of the newly selected item extends below the bottom of the list
if (selectedEnd > end) { if (selectedEnd > end) {
// Find space available above the selection into which we can scroll upwards // Find space available above the selection into which we can scroll upwards
final int spaceBefore = selectedStart - start; final int spaceBefore = selectedStart - minStart;
// Find space required to bring the bottom of the selected item fully into view // Find space required to bring the bottom of the selected item fully into view
final int spaceAfter = selectedEnd - end; final int spaceAfter = selectedEnd - maxEnd;
// Don't scroll more than half the size of the list // Don't scroll more than half the size of the list
final int halfSpace = (end - start) / 2; final int halfSpace = (end - start) / 2;
@ -4291,12 +4422,12 @@ public class TwoWayView extends AdapterView<ListAdapter> implements
final int selectedEnd = getChildEndEdge(selected); final int selectedEnd = getChildEndEdge(selected);
// Some of the newly selected item extends above the top of the list // Some of the newly selected item extends above the top of the list
if (selectedStart < start) { if (selectedStart < minStart) {
// Find space required to bring the top of the selected item fully into view // Find space required to bring the top of the selected item fully into view
final int spaceBefore = start - selectedStart; final int spaceBefore = minStart - selectedStart;
// Find space available below the selection into which we can scroll downwards // Find space available below the selection into which we can scroll downwards
final int spaceAfter = end - selectedEnd; final int spaceAfter = maxEnd - selectedEnd;
// Don't scroll more than half the height of the list // Don't scroll more than half the height of the list
final int halfSpace = (end - start) / 2; final int halfSpace = (end - start) / 2;
@ -4515,8 +4646,8 @@ public class TwoWayView extends AdapterView<ListAdapter> implements
int selectedStart = 0; int selectedStart = 0;
int selectedPosition; int selectedPosition;
final int start = getStartEdge(); int start = getStartEdge();
final int end = getEndEdge(); int end = getEndEdge();
final int firstPosition = mFirstPosition; final int firstPosition = mFirstPosition;
final int toPosition = mResurrectToPosition; final int toPosition = mResurrectToPosition;
@ -4527,6 +4658,15 @@ public class TwoWayView extends AdapterView<ListAdapter> implements
final View selected = getChildAt(selectedPosition - mFirstPosition); final View selected = getChildAt(selectedPosition - mFirstPosition);
selectedStart = getChildStartEdge(selected); selectedStart = getChildStartEdge(selected);
final int selectedEnd = getChildEndEdge(selected);
// We are scrolled, don't get in the fade
if (selectedStart < start) {
selectedStart = start + getFadingEdgeLength();
} else if (selectedEnd > end) {
selectedStart = end - getChildMeasuredSize(selected) - getFadingEdgeLength();
}
} else if (toPosition < firstPosition) { } else if (toPosition < firstPosition) {
// Default to selecting whatever is first // Default to selecting whatever is first
selectedPosition = firstPosition; selectedPosition = firstPosition;
@ -4538,6 +4678,13 @@ public class TwoWayView extends AdapterView<ListAdapter> implements
if (i == 0) { if (i == 0) {
// Remember the position of the first item // Remember the position of the first item
selectedStart = childStart; selectedStart = childStart;
// See if we are scrolled at all
if (firstPosition > 0 || childStart < start) {
// If we are scrolled, don't select anything that is
// in the fade region
start += getFadingEdgeLength();
}
} }
if (childStart >= start) { if (childStart >= start) {
@ -4548,6 +4695,7 @@ public class TwoWayView extends AdapterView<ListAdapter> implements
} }
} }
} else { } else {
final int itemCount = mItemCount;
selectedPosition = firstPosition + childCount - 1; selectedPosition = firstPosition + childCount - 1;
down = false; down = false;
@ -4558,6 +4706,10 @@ public class TwoWayView extends AdapterView<ListAdapter> implements
if (i == childCount - 1) { if (i == childCount - 1) {
selectedStart = childStart; selectedStart = childStart;
if (firstPosition + childCount < itemCount || childEnd > end) {
end -= getFadingEdgeLength();
}
} }
if (childEnd <= end) { if (childEnd <= end) {
@ -5093,35 +5245,39 @@ public class TwoWayView extends AdapterView<ListAdapter> implements
} }
private View fillFromSelection(int selectedTop, int start, int end) { private View fillFromSelection(int selectedTop, int start, int end) {
int fadingEdgeLength = getFadingEdgeLength();
final int selectedPosition = mSelectedPosition; final int selectedPosition = mSelectedPosition;
final int minStart = getMinSelectionPixel(start, fadingEdgeLength, selectedPosition);
final int maxEnd = getMaxSelectionPixel(end, fadingEdgeLength, selectedPosition);
View selected = makeAndAddView(selectedPosition, selectedTop, true, true); View selected = makeAndAddView(selectedPosition, selectedTop, true, true);
final int selectedStart = getChildStartEdge(selected); final int selectedStart = getChildStartEdge(selected);
final int selectedEnd = getChildEndEdge(selected); final int selectedEnd = getChildEndEdge(selected);
// Some of the newly selected item extends below the bottom of the list // Some of the newly selected item extends below the bottom of the list
if (selectedEnd > end) { if (selectedEnd > maxEnd) {
// Find space available above the selection into which we can scroll // Find space available above the selection into which we can scroll
// upwards // upwards
final int spaceAbove = selectedStart - start; final int spaceAbove = selectedStart - minStart;
// Find space required to bring the bottom of the selected item // Find space required to bring the bottom of the selected item
// fully into view // fully into view
final int spaceBelow = selectedEnd - end; final int spaceBelow = selectedEnd - maxEnd;
final int offset = Math.min(spaceAbove, spaceBelow); final int offset = Math.min(spaceAbove, spaceBelow);
// Now offset the selected item to get it into view // Now offset the selected item to get it into view
selected.offsetTopAndBottom(-offset); selected.offsetTopAndBottom(-offset);
} else if (selectedStart < start) { } else if (selectedStart < minStart) {
// Find space required to bring the top of the selected item fully // Find space required to bring the top of the selected item fully
// into view // into view
final int spaceAbove = start - selectedStart; final int spaceAbove = minStart - selectedStart;
// Find space available below the selection into which we can scroll // Find space available below the selection into which we can scroll
// downwards // downwards
final int spaceBelow = end - selectedEnd; final int spaceBelow = maxEnd - selectedEnd;
final int offset = Math.min(spaceAbove, spaceBelow); final int offset = Math.min(spaceAbove, spaceBelow);