summaryrefslogtreecommitdiffstats
path: root/src/com/android/launcher3/AppDrawerListAdapter.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/launcher3/AppDrawerListAdapter.java')
-rw-r--r--src/com/android/launcher3/AppDrawerListAdapter.java215
1 files changed, 213 insertions, 2 deletions
diff --git a/src/com/android/launcher3/AppDrawerListAdapter.java b/src/com/android/launcher3/AppDrawerListAdapter.java
index a16937308..ea3243534 100644
--- a/src/com/android/launcher3/AppDrawerListAdapter.java
+++ b/src/com/android/launcher3/AppDrawerListAdapter.java
@@ -16,25 +16,29 @@
package com.android.launcher3;
+import android.animation.ValueAnimator;
import android.content.ComponentName;
import android.content.Context;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.provider.Settings;
import android.text.TextUtils;
+import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.support.v7.widget.RecyclerView;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.Interpolator;
import android.widget.LinearLayout;
import android.widget.SectionIndexer;
import com.android.launcher3.locale.LocaleSetManager;
import com.android.launcher3.locale.LocaleUtils;
import com.android.launcher3.settings.SettingsProvider;
-import java.text.Collator;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
@@ -61,6 +65,8 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap
private boolean mHideIconLabels;
+ private ItemAnimatorSet mItemAnimatorSet;
+
public enum DrawerType {
Drawer(0),
Pager(1);
@@ -87,10 +93,173 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap
public static class ViewHolder extends RecyclerView.ViewHolder {
public AutoFitTextView mTextView;
public ViewGroup mLayout;
+ public View mFadingBackground;
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);
+ }
+ }
+
+ /**
+ * This class handles animating the different items when the user scrolls through the drawer
+ * quickly
+ */
+ private class ItemAnimatorSet {
+ private static final long ANIMATION_DURATION = 200;
+ private static final float MAX_SCALE = 2f;
+ private static final float MIN_SCALE = 1f;
+ private static final float FAST_SCROLL = 0.3f;
+
+ private final float YDPI;
+ private final HashSet<ViewHolder> mViewHolderSet;
+ private final Interpolator mInterpolator;
+ private final View.OnLayoutChangeListener mLayoutChangeListener;
+
+ private boolean mDragging;
+ private boolean mExpanding;
+ private boolean mPendingShrink;
+ private long mStartTime;
+ private int mScrollState;
+ private float mFastScrollSpeed;
+ private float mLastScrollSpeed;
+
+ public ItemAnimatorSet(Context ctx) {
+ mDragging = false;
+ mExpanding = false;
+ mPendingShrink = false;
+ mScrollState = RecyclerView.SCROLL_STATE_IDLE;
+ mViewHolderSet = new HashSet<>();
+ mInterpolator = new DecelerateInterpolator();
+ YDPI = ctx.getResources().getDisplayMetrics().ydpi;
+ mLayoutChangeListener = new View.OnLayoutChangeListener() {
+ @Override
+ public void onLayoutChange(View v, int left, int top, int right, int bottom,
+ int oldLeft, int oldTop, int oldRight, int oldBottom) {
+ // set the pivot of the text view
+ v.setPivotX(0);
+ v.setPivotY(v.getMeasuredHeight() / 2);
+ }
+ };
+ }
+
+ public void add(ViewHolder holder) {
+ mViewHolderSet.add(holder);
+ holder.mTextView.addOnLayoutChangeListener(mLayoutChangeListener);
+
+ createAnimationHook(holder);
+ }
+
+ public void remove(ViewHolder holder) {
+ mViewHolderSet.remove(holder);
+ holder.mTextView.removeOnLayoutChangeListener(mLayoutChangeListener);
+ }
+
+ public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
+ if (newState != mScrollState) {
+ mScrollState = newState;
+ mFastScrollSpeed = 0;
+ checkAnimationState();
+ }
+ }
+
+ public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
+ if (mScrollState == RecyclerView.SCROLL_STATE_SETTLING) {
+ mLastScrollSpeed = Math.abs(dy / YDPI);
+ // get the max of the current scroll speed and the previous fastest scroll speed
+ mFastScrollSpeed = Math.max(mFastScrollSpeed, mLastScrollSpeed);
+ checkAnimationState();
+ }
+ }
+
+ public void setDragging(boolean dragging) {
+ mDragging = dragging;
+ checkAnimationState();
+ }
+
+ private void checkAnimationState() {
+ // if the user is dragging or if we're settling at a fast speed, then show animation
+ showAnimation(mDragging ||
+ (mScrollState == RecyclerView.SCROLL_STATE_SETTLING &&
+ mFastScrollSpeed >= FAST_SCROLL));
+ }
+
+ private void showAnimation(boolean expanding) {
+ if (mExpanding != expanding) {
+ // if near the top or bottom and flick to that side of the list, the scroll speed
+ // will hit 0 and the animation will cut straight to shrinking. This code
+ // is here to allow the expand animation to complete in that specific scenario
+ // before shrinking
+ // if the user isn't dragging, the scroll state is idle, the last scroll is fast and
+ // the expand animation is still playing, then mark pending shrink as true
+ if (!mDragging
+ && mScrollState == RecyclerView.SCROLL_STATE_IDLE
+ && mLastScrollSpeed > FAST_SCROLL
+ && System.currentTimeMillis() - mStartTime < ANIMATION_DURATION) {
+ mPendingShrink = true;
+ return;
+ }
+
+ mExpanding = expanding;
+ mPendingShrink = false;
+ mStartTime = System.currentTimeMillis();
+
+ for (ViewHolder holder : mViewHolderSet) {
+ createAnimationHook(holder);
+ }
+ }
+ }
+
+ public void createAnimationHook(ViewHolder holder) {
+ holder.mTextView.animate().cancel();
+ holder.mTextView.animate()
+ .setUpdateListener(new ItemAnimator(holder, mItemAnimatorSet))
+ .setDuration(ANIMATION_DURATION)
+ .start();
+ }
+
+ public void animate(ViewHolder holder, ValueAnimator animation) {
+ long diffTime = System.currentTimeMillis() - mStartTime;
+
+ float percentage = Math.min(diffTime / (float) ANIMATION_DURATION, 1f);
+ percentage = mInterpolator.getInterpolation(percentage);
+
+ if (!mExpanding) {
+ percentage = 1 - percentage;
+ }
+
+ final float targetScale = (MAX_SCALE - MIN_SCALE) * percentage + MIN_SCALE;
+ 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();
+ }
+
+ }
+ }
+ }
+
+ private static class ItemAnimator implements ValueAnimator.AnimatorUpdateListener {
+ private ViewHolder mViewHolder;
+ private ItemAnimatorSet mAnimatorSet;
+
+ public ItemAnimator(final ViewHolder holder, final ItemAnimatorSet animatorSet) {
+ mViewHolder = holder;
+ mAnimatorSet = animatorSet;
+ }
+
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ mAnimatorSet.animate(mViewHolder, animation);
}
}
@@ -101,11 +270,25 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap
mLocaleSetManager = new LocaleSetManager(mLauncher);
mLocaleSetManager.updateLocaleSet(mLocaleSetManager.getSystemLocaleSet());
+ mItemAnimatorSet = new ItemAnimatorSet(launcher);
initParams();
updateProtectedAppsList(mLauncher);
}
+ public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
+ mItemAnimatorSet.onScrollStateChanged(recyclerView, newState);
+ }
+
+ public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
+ mItemAnimatorSet.onScrolled(recyclerView, dx, dy);
+ }
+
+
+ public void setDragging(boolean dragging) {
+ mItemAnimatorSet.setDragging(dragging);
+ }
+
private void initParams() {
mDeviceProfile = LauncherAppState.getInstance().getDynamicGrid().getDeviceProfile();
@@ -347,7 +530,17 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap
View v = LayoutInflater.from(parent.getContext()).
inflate(R.layout.app_drawer_item, parent, false);
ViewHolder holder = new ViewHolder(v);
- holder.mTextView.setPadding(0, 0, 0, mDeviceProfile.iconTextSizePx + 10);
+ ViewGroup.LayoutParams params = holder.mTextView.getLayoutParams();
+
+ // set the margin parameter to account for the text size of the icons so that the text view
+ // is based on the icon size only
+ if (params instanceof ViewGroup.MarginLayoutParams) {
+ ViewGroup.MarginLayoutParams marginParams = (ViewGroup.MarginLayoutParams) params;
+ marginParams.setMargins(marginParams.leftMargin, marginParams.topMargin,
+ marginParams.rightMargin, mDeviceProfile.iconTextSizePx);
+ holder.mTextView.setLayoutParams(marginParams);
+ }
+
for (int i = 0; i < mDeviceProfile.numColumnsBase; i++) {
AppDrawerIconView icon = (AppDrawerIconView) mLayoutInflater.inflate(
R.layout.drawer_icon, holder.mLayout, false);
@@ -359,6 +552,20 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap
}
@Override
+ public void onViewAttachedToWindow(ViewHolder holder) {
+ super.onViewAttachedToWindow(holder);
+
+ mItemAnimatorSet.add(holder);
+ }
+
+ @Override
+ public void onViewDetachedFromWindow(ViewHolder holder) {
+ super.onViewDetachedFromWindow(holder);
+
+ mItemAnimatorSet.remove(holder);
+ }
+
+ @Override
public int getItemCount() {
return mHeaderList.size();
}
@@ -380,6 +587,10 @@ public class AppDrawerListAdapter extends RecyclerView.Adapter<AppDrawerListAdap
holder.mTextView.setText(String.valueOf(indexedInfo.mStartString));
}
}
+
+ holder.mTextView.setPivotX(0);
+ holder.mTextView.setPivotY(holder.mTextView.getHeight() / 2);
+
final int size = indexedInfo.mInfo.size();
for (int i = 0; i < holder.mLayout.getChildCount(); i++) {
AppDrawerIconView icon = (AppDrawerIconView) holder.mLayout.getChildAt(i);