summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--res/layout/app_drawer_item.xml11
-rw-r--r--src/com/android/launcher3/AppDrawerListAdapter.java122
-rw-r--r--src/com/android/launcher3/AppDrawerScrubber.java39
3 files changed, 143 insertions, 29 deletions
diff --git a/res/layout/app_drawer_item.xml b/res/layout/app_drawer_item.xml
index cc2ed8f9b..5d3b94655 100644
--- a/res/layout/app_drawer_item.xml
+++ b/res/layout/app_drawer_item.xml
@@ -19,6 +19,15 @@
android:splitMotionEvents="false"
android:layout_width="match_parent"
android:layout_height="wrap_content">
+ <View
+ android:id="@+id/fading_background_back"
+ android:alpha="0"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:layout_alignTop="@+id/drawer_item_flow"
+ android:layout_alignBottom="@+id/drawer_item_flow"
+ android:background="@color/app_drawer_drag_background" />
+
<!-- Layout in back to front render order -->
<LinearLayout
android:id="@+id/drawer_item_flow"
@@ -30,7 +39,7 @@
android:orientation="horizontal" />
<View
- android:id="@+id/fading_background"
+ android:id="@+id/fading_background_front"
android:alpha="0"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
diff --git a/src/com/android/launcher3/AppDrawerListAdapter.java b/src/com/android/launcher3/AppDrawerListAdapter.java
index 5a5e6cb9f..5bbc2ad03 100644
--- a/src/com/android/launcher3/AppDrawerListAdapter.java
+++ b/src/com/android/launcher3/AppDrawerListAdapter.java
@@ -16,6 +16,8 @@
package com.android.launcher3;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.ComponentName;
import android.content.Context;
@@ -51,12 +53,27 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap
private static final String NUMERIC_OR_SPECIAL_HEADER = "#";
+ /**
+ * Tracks both the section index and the positional item index for the sections
+ * section: 0 0 0 1 1 2 3 4 4
+ * itemIndex: 0 1 2 3 4 5 6 7 8
+ * Sections: A A A B B C D E E
+ */
+ private static class SectionIndices {
+ public int mSectionIndex;
+ public int mItemIndex;
+ public SectionIndices(int sectionIndex, int itemIndex) {
+ mSectionIndex = sectionIndex;
+ mItemIndex = itemIndex;
+ }
+ }
+
private ArrayList<AppItemIndexedInfo> mHeaderList;
private LayoutInflater mLayoutInflater;
private Launcher mLauncher;
private DeviceProfile mDeviceProfile;
- private LinkedHashMap<String, Integer> mSectionHeaders;
+ private LinkedHashMap<String, SectionIndices> mSectionHeaders;
private LinearLayout.LayoutParams mIconParams;
private Rect mIconRect;
private LocaleSetManager mLocaleSetManager;
@@ -93,12 +110,14 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap
public static class ViewHolder extends RecyclerView.ViewHolder {
public AutoFitTextView mTextView;
public ViewGroup mLayout;
- public View mFadingBackground;
+ public View mFadingBackgroundFront;
+ public View mFadingBackgroundBack;
public ViewHolder(View itemView) {
super(itemView);
mTextView = (AutoFitTextView) itemView.findViewById(R.id.drawer_item_title);
mLayout = (ViewGroup) itemView.findViewById(R.id.drawer_item_flow);
- mFadingBackground = itemView.findViewById(R.id.fading_background);
+ mFadingBackgroundFront = itemView.findViewById(R.id.fading_background_front);
+ mFadingBackgroundBack = itemView.findViewById(R.id.fading_background_back);
}
}
@@ -111,6 +130,7 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap
private static final float MAX_SCALE = 2f;
private static final float MIN_SCALE = 1f;
private static final float FAST_SCROLL = 0.3f;
+ private static final int NO_SECTION_TARGET = -1;
private final float YDPI;
private final HashSet<ViewHolder> mViewHolderSet;
@@ -125,11 +145,16 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap
private float mFastScrollSpeed;
private float mLastScrollSpeed;
+ // If the user is scrubbing, we want to highlight the target section differently,
+ // so we use this to track where the user is currently scrubbing to
+ private int mSectionTarget;
+
public ItemAnimatorSet(Context ctx) {
mDragging = false;
mExpanding = false;
mPendingShrink = false;
mScrollState = RecyclerView.SCROLL_STATE_IDLE;
+ mSectionTarget = NO_SECTION_TARGET;
mViewHolderSet = new HashSet<>();
mInterpolator = new DecelerateInterpolator();
YDPI = ctx.getResources().getDisplayMetrics().ydpi;
@@ -161,6 +186,12 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap
mScrollState = newState;
mFastScrollSpeed = 0;
checkAnimationState();
+
+ // If the user is dragging, clear the section target
+ if (mScrollState == RecyclerView.SCROLL_STATE_DRAGGING
+ && mSectionTarget != NO_SECTION_TARGET) {
+ setSectionTarget(NO_SECTION_TARGET);
+ }
}
}
@@ -211,18 +242,46 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap
}
}
- public void createAnimationHook(ViewHolder holder) {
+ public void createAnimationHook(final ViewHolder holder) {
holder.mTextView.animate().cancel();
holder.mTextView.animate()
.setUpdateListener(new ItemAnimator(holder, mItemAnimatorSet))
+ .setListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(final Animator animation) {
+ animateEnd(holder, animation);
+ }
+ })
.setDuration(ANIMATION_DURATION)
.start();
}
- public void animate(ViewHolder holder, ValueAnimator animation) {
+ public void animateEnd(ViewHolder holder, Animator animation) {
+ animate(holder, animation, 1f);
+ }
+
+ public void animate(ViewHolder holder, Animator animation) {
long diffTime = System.currentTimeMillis() - mStartTime;
float percentage = Math.min(diffTime / (float) ANIMATION_DURATION, 1f);
+
+ animate(holder, animation, percentage);
+
+ if (diffTime >= ANIMATION_DURATION) {
+ if (animation != null) {
+ animation.cancel();
+ }
+
+ if (mPendingShrink) {
+ mPendingShrink = false;
+ mLastScrollSpeed = 0;
+ checkAnimationState();
+ }
+
+ }
+ }
+
+ public void animate(ViewHolder holder, Animator animation, float percentage) {
percentage = mInterpolator.getInterpolation(percentage);
if (!mExpanding) {
@@ -233,17 +292,24 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap
holder.mTextView.setScaleX(targetScale);
holder.mTextView.setScaleY(targetScale);
- holder.mFadingBackground.setAlpha(percentage);
-
- if (diffTime >= ANIMATION_DURATION) {
- animation.cancel();
-
- if (mPendingShrink) {
- mPendingShrink = false;
- mLastScrollSpeed = 0;
- checkAnimationState();
- }
+ if (getSectionForPosition(holder.getPosition()) == mSectionTarget) {
+ holder.mFadingBackgroundFront.setVisibility(View.INVISIBLE);
+ holder.mFadingBackgroundBack.setAlpha(percentage);
+ holder.mFadingBackgroundBack.setVisibility(View.VISIBLE);
+ } else {
+ holder.mFadingBackgroundFront.setAlpha(percentage);
+ holder.mFadingBackgroundFront.setVisibility(View.VISIBLE);
+ holder.mFadingBackgroundBack.setVisibility(View.INVISIBLE);
+ }
+ }
+ /**
+ * Sets the section index to highlight different from the rest when scrubbing
+ */
+ public void setSectionTarget(int sectionIndex) {
+ mSectionTarget = sectionIndex;
+ for (ViewHolder holder : mViewHolderSet) {
+ animate(holder, null);
}
}
}
@@ -289,6 +355,13 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap
mItemAnimatorSet.setDragging(dragging);
}
+ /**
+ * Sets the section index to highlight different from the rest when scrubbing
+ */
+ public void setSectionTarget(int sectionIndex) {
+ mItemAnimatorSet.setSectionTarget(sectionIndex);
+ }
+
private void initParams() {
mDeviceProfile = LauncherAppState.getInstance().getDynamicGrid().getDeviceProfile();
@@ -380,18 +453,15 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap
private void populateSectionHeaders() {
if (mSectionHeaders == null || mSectionHeaders.size() != mHeaderList.size()) {
- mSectionHeaders = new LinkedHashMap<String, Integer>();
+ mSectionHeaders = new LinkedHashMap<>();
}
- int count = 0;
+
+ int sectionIndex = 0;
for (int i = 0; i < mHeaderList.size(); i++) {
- AppItemIndexedInfo info = mHeaderList.get(i);
if (!mHeaderList.get(i).isChild) {
- mSectionHeaders.put(String.valueOf(mHeaderList.get(i).mStartString), count);
- }
- if (info.mInfo.size() < mDeviceProfile.numColumnsBase) {
- count++;
- } else {
- count += info.mInfo.size() / mDeviceProfile.numColumnsBase;
+ mSectionHeaders.put(String.valueOf(mHeaderList.get(i).mStartString),
+ new SectionIndices(sectionIndex, i));
+ sectionIndex++;
}
}
}
@@ -741,12 +811,12 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap
@Override
public int getPositionForSection(int sectionIndex) {
- return mSectionHeaders.get(getSections()[sectionIndex]);
+ return mSectionHeaders.get(getSections()[sectionIndex]).mItemIndex;
}
@Override
public int getSectionForPosition(int position) {
- return mSectionHeaders.get(mHeaderList.get(position).mStartString);
+ return mSectionHeaders.get(mHeaderList.get(position).mStartString).mSectionIndex;
}
private void filterProtectedApps(ArrayList<AppInfo> list) {
diff --git a/src/com/android/launcher3/AppDrawerScrubber.java b/src/com/android/launcher3/AppDrawerScrubber.java
index 706ddfe96..c65fd373d 100644
--- a/src/com/android/launcher3/AppDrawerScrubber.java
+++ b/src/com/android/launcher3/AppDrawerScrubber.java
@@ -20,9 +20,11 @@ import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.content.Context;
import android.graphics.Color;
+import android.graphics.PointF;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.LinearSmoothScroller;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.LayoutInflater;
@@ -261,8 +263,41 @@ public class AppDrawerScrubber extends LinearLayout {
// get the index of the underlying list
int adapterIndex = mSectionContainer.getAdapterIndex(mLastIndex, index);
- mLayoutManager.smoothScrollToPosition(mListView, null,
- mAdapter.getPositionForSection(adapterIndex));
+ int itemIndex = mAdapter.getPositionForSection(adapterIndex);
+
+ // get any child's height since all children are the same height
+ int itemHeight = 0;
+ View child = mLayoutManager.getChildAt(0);
+ if (child != null) {
+ itemHeight = child.getMeasuredHeight();
+ }
+
+ if (itemHeight != 0) {
+ // scroll to the item such that there are 2 rows beneath it from the bottom
+ final int itemDiff = 2 * itemHeight;
+ LinearSmoothScroller scroller = new LinearSmoothScroller(mListView.getContext()) {
+ @Override
+ protected int getVerticalSnapPreference() {
+ // position the item against the end of the list view
+ return SNAP_TO_END;
+ }
+
+ @Override
+ public PointF computeScrollVectorForPosition(int targetPosition) {
+ return mLayoutManager.computeScrollVectorForPosition(targetPosition);
+ }
+
+ @Override
+ public int calculateDyToMakeVisible(View view, int snapPreference) {
+ int dy = super.calculateDyToMakeVisible(view, snapPreference);
+ return dy - itemDiff;
+ }
+ };
+ scroller.setTargetPosition(itemIndex);
+ mLayoutManager.startSmoothScroll(scroller);
+ }
+
+ mAdapter.setSectionTarget(adapterIndex);
mLastIndex = index;
}