From 36f745ed8c21c4bbb05cf99ed9f0b4fd1c8d448d Mon Sep 17 00:00:00 2001 From: Andy Mast Date: Wed, 9 Jul 2014 14:37:24 -0700 Subject: Theme component cards Change-Id: I31b3102a6b578974a6b0f11116dce052c83bce73 --- .../theme/chooserv2/ChooserActivity.java | 21 ++- .../theme/chooserv2/ComponentCardView.java | 90 +++++++++++++ .../theme/chooserv2/PagerContainer.java | 24 +++- .../cyanogenmod/theme/chooserv2/ThemeFragment.java | 146 ++++++++++++++------- 4 files changed, 222 insertions(+), 59 deletions(-) create mode 100644 src/org/cyanogenmod/theme/chooserv2/ComponentCardView.java (limited to 'src') diff --git a/src/org/cyanogenmod/theme/chooserv2/ChooserActivity.java b/src/org/cyanogenmod/theme/chooserv2/ChooserActivity.java index ee60286..05aa1ae 100644 --- a/src/org/cyanogenmod/theme/chooserv2/ChooserActivity.java +++ b/src/org/cyanogenmod/theme/chooserv2/ChooserActivity.java @@ -82,7 +82,7 @@ public class ChooserActivity extends FragmentActivity DisplayMetrics dm = getResources().getDisplayMetrics(); int margin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 24, dm); - mPager.setPageMargin(margin); + mPager.setPageMargin(-margin / 2); mPager.setOffscreenPageLimit(3); mPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() { @@ -187,10 +187,14 @@ public class ChooserActivity extends FragmentActivity hideSaveApplyButton(); } else if (mExpanded) { mExpanded = false; - mContainer.collapse(); - ThemeFragment f = (ThemeFragment) getSupportFragmentManager() + final ThemeFragment f = (ThemeFragment) getSupportFragmentManager() .findFragmentByTag(getFragmentTag(mPager.getCurrentItem())); - f.collapse(); + f.fadeOutCards(new Runnable() { + public void run() { + mContainer.collapse(); + f.collapse(); + } + }); } else { super.onBackPressed(); } @@ -261,17 +265,12 @@ public class ChooserActivity extends FragmentActivity private View.OnClickListener mPagerClickListener = new View.OnClickListener() { @Override public void onClick(View v) { - mExpanded = !mExpanded; - if (mExpanded) { + if (!mExpanded) { + mExpanded = true; mContainer.expand(); ThemeFragment f = (ThemeFragment) getSupportFragmentManager() .findFragmentByTag(getFragmentTag(mPager.getCurrentItem())); f.expand(); - } else { - mContainer.collapse(); - ThemeFragment f = (ThemeFragment) getSupportFragmentManager() - .findFragmentByTag(getFragmentTag(mPager.getCurrentItem())); - f.collapse(); } } }; diff --git a/src/org/cyanogenmod/theme/chooserv2/ComponentCardView.java b/src/org/cyanogenmod/theme/chooserv2/ComponentCardView.java new file mode 100644 index 0000000..8a56093 --- /dev/null +++ b/src/org/cyanogenmod/theme/chooserv2/ComponentCardView.java @@ -0,0 +1,90 @@ +package org.cyanogenmod.theme.chooserv2; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Rect; +import android.graphics.drawable.TransitionDrawable; +import android.util.AttributeSet; +import android.view.View; +import android.widget.LinearLayout; +import android.widget.TextView; + +import org.cyanogenmod.theme.chooser.R; + +public class ComponentCardView extends LinearLayout { + public static final int CARD_FADE_DURATION = 300; + + private TextView mLabel; + + // Expanded Padding + int mExpandPadLeft; + int mExpandPadTop; + int mExpandPadRight; + int mExpandPadBottom; + + public ComponentCardView(Context context) { + this(context, null); + } + + public ComponentCardView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public ComponentCardView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + @Override + protected void onFinishInflate() { + mLabel = (TextView) findViewById(R.id.label); + + Resources r = getContext().getResources(); + mExpandPadLeft = + (int) r.getDimension(R.dimen.card_padding_left_right) + getPaddingLeft(); + mExpandPadTop = + (int) r.getDimension(R.dimen.card_padding_top) + getPaddingTop(); + mExpandPadRight = + (int) r.getDimension(R.dimen.card_padding_left_right) + getPaddingRight(); + mExpandPadBottom = + (int) r.getDimension(R.dimen.card_padding_bottom) + getPaddingBottom(); + } + + public void expand() { + TransitionDrawable bg = (TransitionDrawable) getBackground(); + Rect paddingRect = new Rect(); + bg.getPadding(paddingRect); + + setPadding(mExpandPadLeft, mExpandPadTop, mExpandPadRight, mExpandPadBottom); + + if (mLabel != null) { + mLabel.setVisibility(View.VISIBLE); + } + } + + public void animateExpand() { + if (getBackground() instanceof TransitionDrawable) { + TransitionDrawable background = (TransitionDrawable) getBackground(); + if (mLabel != null) { + mLabel.setVisibility(View.VISIBLE); + mLabel.animate().alpha(1f).setDuration(CARD_FADE_DURATION); + } + background.startTransition(CARD_FADE_DURATION); + } + } + + public void collapse() { + if (mLabel != null) { + mLabel.setVisibility(View.GONE); + } + setPadding(0, 0, 0, 0); + } + + public void animateFadeOut() { + if (mLabel != null) { + mLabel.animate().alpha(0f).setDuration(CARD_FADE_DURATION); + } + TransitionDrawable background = (TransitionDrawable) getBackground(); + background.reverseTransition(CARD_FADE_DURATION); + } + +} diff --git a/src/org/cyanogenmod/theme/chooserv2/PagerContainer.java b/src/org/cyanogenmod/theme/chooserv2/PagerContainer.java index f58957f..f6cd8ef 100644 --- a/src/org/cyanogenmod/theme/chooserv2/PagerContainer.java +++ b/src/org/cyanogenmod/theme/chooserv2/PagerContainer.java @@ -133,9 +133,30 @@ public class PagerContainer extends FrameLayout implements ViewPager.OnPageChang setLayoutParams(params); mPager.setExpanded(true); + final int current = mPager.getCurrentItem(); final int prevY = (int) getY(); + //Since our viewpager's width is changing to fill the screen + //we must start the left/right children of the current page inwards on first draw + final int lChildPrevXf; + final int rChildPrevXf; + + if (current != 0) { + final View lchild = mPager.getViewForPosition(current - 1); + lChildPrevXf = (int) lchild.getX(); + } else { + lChildPrevXf = 0; + } + + if (current < mPager.getAdapter().getCount() - 1) { + View rchild = mPager.getViewForPosition(current + 1); + rChildPrevXf = (int) rchild.getX(); + } else { + rChildPrevXf = 0; + } + + final ViewTreeObserver observer = mPager.getViewTreeObserver(); observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { public boolean onPreDraw() { @@ -143,11 +164,13 @@ public class PagerContainer extends FrameLayout implements ViewPager.OnPageChang if (current != 0) { View lchild = mPager.getViewForPosition(current - 1); lchild.setTranslationY(prevY - getY()); + lchild.setX(lChildPrevXf); animateChildOut(lchild, -getWidth()); } if (current < mPager.getAdapter().getCount() - 1) { View rchild = mPager.getViewForPosition(current + 1); + rchild.setX(rChildPrevXf); rchild.setTranslationY(prevY - getY()); animateChildOut(rchild, getWidth()); } @@ -166,7 +189,6 @@ public class PagerContainer extends FrameLayout implements ViewPager.OnPageChang final int prevY = (int) getY(); if (current != 0) { - View lchild = mPager.getViewForPosition(current - 1); lchild.setTranslationY(0); animateChildIn(lchild); diff --git a/src/org/cyanogenmod/theme/chooserv2/ThemeFragment.java b/src/org/cyanogenmod/theme/chooserv2/ThemeFragment.java index c716c7b..4fa467a 100644 --- a/src/org/cyanogenmod/theme/chooserv2/ThemeFragment.java +++ b/src/org/cyanogenmod/theme/chooserv2/ThemeFragment.java @@ -24,11 +24,13 @@ import android.content.res.ThemeConfig; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.BitmapFactory; +import android.graphics.Rect; import android.graphics.Typeface; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Bundle; +import android.os.Handler; import android.provider.Settings; import android.provider.ThemesContract; import android.provider.ThemesContract.PreviewColumns; @@ -37,7 +39,6 @@ import android.support.v4.app.Fragment; import android.support.v4.app.LoaderManager; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; -import android.util.TypedValue; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -57,7 +58,7 @@ import java.util.List; public class ThemeFragment extends Fragment implements LoaderManager.LoaderCallbacks { public static final int ANIMATE_START_DELAY = 200; - public static final int ANIMATE_DURATION = 800; + public static final int ANIMATE_DURATION = 300; public static final int ANIMATE_INTERPOLATE_FACTOR = 3; public static final String CURRENTLY_APPLIED_THEME = "currently_applied_theme"; @@ -109,6 +110,8 @@ public class ThemeFragment extends Fragment implements LoaderManager.LoaderCallb private ImageView mHomeButton; private ImageView mRecentButton; + private Handler mHandler; + static ThemeFragment newInstance(String pkgName) { ThemeFragment f = new ThemeFragment(); Bundle args = new Bundle(); @@ -132,6 +135,8 @@ public class ThemeFragment extends Fragment implements LoaderManager.LoaderCallb helper.load(getActivity(), CURRENTLY_APPLIED_THEME.equals(mPkgName) ? getAppliedFontPackageName() : mPkgName); mTypefaceNormal = helper.getTypeface(Typeface.NORMAL); + + mHandler = new Handler(); } @Override @@ -179,61 +184,99 @@ public class ThemeFragment extends Fragment implements LoaderManager.LoaderCallb } public void expand() { - ViewGroup.LayoutParams layoutParams = mScrollContent.getLayoutParams(); - layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT; - mScrollContent.setLayoutParams(layoutParams); - - layoutParams = mPreviewContent.getLayoutParams(); + // Full width and height! + ViewGroup content = (ViewGroup) mScrollView.getParent(); + content.setPadding(0, 0, 0, 0); + ViewGroup.LayoutParams layoutParams = mPreviewContent.getLayoutParams(); layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT; + // Expand the children for (int i = 0; i < mPreviewContent.getChildCount(); i++) { - View child = mPreviewContent.getChildAt(i); - RelativeLayout.LayoutParams layout = + ComponentCardView child = (ComponentCardView) mPreviewContent.getChildAt(i); + RelativeLayout.LayoutParams lparams = (RelativeLayout.LayoutParams) child.getLayoutParams(); - int botMargin = (int) child.getContext().getResources() - .getDimension(R.dimen.expanded_preview_margin); - layout.setMargins(0, 0, 0, botMargin); - child.setLayoutParams(layout); + + int top = (int) child.getResources() + .getDimension(R.dimen.expanded_card_margin_top); + lparams.setMargins(0, top, 0, 0); + if (child.getId() == R.id.navigation_bar_container) { + lparams.removeRule(RelativeLayout.ALIGN_PARENT_BOTTOM); + lparams.addRule(RelativeLayout.BELOW, R.id.icon_container); + } + + child.setLayoutParams(lparams); + child.expand(); } - mScrollContent.requestLayout(); - animateChildren(true); + + // Collect the present position of all the children. The next layout/draw cycle will + // change these bounds since we just expanded them. Then we can animate from prev location + // to the new location. + animateChildren(true, getChildrensGlobalBounds()); animateWallpaperOut(); + } + // Returns the boundaries for all the children in the scrollview relative to the window + private List getChildrensGlobalBounds() { + List bounds = new ArrayList(); + for (int i = 0; i < mPreviewContent.getChildCount(); i++) { + final View v = mPreviewContent.getChildAt(i); + int[] pos = new int[2]; + v.getLocationInWindow(pos); + Rect boundary = new Rect(pos[0], pos[1], pos[0]+v.getWidth(), pos[1]+v.getHeight()); + bounds.add(boundary); + } + return bounds; + } + + public void fadeOutCards(Runnable endAction) { + for (int i = 0; i < mPreviewContent.getChildCount(); i++) { + ComponentCardView v = (ComponentCardView) mPreviewContent.getChildAt(i); + v.animateFadeOut(); + } + mHandler.postDelayed(endAction, ComponentCardView.CARD_FADE_DURATION); } public void collapse() { + // Pad the view so it appears thinner + ViewGroup content = (ViewGroup) mScrollView.getParent(); + Resources r = mScrollView.getContext().getResources(); + int leftRightPadding = (int) r.getDimension(R.dimen.collapsed_theme_page_padding); + content.setPadding(leftRightPadding, 0, leftRightPadding, 0); + + // Shrink the height ViewGroup.LayoutParams layoutParams = mPreviewContent.getLayoutParams(); Resources resources = mPreviewContent.getResources(); layoutParams.height = (int) resources.getDimension(R.dimen.theme_preview_height); for (int i = 0; i < mPreviewContent.getChildCount(); i++) { - View child = mPreviewContent.getChildAt(i); - RelativeLayout.LayoutParams layout = + ComponentCardView child = (ComponentCardView) mPreviewContent.getChildAt(i); + RelativeLayout.LayoutParams lparams = (RelativeLayout.LayoutParams) child.getLayoutParams(); - layout.setMargins(0, 0, 0, 0); - child.setLayoutParams(layout); + lparams.setMargins(0, 0, 0, 0); + + if (child.getId() == R.id.navigation_bar_container) { + lparams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM); + lparams.removeRule(RelativeLayout.BELOW); + } else if (child.getId() == R.id.icon_container) { + int top = (int) child.getResources() + .getDimension(R.dimen.collapsed_icon_card_margin_top); + lparams.setMargins(0, top, 0, 0); + } + + child.getLayoutParams(); + child.collapse(); } mPreviewContent.requestLayout(); - - animateChildren(false); + animateChildren(false, getChildrensGlobalBounds()); animateWallpaperIn(); } - // This will animate the children's vertical value between the existing and - // new layout changes - private void animateChildren(final boolean isExpanding) { + // This will animate the children's vertical positions between the previous bounds and the + // new bounds which occur on the next draw + private void animateChildren(final boolean isExpanding, final List prevBounds) { final ViewGroup root = (ViewGroup) getActivity().getWindow() .getDecorView().findViewById(android.R.id.content); - // Get the child's current location - final List prevYs = new ArrayList(); - for (int i = 0; i < mPreviewContent.getChildCount(); i++) { - final View v = mPreviewContent.getChildAt(i); - int[] pos = new int[2]; - v.getLocationInWindow(pos); - prevYs.add((float) pos[1]); - } - // Grab the child's new location and animate from prev to current loc. final ViewTreeObserver observer = mScrollContent.getViewTreeObserver(); observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @@ -241,22 +284,28 @@ public class ThemeFragment extends Fragment implements LoaderManager.LoaderCallb observer.removeOnPreDrawListener(this); for (int i = mPreviewContent.getChildCount() - 1; i >= 0; i--) { - final View v = mPreviewContent.getChildAt(i); + final ComponentCardView v = (ComponentCardView) mPreviewContent.getChildAt(i); - float prevY; - float endY; - if (i >= prevYs.size()) { + float prevY; float endY; + float prevHeight; float endHeight; + if (i >= prevBounds.size()) { // View is being created prevY = mPreviewContent.getTop() + mPreviewContent.getHeight(); endY = v.getY(); + prevHeight = v.getHeight(); + endHeight = v.getHeight(); } else { - prevY = prevYs.get(i); + Rect boundary = prevBounds.get(i); + prevY = boundary.top; + prevHeight = boundary.height(); + int[] endPos = new int[2]; v.getLocationInWindow(endPos); endY = endPos[1]; + endHeight = v.getHeight(); } - v.setTranslationY((prevY - endY)); + v.setTranslationY((prevY - endY) + (prevHeight - endHeight) / 2); root.getOverlay().add(v); // Expanding has a delay while the wallpaper begins to fade out @@ -275,6 +324,13 @@ public class ThemeFragment extends Fragment implements LoaderManager.LoaderCallb mPreviewContent.addView(v, 0); } }); + v.postDelayed(new Runnable() { + public void run() { + if (isExpanding) { + v.animateExpand(); + } + } + }, ANIMATE_DURATION / 2); } @@ -313,16 +369,11 @@ public class ThemeFragment extends Fragment implements LoaderManager.LoaderCallb } private void animateWallpaperIn() { + mWallpaper.setVisibility(View.VISIBLE); mWallpaper.setTranslationY(0); mWallpaper.animate() - .setStartDelay(ANIMATE_START_DELAY) .alpha(1f) - .setDuration(300) - .withEndAction(new Runnable() { - public void run() { - mWallpaper.setVisibility(View.VISIBLE); - } - }); + .setDuration(300); } private String getAppliedFontPackageName() { @@ -394,6 +445,7 @@ public class ThemeFragment extends Fragment implements LoaderManager.LoaderCallb @Override public void onLoadFinished(Loader loader, Cursor c) { c.moveToFirst(); + if (c.getCount() == 0) return; loadWallpaper(c); loadStatusBar(c); loadIcons(c); @@ -462,7 +514,7 @@ public class ThemeFragment extends Fragment implements LoaderManager.LoaderCallb // fall back to the default icon set IconPreviewHelper helper = new IconPreviewHelper(getActivity(), ""); for(int i=0; i < mIconContainer.getChildCount() && i < iconIdx.length; i++) { - ImageView v = (ImageView) mIconContainer.getChildAt(i); + ImageView v = (ImageView) ((ViewGroup)mIconContainer.getChildAt(1)).getChildAt(i); Bitmap bitmap = Utils.loadBitmapBlob(c, iconIdx[i]); if (bitmap == null) { ComponentName component = sIconComponents[i]; -- cgit v1.1