diff --git a/.gitignore b/.gitignore index c6cbe56..c88a4b6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,7 @@ *.iml .gradle /local.properties -/.idea/workspace.xml -/.idea/libraries +.idea .DS_Store /build /captures diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index f0b7884..c3431c1 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -10,16 +10,9 @@ android:id="@+id/thumb" android:layout_width="match_parent" android:layout_height="match_parent" + android:background="@mipmap/profile_background" app:menu_direction="bottom" app:scale_ratio=".38"> - - - - - * Created by hitomi on 2016/8/26. @@ -21,349 +21,345 @@ */ public class ThumbnailAnimator { - private final Interpolator interpolator = new OvershootInterpolator(); - - /** - * 缩略图菜单 - */ - private ThumbnailMenu thumbnailMenu; - - /** - * 用于放置缩略图菜单的容器 ScrollView - */ - private final FrameLayout scrollLayout; - - /** - * 用于放置缩略图菜单的容器 ViewGroup - */ - private ThumbnailContainer container; - - /** - * Fragment 容器布局集合 - */ - private List tranLayoutList; - - /** - *菜单关闭时的监听器 - */ - private ThumbnailMenu.OnThumbnailMenuCloseListener onMenuCloseListener; - - /** - * 菜单方向 - */ - private int direction; - - private boolean init = true; - - public ThumbnailAnimator(int direction, ThumbnailMenu thumbnailMenu, List tranLayoutList) { - this.direction = direction; - this.thumbnailMenu = thumbnailMenu; - this.tranLayoutList = tranLayoutList; - - scrollLayout = (FrameLayout) thumbnailMenu.findViewWithTag(ThumbnailMenu.TAG_SCROLL_LAYOUT); - container = (ThumbnailContainer) scrollLayout.getChildAt(0); + private final Interpolator interpolator = new OvershootInterpolator(); + /** + * 菜单是否打开 + */ + private boolean isOpen = false; + /** + * 是否正在执行动画 + */ + private boolean mIsInAnimation = false; + /** + * 缩略图菜单 + */ + private ThumbnailMenu thumbnailMenu; + + /** + * 用于放置缩略图菜单的容器 ScrollView + */ + private final FrameLayout scrollLayout; + + /** + * 用于放置缩略图菜单的容器 ViewGroup + */ + private ThumbnailContainer container; + + /** + * Fragment 容器布局集合 + */ + private List tranLayoutList; + + /** + * 菜单关闭时的监听器 + */ + private ThumbnailMenu.OnThumbnailMenuCloseListener onMenuCloseListener; + + /** + * 菜单方向 + */ + private int direction; + + private boolean init = true; + + public ThumbnailAnimator(int direction, ThumbnailMenu thumbnailMenu, + List tranLayoutList) { + this.direction = direction; + this.thumbnailMenu = thumbnailMenu; + this.tranLayoutList = tranLayoutList; + + scrollLayout = (FrameLayout) thumbnailMenu.findViewWithTag(ThumbnailMenu.TAG_SCROLL_LAYOUT); + container = (ThumbnailContainer) scrollLayout.getChildAt(0); + } + + public boolean isOpen() { + return isOpen; + } + + /** + * 动画模式打开菜单 + */ + public void openMenuAnimator() { + if (mIsInAnimation || isOpen) { + return; } + mIsInAnimation = true; + switch (direction) { + case ThumbnailFactory.MENU_DIRECTION_LEFT: + case ThumbnailFactory.MENU_DIRECTION_RIGHT: + horizontalOpenMenu(); + break; - /** - * 动画模式打开菜单 - */ - public void openMenuAnimator() { - scrollLayout.setVisibility(View.VISIBLE); - switch (direction) { - case ThumbnailFactory.MENU_DIRECTION_LEFT: - case ThumbnailFactory.MENU_DIRECTION_RIGHT: - horizontalOpenMenu(); - break; - - case ThumbnailFactory.MENU_DIRECTION_BOTTOM: - verticalOpenMun(); - break; + case ThumbnailFactory.MENU_DIRECTION_BOTTOM: + verticalOpenMenu(); + break; - } } - - /** - * 动画模式关闭菜单,并显示 transitionLayout - * - * @param transitionLayout 选中页面所在的 TransitionLayout - * @param onMenuCloseListener - */ - public void closeMenuAnimator(TransitionLayout transitionLayout, - ThumbnailMenu.OnThumbnailMenuCloseListener onMenuCloseListener) { - this.onMenuCloseListener = onMenuCloseListener; - switch (direction) { - case ThumbnailFactory.MENU_DIRECTION_LEFT: - case ThumbnailFactory.MENU_DIRECTION_RIGHT: - horizontalCloseMenu(transitionLayout); - break; - - case ThumbnailFactory.MENU_DIRECTION_BOTTOM: - verticalCloseMenu(transitionLayout); - break; - } + } + + /** + * 动画模式关闭菜单,并显示 transitionLayout + * + * @param transitionLayout 选中页面所在的 TransitionLayout + * @param onMenuCloseListener + */ + public void closeMenuAnimator(TransitionLayout transitionLayout, + ThumbnailMenu.OnThumbnailMenuCloseListener onMenuCloseListener) { + if (mIsInAnimation || !isOpen) { + return; } - - /** - * 纵向打开菜单 - */ - private void verticalOpenMun() { - float endTranX, endTranY; - if (init) { - for (int i = 0; i < tranLayoutList.size(); i++) { - final TransitionLayout currTranLayout = tranLayoutList.get(i); - final float tmpTranX = currTranLayout.getWidth() * (1.f - thumbnailMenu.getScaleRatio()) * .5f; - - endTranX = -tmpTranX + (i * (currTranLayout.getWidth() * thumbnailMenu.getScaleRatio() + ThumbnailMenu.THUM_MARGIN)); - endTranY = currTranLayout.getHeight() * (1.f - thumbnailMenu.getScaleRatio()) * .5f; - - AnimatorSet animSet = makeOpenMenuAnimatorSet(endTranX, endTranY, currTranLayout); - addOpenMenuAnimatorSetListener(animSet, currTranLayout, endTranY, i, tmpTranX); - } - init = false; - } else { - TransitionLayout showingTranLayout = (TransitionLayout) thumbnailMenu.getChildAt(thumbnailMenu.getChildCount() - 1); - - float singleThumMenuWidth = showingTranLayout.getWidth() * thumbnailMenu.getScaleRatio(); - int menuIndex = tranLayoutList.indexOf(showingTranLayout); - - // 调整菜单滚动的位置 - int adjustScrollPosition = (int) (menuIndex * (singleThumMenuWidth + ThumbnailMenu.THUM_MARGIN)); - HorizontalScrollView scrollView = (HorizontalScrollView) scrollLayout; - scrollView.scrollTo(adjustScrollPosition, 0); - - // 当前 ScrollView 滚动的距离 - int scrollDistance = scrollView.getScrollX(); - float tmpTranX = showingTranLayout.getWidth() * (1.f - thumbnailMenu.getScaleRatio()) * .5f; - - endTranX = -tmpTranX + (menuIndex * (singleThumMenuWidth + ThumbnailMenu.THUM_MARGIN)) - scrollDistance; - endTranY = showingTranLayout.getHeight() * (1.f - thumbnailMenu.getScaleRatio()) * .5f; - - AnimatorSet animSet = makeOpenMenuAnimatorSet(endTranX, endTranY, showingTranLayout); - addOpenMenuAnimatorSetListener(animSet, showingTranLayout, endTranY, menuIndex, tmpTranX); - } + mIsInAnimation = true; + this.onMenuCloseListener = onMenuCloseListener; + switch (direction) { + case ThumbnailFactory.MENU_DIRECTION_LEFT: + case ThumbnailFactory.MENU_DIRECTION_RIGHT: + horizontalCloseMenu(transitionLayout); + break; + + case ThumbnailFactory.MENU_DIRECTION_BOTTOM: + verticalCloseMenu(transitionLayout); + break; } - - /** - * 纵向(左侧或者右侧)关闭菜单,并显示选中的 TransitionLayout - * - * @param transitionLayout 选中页面所在的 TransitionLayout - */ - private void verticalCloseMenu(final TransitionLayout transitionLayout) { - HorizontalScrollView scrollView = (HorizontalScrollView) scrollLayout; - // 当前 ScrollView 滚动的距离 - final int scrollDistance = scrollView.getScrollX(); - // 当前选中的 TransitionLayout 所在模型的 Left - final int currTranLeft = ((FrameLayout) transitionLayout.getParent()).getLeft(); - - int tranTop = ((FrameLayout) transitionLayout.getParent()).getTop(); - // 将选中 TransitionLayout 从其所在模型中移除并放置在 ThumbnailMenu 相对模型所在同一个位置上 - final int choosenMenuIndex = tranLayoutList.indexOf(transitionLayout); - FrameLayout frameLayout = (FrameLayout) container.getChildAt(choosenMenuIndex); - frameLayout.removeView(transitionLayout); - - final FrameLayout.LayoutParams frameParams = new FrameLayout.LayoutParams( - transitionLayout.getWidth(), - transitionLayout.getHeight()); - frameParams.leftMargin = currTranLeft - scrollDistance; - frameParams.topMargin = tranTop; - transitionLayout.setLayoutParams(frameParams); - - thumbnailMenu.addView(transitionLayout); - - float endTranX = (thumbnailMenu.getWidth() - transitionLayout.getWidth()) * .5f - currTranLeft + scrollDistance; - float endTranY = -frameParams.topMargin; - - AnimatorSet animSet = makeCloseMenuAnimatorSet(transitionLayout, endTranX, endTranY); - addCloseMenuAnimatorSetListener(transitionLayout, frameParams, animSet); + } + + /** + * 纵向打开菜单 + */ + private void verticalOpenMenu() { + float endTranX, endTranY; + if (init) { + for (int i = 0; i < tranLayoutList.size(); i++) { + final TransitionLayout currTranLayout = tranLayoutList.get(i); + final float tmpTranX = + currTranLayout.getWidth() * (1.f - thumbnailMenu.getScaleRatio()) * .5f; + + endTranX = -tmpTranX + (i * (currTranLayout.getWidth() * thumbnailMenu.getScaleRatio() + + ThumbnailMenu.THUM_MARGIN)); + endTranY = currTranLayout.getHeight() * (1.f - thumbnailMenu.getScaleRatio()) * .5f; + + AnimatorSet animSet = makeOpenMenuAnimatorSet(endTranX, endTranY, currTranLayout); + addOpenMenuAnimatorSetListener(animSet, currTranLayout, i); + } + init = false; + } else { + TransitionLayout showingTranLayout = + (TransitionLayout) thumbnailMenu.getChildAt(thumbnailMenu.getChildCount() - 1); + + float singleThumMenuWidth = showingTranLayout.getWidth() * thumbnailMenu.getScaleRatio(); + int menuIndex = tranLayoutList.indexOf(showingTranLayout); + + + HorizontalScrollView scrollView = (HorizontalScrollView) scrollLayout; + + // 当前 ScrollView 滚动的距离 + int scrollDistance = scrollView.getScrollX(); + float tmpTranX = showingTranLayout.getWidth() * (1.f - thumbnailMenu.getScaleRatio()) * .5f; + + endTranX = -tmpTranX + (menuIndex * (singleThumMenuWidth + ThumbnailMenu.THUM_MARGIN)) + - scrollDistance; + endTranY = showingTranLayout.getHeight() * (1.f - thumbnailMenu.getScaleRatio()) * .5f; + + AnimatorSet animSet = makeOpenMenuAnimatorSet(endTranX, endTranY, showingTranLayout); + addOpenMenuAnimatorSetListener(animSet, showingTranLayout, menuIndex); } + } + + /** + * 纵向(左侧或者右侧)关闭菜单,并显示选中的 TransitionLayout + * + * @param transitionLayout 选中页面所在的 TransitionLayout + */ + private void verticalCloseMenu(final TransitionLayout transitionLayout) { + thumbnailMenu.bringChildToFront(transitionLayout); + + HorizontalScrollView scrollView = (HorizontalScrollView) scrollLayout; + // 当前 ScrollView 滚动的距离 + final int scrollDistance = scrollView.getScrollX(); + + final int choosenMenuIndex = tranLayoutList.indexOf(transitionLayout); + ThumbnailView frameLayout = (ThumbnailView) container.getChildAt(choosenMenuIndex); + // 当前选中的 TransitionLayout 所在模型的 Left + final int currTranLeft = frameLayout.getLeft(); + + float offsetX = (thumbnailMenu.getWidth() - frameLayout.getWidth()) * .5f; + float offsetY = (thumbnailMenu.getHeight() - frameLayout.getHeight()) * .5f; + transitionLayout.setTranslationX(currTranLeft - scrollDistance - offsetX); + transitionLayout.setTranslationY(offsetY); + + AnimatorSet animSet = makeCloseMenuAnimatorSet(transitionLayout, 0, 0); + addCloseMenuAnimatorSetListener(animSet); + } + + /** + * 横向(左侧或者右侧)打开菜单 + */ + private void horizontalOpenMenu() { + float endTranX, endTranY; + if (init) { + for (int i = 0; i < tranLayoutList.size(); i++) { + TransitionLayout currTranLayout = tranLayoutList.get(i); + float tmpTranY = currTranLayout.getHeight() * (1.f - thumbnailMenu.getScaleRatio()) * .5f; + + endTranX = currTranLayout.getWidth() * (1.f - thumbnailMenu.getScaleRatio()) * .5f; + endTranY = -tmpTranY + (i * (currTranLayout.getHeight() * thumbnailMenu.getScaleRatio() + + ThumbnailMenu.THUM_MARGIN)); - /** - * 横向(左侧或者右侧)打开菜单 - */ - private void horizontalOpenMenu() { - float endTranX, endTranY; - if (init) { - for (int i = 0; i < tranLayoutList.size(); i++) { - TransitionLayout currTranLayout = tranLayoutList.get(i); - float tmpTranY = currTranLayout.getHeight() * (1.f - thumbnailMenu.getScaleRatio()) * .5f; - - endTranX = currTranLayout.getWidth() * (1.f - thumbnailMenu.getScaleRatio()) * .5f; - endTranY = -tmpTranY + (i * (currTranLayout.getHeight() * thumbnailMenu.getScaleRatio() + ThumbnailMenu.THUM_MARGIN)); - - AnimatorSet animSet = makeOpenMenuAnimatorSet(endTranX, endTranY, currTranLayout); - addOpenMenuAnimatorSetListener(animSet, currTranLayout, tmpTranY, i, endTranX); - } - init = false; - } else { - TransitionLayout showingTranLayout = (TransitionLayout) thumbnailMenu.getChildAt(thumbnailMenu.getChildCount() - 1); - - float singleThumMenuHeight = showingTranLayout.getHeight() * thumbnailMenu.getScaleRatio(); - int menuIndex = tranLayoutList.indexOf(showingTranLayout); - - // 调整菜单滚动的位置 - int adjustScrollPosition = (int) (menuIndex * (singleThumMenuHeight + ThumbnailMenu.THUM_MARGIN)); - ScrollView scrollView = (ScrollView) scrollLayout; - scrollView.scrollTo(0, adjustScrollPosition); - - // 当前 ScrollView 滚动的距离 - int scrollDistance = scrollView.getScrollY(); - float tmpTranY = showingTranLayout.getHeight() * (1.f - thumbnailMenu.getScaleRatio()) * .5f; - - endTranX = showingTranLayout.getWidth() * (1.f - thumbnailMenu.getScaleRatio()) * .5f; - endTranY = -tmpTranY + (menuIndex * (singleThumMenuHeight + ThumbnailMenu.THUM_MARGIN)) - scrollDistance; - - AnimatorSet animSet = makeOpenMenuAnimatorSet(endTranX, endTranY, showingTranLayout); - addOpenMenuAnimatorSetListener(animSet, showingTranLayout, tmpTranY, menuIndex, endTranX); - } - + endTranX = direction == ThumbnailFactory.MENU_DIRECTION_LEFT ? -endTranX : endTranX; + AnimatorSet animSet = makeOpenMenuAnimatorSet(endTranX, endTranY, currTranLayout); + addOpenMenuAnimatorSetListener(animSet, currTranLayout, i); + } + init = false; + } else { + TransitionLayout showingTranLayout = + (TransitionLayout) thumbnailMenu.getChildAt(thumbnailMenu.getChildCount() - 1); + + float singleThumMenuHeight = showingTranLayout.getHeight() * thumbnailMenu.getScaleRatio(); + int menuIndex = tranLayoutList.indexOf(showingTranLayout); + + ScrollView scrollView = (ScrollView) scrollLayout; + + // 当前 ScrollView 滚动的距离 + int scrollDistance = scrollView.getScrollY(); + float tmpTranY = showingTranLayout.getHeight() * (1.f - thumbnailMenu.getScaleRatio()) * .5f; + + endTranX = showingTranLayout.getWidth() * (1.f - thumbnailMenu.getScaleRatio()) * .5f; + endTranY = -tmpTranY + (menuIndex * (singleThumMenuHeight + ThumbnailMenu.THUM_MARGIN)) + - scrollDistance; + + endTranX = direction == ThumbnailFactory.MENU_DIRECTION_LEFT ? -endTranX : endTranX; + AnimatorSet animSet = makeOpenMenuAnimatorSet(endTranX, endTranY, showingTranLayout); + addOpenMenuAnimatorSetListener(animSet, showingTranLayout, menuIndex); } - /** - * 横向(左侧或者右侧)关闭菜单,并显示选中的 TransitionLayout - * - * @param transitionLayout 选中页面所在的TransitionLayout - */ - private void horizontalCloseMenu(final TransitionLayout transitionLayout) { - // 当前 ScrollView 滚动的距离 - final int scrollDistance = scrollLayout.getScrollY(); - // 当前选中的 TransitionLayout 所在模型的 Top - final int currTranTop = ((FrameLayout) transitionLayout.getParent()).getTop(); - - // 将选中 TransitionLayout 从其所在模型中移除并放置在 ThumbnailMenu 相对模型所在同一个位置上 - final int choosenMenuIndex = tranLayoutList.indexOf(transitionLayout); - FrameLayout frameLayout = (FrameLayout) container.getChildAt(choosenMenuIndex); - frameLayout.removeView(transitionLayout); - - final FrameLayout.LayoutParams frameParams = new FrameLayout.LayoutParams( - transitionLayout.getWidth(), - transitionLayout.getHeight()); - frameParams.topMargin = currTranTop - scrollDistance; - transitionLayout.setLayoutParams(frameParams); - - thumbnailMenu.addView(transitionLayout); + } - float endTranX = (thumbnailMenu.getWidth() - transitionLayout.getWidth()) * .5f; - float endTranY = (thumbnailMenu.getHeight() - transitionLayout.getHeight()) * .5f - currTranTop + scrollDistance; + /** + * 横向(左侧或者右侧)关闭菜单,并显示选中的 TransitionLayout + * + * @param transitionLayout 选中页面所在的TransitionLayout + */ + private void horizontalCloseMenu(final TransitionLayout transitionLayout) { + thumbnailMenu.bringChildToFront(transitionLayout); - AnimatorSet animSet = makeCloseMenuAnimatorSet(transitionLayout, endTranX, endTranY); - addCloseMenuAnimatorSetListener(transitionLayout, frameParams, animSet); + // 当前 ScrollView 滚动的距离 + final int scrollDistance = scrollLayout.getScrollY(); - } + final int choosenMenuIndex = tranLayoutList.indexOf(transitionLayout); + ThumbnailView frameLayout = (ThumbnailView) container.getChildAt(choosenMenuIndex); + // 当前选中的 TransitionLayout 所在模型的 Top + final int currTranTop = frameLayout.getTop(); - private void addCloseMenuAnimatorSetListener(final TransitionLayout transitionLayout, - final FrameLayout.LayoutParams frameParams, - AnimatorSet animSet) { - - animSet.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - frameParams.leftMargin = 0; - frameParams.topMargin = 0; - // 还原选中的 TransitionLayout - transitionLayout.setTranslationX(0); - transitionLayout.setTranslationY(0); - transitionLayout.setLayoutParams(frameParams); - - if (onMenuCloseListener != null) { - onMenuCloseListener.onMenuCloseListener(); - } - scrollLayout.setVisibility(View.GONE); - } - }); - } + float offsetX = (thumbnailMenu.getWidth() - frameLayout.getWidth()) * .5f; + float translationX = + direction == ThumbnailFactory.MENU_DIRECTION_LEFT ? -offsetX : offsetX; + transitionLayout.setTranslationX(translationX); + transitionLayout.setTranslationY(currTranTop - scrollDistance + - (thumbnailMenu.getHeight() - frameLayout.getHeight()) * .5f); - /** - * 创建打开菜单的动画集 - * - * @param endTranX - * @param endTranY - * @param transitionLayout - * @return - */ - @NonNull - private AnimatorSet makeOpenMenuAnimatorSet(float endTranX, float endTranY, TransitionLayout transitionLayout) { - endTranX = direction == ThumbnailFactory.MENU_DIRECTION_LEFT ? -endTranX : endTranX; + AnimatorSet animSet = makeCloseMenuAnimatorSet(transitionLayout, 0, 0); + addCloseMenuAnimatorSetListener(animSet); - ObjectAnimator scaleXAnima = ObjectAnimator.ofFloat( - transitionLayout, "scaleX", transitionLayout.getScaleX(), thumbnailMenu.getScaleRatio()); - ObjectAnimator scaleYAnima = ObjectAnimator.ofFloat( - transitionLayout, "scaleY", transitionLayout.getScaleY(), thumbnailMenu.getScaleRatio()); - - ObjectAnimator tranXAnima = ObjectAnimator.ofFloat( - transitionLayout, "translationX", transitionLayout.getTranslationX(), endTranX); - ObjectAnimator tranYAnima = ObjectAnimator.ofFloat( - transitionLayout, "translationY", transitionLayout.getTranslationY(), endTranY); - - AnimatorSet animSet = new AnimatorSet(); - animSet.setDuration(300); - animSet.setInterpolator(interpolator); - animSet.play(scaleXAnima).with(scaleYAnima).before(tranXAnima).before(tranYAnima); - animSet.start(); - return animSet; - } + } - /** - * 创建关闭菜单的动画集 - * - * @param transitionLayout - * @param endTranX - * @param endTranY - * @return - */ - @NonNull - private AnimatorSet makeCloseMenuAnimatorSet(TransitionLayout transitionLayout, float endTranX, float endTranY) { - ObjectAnimator scaleXAnima = ObjectAnimator.ofFloat( - transitionLayout, "scaleX", transitionLayout.getScaleX(), transitionLayout.getScaleX() / thumbnailMenu.getScaleRatio()); - ObjectAnimator scaleYAnima = ObjectAnimator.ofFloat( - transitionLayout, "scaleY", transitionLayout.getScaleX(), transitionLayout.getScaleY() / thumbnailMenu.getScaleRatio()); - - float currTranX = direction == ThumbnailFactory.MENU_DIRECTION_RIGHT ? - -transitionLayout.getTranslationX() : - transitionLayout.getTranslationX(); - - ObjectAnimator tranXAnima = ObjectAnimator.ofFloat( - transitionLayout, "translationX", currTranX, endTranX); - ObjectAnimator tranYAnima = ObjectAnimator.ofFloat( - transitionLayout, "translationY", transitionLayout.getTranslationY(), endTranY); - - AnimatorSet animSet = new AnimatorSet(); - animSet.setDuration(300); - animSet.play(tranXAnima).with(tranYAnima).before(scaleXAnima).before(scaleYAnima); - animSet.setInterpolator(interpolator); - animSet.start(); - return animSet; - } + private void addCloseMenuAnimatorSetListener(AnimatorSet animSet) { - /** - * 为菜单打开动画集添加一个监听器 - * - * @param animSet - * @param transitionLayout - * @param tmpTranY - * @param index - * @param finalEndTranX - */ - private void addOpenMenuAnimatorSetListener(AnimatorSet animSet, final TransitionLayout transitionLayout, - final float tmpTranY, final int index, final float finalEndTranX) { - animSet.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - // 1. 将 transitionLayout 从 menu 容器中移除 - thumbnailMenu.removeViewAt(thumbnailMenu.indexOfChild(transitionLayout)); - - // 2. 将 transitionLayout 放入菜单容器中 - // 设置为原来的宽高大小,是因为之前缩小过 - FrameLayout.LayoutParams frameParams = new FrameLayout.LayoutParams( - transitionLayout.getWidth(), - transitionLayout.getHeight() - ); - FrameLayout frameLayout = (FrameLayout) container.getChildAt(index); - // 调整位置 - transitionLayout.setTranslationX(-finalEndTranX); - transitionLayout.setTranslationY(-tmpTranY); - // 将缩小后的 transitionLayout 放入模型中 - frameLayout.addView(transitionLayout, frameParams); - } - }); - } + animSet.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (onMenuCloseListener != null) { + onMenuCloseListener.onMenuCloseListener(); + } + isOpen = false; + mIsInAnimation = false; + } + }); + } + + /** + * 创建打开菜单的动画集 + * + * @param endTranX + * @param endTranY + * @param transitionLayout + * @return + */ + @NonNull + private AnimatorSet makeOpenMenuAnimatorSet(float endTranX, float endTranY, + TransitionLayout transitionLayout) { + ObjectAnimator scaleXAnima = ObjectAnimator.ofFloat( + transitionLayout, "scaleX", transitionLayout.getScaleX(), thumbnailMenu.getScaleRatio()); + ObjectAnimator scaleYAnima = ObjectAnimator.ofFloat( + transitionLayout, "scaleY", transitionLayout.getScaleY(), thumbnailMenu.getScaleRatio()); + + ObjectAnimator tranXAnima = ObjectAnimator.ofFloat( + transitionLayout, "translationX", transitionLayout.getTranslationX(), endTranX); + ObjectAnimator tranYAnima = ObjectAnimator.ofFloat( + transitionLayout, "translationY", transitionLayout.getTranslationY(), endTranY); + + AnimatorSet animSet = new AnimatorSet(); + animSet.setDuration(300); + animSet.setInterpolator(interpolator); + animSet.play(scaleXAnima).with(scaleYAnima).with(tranXAnima).with(tranYAnima); + animSet.start(); + return animSet; + } + + /** + * 创建关闭菜单的动画集 + * + * @param transitionLayout + * @param endTranX + * @param endTranY + * @return + */ + @NonNull + private AnimatorSet makeCloseMenuAnimatorSet(TransitionLayout transitionLayout, float endTranX, + float endTranY) { + ObjectAnimator scaleXAnima = ObjectAnimator.ofFloat( + transitionLayout, "scaleX", transitionLayout.getScaleX(), + transitionLayout.getScaleX() / thumbnailMenu.getScaleRatio()); + ObjectAnimator scaleYAnima = ObjectAnimator.ofFloat( + transitionLayout, "scaleY", transitionLayout.getScaleX(), + transitionLayout.getScaleY() / thumbnailMenu.getScaleRatio()); + + float currTranX = transitionLayout.getTranslationX(); + + ObjectAnimator tranXAnima = ObjectAnimator.ofFloat( + transitionLayout, "translationX", currTranX, endTranX); + ObjectAnimator tranYAnima = ObjectAnimator.ofFloat( + transitionLayout, "translationY", transitionLayout.getTranslationY(), endTranY); + + AnimatorSet animSet = new AnimatorSet(); + animSet.setDuration(300); + animSet.play(tranXAnima).with(tranYAnima).with(scaleXAnima).with(scaleYAnima); + animSet.setInterpolator(interpolator); + animSet.start(); + return animSet; + } + + /** + * 为菜单打开动画集添加一个监听器 + * + * @param animSet + * @param transitionLayout + * @param index + */ + private void addOpenMenuAnimatorSetListener(AnimatorSet animSet, + final TransitionLayout transitionLayout, + final int index) { + animSet.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + + // ThumbnailView frameLayout = (ThumbnailView) container.getChildAt(index); + // frameLayout.setVisibility(View.VISIBLE); + + // 移到屏幕外进行隐藏处理 + transitionLayout.setTranslationY(transitionLayout.getHeight()); + + isOpen = true; + mIsInAnimation = false; + } + }); + } } diff --git a/tmlibrary/src/main/java/com/hitomi/tmlibrary/ThumbnailMenu.java b/tmlibrary/src/main/java/com/hitomi/tmlibrary/ThumbnailMenu.java index 0d9b858..e355851 100644 --- a/tmlibrary/src/main/java/com/hitomi/tmlibrary/ThumbnailMenu.java +++ b/tmlibrary/src/main/java/com/hitomi/tmlibrary/ThumbnailMenu.java @@ -1,5 +1,10 @@ +/* + * Copyright (C) 2016 Baidu, Inc. All Rights Reserved. + */ package com.hitomi.tmlibrary; +import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; + import android.content.Context; import android.content.res.TypedArray; import android.support.v4.view.PagerAdapter; @@ -11,8 +16,6 @@ import java.util.ArrayList; import java.util.List; -import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; - /** * 缩略图菜单 * Created by hitomi on 2016/8/19. @@ -20,229 +23,242 @@ */ public class ThumbnailMenu extends FrameLayout { - static final float SCALE_RATIO = .45f; + static final float SCALE_RATIO = .45f; - static final int THUM_MARGIN = 2; + static final int THUM_MARGIN = 2; - static final String TAG_SCROLL_LAYOUT = "tag_scroll_layout"; + static final String TAG_SCROLL_LAYOUT = "tag_scroll_layout"; - private ThumbnailFactory factory; + private ThumbnailFactory factory; - private ThumbnailAnimator thumbnailAnimator; + private ThumbnailAnimator thumbnailAnimator; - private ThumbnailMenuChooser thumbnailMenuChooser; + private ThumbnailMenuChooser thumbnailMenuChooser; - private FrameLayout thumScrollLayout; + private FrameLayout thumScrollLayout; - private PagerAdapter pageAdapter; + private PagerAdapter pageAdapter; - private OnThumbnailMenuCloseListener menuCloseListener; + private OnThumbnailMenuCloseListener menuCloseListener; - private List objects; + private List objects; - private List tranLayoutList; + private List tranLayoutList; - /** - * 缩略图菜单位置方向 - */ - private int direction = ThumbnailFactory.MENU_DIRECTION_BOTTOM; + /** + * 缩略图菜单位置方向 + */ + private int direction = ThumbnailFactory.MENU_DIRECTION_BOTTOM; - /** - * 缩略图当前缩放比率 - */ - private float scaleRation = SCALE_RATIO; + /** + * 缩略图当前缩放比率 + */ + private float scaleRation = SCALE_RATIO; - /** - * 第一次初始化标记 - */ - private boolean init = true; + /** + * 第一次初始化标记 + */ + private boolean init = true; - /** - * 菜单是否打开 - */ - private boolean isOpen; + /** + * 页面数量 + */ + private int pageCount; - /** - * 页面数量 - */ - private int pageCount; + public ThumbnailMenu(Context context) { + this(context, null); + } - public ThumbnailMenu(Context context) { - this(context, null); - } + public ThumbnailMenu(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } - public ThumbnailMenu(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } + public ThumbnailMenu(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); - public ThumbnailMenu(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); + TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ThumbnailMenu); + direction = typedArray.getInt(R.styleable.ThumbnailMenu_menu_direction, direction); + scaleRation = typedArray.getFloat(R.styleable.ThumbnailMenu_scale_ratio, scaleRation); + scaleRation = scaleRation >= 1.f ? 1.f : scaleRation; + scaleRation = scaleRation <= .1f ? .1f : scaleRation; + typedArray.recycle(); - TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ThumbnailMenu); - direction = typedArray.getInt(R.styleable.ThumbnailMenu_menu_direction, direction); - scaleRation = typedArray.getFloat(R.styleable.ThumbnailMenu_scale_ratio, scaleRation); - scaleRation = scaleRation >= 1.f ? 1.f : scaleRation; - scaleRation = scaleRation <= .1f ? .1f : scaleRation; - typedArray.recycle(); + init(); + } - init(); - } + private void init() { - private void init() { - isOpen = false; - objects = new ArrayList(); - tranLayoutList = new ArrayList<>(); + objects = new ArrayList(); + tranLayoutList = new ArrayList<>(); - thumbnailMenuChooser = new ThumbnailMenuChooser(); - factory = new ThumbnailFactory(); - } + thumbnailMenuChooser = new ThumbnailMenuChooser(); + factory = new ThumbnailFactory(); + } - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - super.onLayout(changed, left, top, right, bottom); - if (init) { - thumScrollLayout = factory.createMenuContainer(getContext(), direction); - thumScrollLayout.setTag(TAG_SCROLL_LAYOUT); - thumScrollLayout.setVisibility(View.GONE); - addView(thumScrollLayout); - - thumbnailAnimator = new ThumbnailAnimator(direction, this, tranLayoutList); - buildingModels(); - - init = false; - } + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + if (init) { + thumScrollLayout = factory.createMenuContainer(getContext(), direction); + thumScrollLayout.setTag(TAG_SCROLL_LAYOUT); + addView(thumScrollLayout, 0); + + thumbnailAnimator = new ThumbnailAnimator(direction, this, tranLayoutList); + buildingModels(); + + init = false; + } + } + + /** + * 绑定页面适配器 + * + * @param adapter + */ + public void setAdapter(PagerAdapter adapter) { + if (pageAdapter != null) { + pageAdapter.startUpdate(this); + for (int i = 0; i < adapter.getCount(); i++) { + pageAdapter.destroyItem((ViewGroup) getChildAt(i), i, objects.get(i)); + } + pageAdapter.finishUpdate(this); } - /** - * 绑定页面适配器 - * - * @param adapter - */ - public void setAdapter(PagerAdapter adapter) { - if (pageAdapter != null) { - pageAdapter.startUpdate(this); - for (int i = 0; i < adapter.getCount(); i++) { - pageAdapter.destroyItem((ViewGroup) getChildAt(i + 1), i, objects.get(i)); - } - pageAdapter.finishUpdate(this); - } + pageAdapter = adapter; + pageCount = pageAdapter.getCount(); - pageAdapter = adapter; - pageCount = pageAdapter.getCount(); - - LayoutParams layoutParams = new LayoutParams(MATCH_PARENT, MATCH_PARENT); - for (int i = 0; i < pageCount; i++) { - TransitionLayout frameLayout = new TransitionLayout(getContext()); - frameLayout.setId(i + 1);// id 不能为0 - frameLayout.setLayoutParams(layoutParams); - frameLayout.setOnClickListener(thumbnailMenuChooser); - addView(frameLayout); - tranLayoutList.add(0, frameLayout); // 倒序添加 - } + pageAdapter.startUpdate(this); - for (int i = 0; i < pageCount; i++) { - Object object = pageAdapter.instantiateItem((ViewGroup) getChildAt(i + 1), i); - objects.add(object); - } - pageAdapter.finishUpdate(this); - } + LayoutParams layoutParams = new LayoutParams(MATCH_PARENT, MATCH_PARENT); + for (int i = 0; i < pageCount; i++) { + TransitionLayout frameLayout = new TransitionLayout(getContext()); + frameLayout.setId(i + 1);// id 不能为0 + frameLayout.setLayoutParams(layoutParams); + addView(frameLayout); + tranLayoutList.add(0, frameLayout); // 倒序添加 - /** - * 获取缩略图菜单容器中的 ScrollView 中唯一 ViewGroup [这里是LinearLayout] - * - * @return - */ - public ThumbnailContainer getThumContainner() { - return (ThumbnailContainer) thumScrollLayout.getChildAt(0); + Object object = pageAdapter.instantiateItem(frameLayout, i); + objects.add(object); } - - /** - * 创建 modelCount 数量的缩略图模型添加到缩略图菜单容器中 - */ - private void buildingModels() { - final ThumbnailContainer containerLayout = getThumContainner(); - containerLayout.removeAllViews(); - - for (int i = 0; i < pageCount; i++) { - ThumbnailContainer.LayoutParams containerLayoutParams = new ThumbnailContainer.LayoutParams( - (int) (getWidth() * scaleRation), (int) (getHeight() * scaleRation)); - if (i != 0) { - if (direction == ThumbnailFactory.MENU_DIRECTION_BOTTOM) { - containerLayoutParams.leftMargin = THUM_MARGIN; - } else { - containerLayoutParams.topMargin = THUM_MARGIN; - } - } - - if (direction == ThumbnailFactory.MENU_DIRECTION_BOTTOM) { - containerLayoutParams.topMargin = getHeight() - containerLayoutParams.height; - } - if (direction == ThumbnailFactory.MENU_DIRECTION_RIGHT) { - containerLayoutParams.leftMargin = getWidth() - containerLayoutParams.width; - } - - FrameLayout modelLayout = new FrameLayout(getContext()); - modelLayout.setTag(i); - containerLayout.addView(modelLayout, containerLayoutParams); + pageAdapter.finishUpdate(this); + } + + /** + * 获取缩略图菜单容器中的 ScrollView 中唯一 ViewGroup [这里是LinearLayout] + * + * @return + */ + public ThumbnailContainer getThumContainner() { + return (ThumbnailContainer) thumScrollLayout.getChildAt(0); + } + + /** + * 创建 modelCount 数量的缩略图模型添加到缩略图菜单容器中 + */ + private void buildingModels() { + final ThumbnailContainer containerLayout = getThumContainner(); + containerLayout.removeAllViews(); + + for (int i = 0; i < pageCount; i++) { + ThumbnailContainer.LayoutParams containerLayoutParams = new ThumbnailContainer.LayoutParams( + (int) (getWidth() * scaleRation), (int) (getHeight() * scaleRation)); + if (i != 0) { + if (direction == ThumbnailFactory.MENU_DIRECTION_BOTTOM) { + containerLayoutParams.leftMargin = THUM_MARGIN; + } else { + containerLayoutParams.topMargin = THUM_MARGIN; } + } + + if (direction == ThumbnailFactory.MENU_DIRECTION_BOTTOM) { + containerLayoutParams.topMargin = getHeight() - containerLayoutParams.height; + } + if (direction == ThumbnailFactory.MENU_DIRECTION_RIGHT) { + containerLayoutParams.leftMargin = getWidth() - containerLayoutParams.width; + } + + ThumbnailView modelLayout = new ThumbnailView(getContext()); + modelLayout.setTag(i); + modelLayout.setTransitionLayout(tranLayoutList.get(i)); + modelLayout.setOnClickListener(thumbnailMenuChooser); + containerLayout.addView(modelLayout, containerLayoutParams); } - - /** - * 打开菜单 - */ - public void openMenu() { - if (!isOpen) { - isOpen = true; - thumbnailAnimator.openMenuAnimator(); - } + } + + /** + * 打开菜单 + */ + public void openMenu() { + if (!isOpen()) { + thumbnailAnimator.openMenuAnimator(); } - - /** - * 关闭菜单 - * - * @param transitionLayout - */ - private void closeMenu(TransitionLayout transitionLayout) { - if (isOpen) { - isOpen = false; - thumbnailAnimator.closeMenuAnimator(transitionLayout, menuCloseListener); - } + } + + /** + * 关闭菜单 + * + * @param transitionLayout + */ + private void closeMenu(TransitionLayout transitionLayout) { + if (isOpen()) { + thumbnailAnimator.closeMenuAnimator(transitionLayout, menuCloseListener); } - - /** - * 菜单是否打开 - * - * @return - */ - public boolean isOpen() { - return isOpen; + } + + /** + * 菜单是否打开 + * + * @return + */ + public boolean isOpen() { + if (thumbnailAnimator == null) { + return false; } + return thumbnailAnimator.isOpen(); + } - /** - * 返回缩略图缩放的比率 - * - * @return - */ - public float getScaleRatio() { - return scaleRation; - } + /** + * 返回缩略图缩放的比率 + * + * @return + */ + public float getScaleRatio() { + return scaleRation; + } - public void setOnMenuCloseListener(OnThumbnailMenuCloseListener menuCloseListener) { - this.menuCloseListener = menuCloseListener; - } + public void setOnMenuCloseListener(OnThumbnailMenuCloseListener menuCloseListener) { + this.menuCloseListener = menuCloseListener; + } - public interface OnThumbnailMenuCloseListener { - void onMenuCloseListener(); - } + public interface OnThumbnailMenuCloseListener { + void onMenuCloseListener(); + } - private class ThumbnailMenuChooser implements OnClickListener { + private class ThumbnailMenuChooser implements OnClickListener { - @Override - public void onClick(View view) { - if (isOpen && view instanceof TransitionLayout) { - TransitionLayout choosenLayout = (TransitionLayout) view; - closeMenu(choosenLayout); - } - } + @Override + public void onClick(View view) { + if (view instanceof ThumbnailView) { + TransitionLayout choosenLayout = ((ThumbnailView) view).getTransitionLayout(); + closeMenu(choosenLayout); + } } + } + + @Override + public void bringChildToFront(View child) { + ViewGroup.LayoutParams layoutParams = child.getLayoutParams(); + detachViewFromParent(child); + attachViewToParent(child, -1, layoutParams); + child.setClickable(true);//防止事件透传 + invalidate(); + } + + public void takeChildToBehind(View child) { + ViewGroup.LayoutParams layoutParams = child.getLayoutParams(); + detachViewFromParent(child); + attachViewToParent(child, 0, layoutParams); + invalidate(); + } + } diff --git a/tmlibrary/src/main/java/com/hitomi/tmlibrary/ThumbnailView.java b/tmlibrary/src/main/java/com/hitomi/tmlibrary/ThumbnailView.java new file mode 100644 index 0000000..ed8041c --- /dev/null +++ b/tmlibrary/src/main/java/com/hitomi/tmlibrary/ThumbnailView.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2016 Baidu, Inc. All Rights Reserved. + */ +package com.hitomi.tmlibrary; + +import android.content.Context; +import android.graphics.Canvas; +import android.util.AttributeSet; +import android.view.View; + +/** + * Created by LukeSkywalker on 2016/9/29. + */ +public class ThumbnailView extends TransitionLayout { + private TransitionLayout mTransitionLayout; + + public ThumbnailView(Context context) { + super(context); + } + + public ThumbnailView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public ThumbnailView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + public void setTransitionLayout(TransitionLayout transitionLayout) { + mTransitionLayout = transitionLayout; + removeAllViews(); + View mView = new View(getContext()); + addView(mView); + } + + public TransitionLayout getTransitionLayout() { + return mTransitionLayout; + } + + @Override + protected boolean drawChild(Canvas canvas, View child, long drawingTime) { + if (mTransitionLayout != null) { + float sw = getMeasuredWidth() / (float) mTransitionLayout.getWidth(); + float sh = getMeasuredHeight() / (float) mTransitionLayout.getHeight(); + canvas.scale(sw, sh); + mTransitionLayout.draw(canvas); + } + return super.drawChild(canvas, child, drawingTime); + } +} diff --git a/tmlibrary/src/main/java/com/hitomi/tmlibrary/TransitionLayout.java b/tmlibrary/src/main/java/com/hitomi/tmlibrary/TransitionLayout.java index ab91b98..8b92f09 100644 --- a/tmlibrary/src/main/java/com/hitomi/tmlibrary/TransitionLayout.java +++ b/tmlibrary/src/main/java/com/hitomi/tmlibrary/TransitionLayout.java @@ -1,8 +1,10 @@ +/* + * Copyright (C) 2016 Baidu, Inc. All Rights Reserved. + */ package com.hitomi.tmlibrary; import android.content.Context; import android.util.AttributeSet; -import android.view.View; import android.widget.FrameLayout; /** @@ -11,8 +13,6 @@ */ public class TransitionLayout extends FrameLayout { - private final View view; - public TransitionLayout(Context context) { this(context, null); } @@ -23,8 +23,6 @@ public TransitionLayout(Context context, AttributeSet attrs) { public TransitionLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); - - view = getChildAt(0); } }