package com.smartisanos.sidebar.view; import android.content.Context; import android.content.res.Resources; import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewTreeObserver; import android.view.animation.Animation; import android.view.animation.Transformation; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import com.smartisanos.sidebar.SidebarController; import com.smartisanos.sidebar.SidebarMode; import com.smartisanos.sidebar.SidebarStatus; import com.smartisanos.sidebar.util.LOG; import com.smartisanos.sidebar.util.Utils; import com.smartisanos.sidebar.util.anim.Anim; import com.smartisanos.sidebar.util.anim.AnimListener; import com.smartisanos.sidebar.util.anim.AnimStatusManager; import com.smartisanos.sidebar.util.anim.AnimTimeLine; import com.smartisanos.sidebar.util.anim.Vector3f; import com.smartisanos.sidebar.R; public class SidebarRootView extends FrameLayout { private static final LOG log = LOG.getInstance(SidebarRootView.class); private Context mContext; private DragView mDragView; private SideView mSideView; private int sidebarWidth; private Trash mTrash; public SidebarRootView(Context context) { this(context, null); } public SidebarRootView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public SidebarRootView(Context context, AttributeSet attrs, int defStyleAttr) { this(context, attrs, defStyleAttr, 0); } public SidebarRootView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); mContext = context; sidebarWidth = mContext.getResources().getDimensionPixelSize(R.dimen.sidebar_width); } @Override protected void onFinishInflate() { mSideView = (SideView) findViewById(R.id.sidebar); mTrash = new Trash(mContext, (ImageView) findViewById(R.id.trash_with_shadow), (ImageView) findViewById(R.id.trash_foreground)); } public void requestStatus(SidebarStatus status) { mSideView.requestStatus(status); } public Trash getTrash() { return mTrash; } public class DragView { public View mListViewItem; private Drawable mIcon; public final View mView; public final ImageView mDragViewIcon; public final TextView mBubbleText; public DragView(Context context, Drawable icon, View view, int[] loc) { mView = LayoutInflater.from(context).inflate(R.layout.drag_view, null); LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); mView.setLayoutParams(params); mIcon = icon; mListViewItem = view; mDragViewIcon = (ImageView) mView.findViewById(R.id.drag_view_icon); mDragViewIcon.setBackground(mIcon); mBubbleText = (TextView) mView.findViewById(R.id.drag_view_bubble_text); mBubbleText.setText(getDisplayName()); mView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { mView.getViewTreeObserver().removeOnGlobalLayoutListener(this); Anim bubbleAlpha = new Anim(mBubbleText, Anim.TRANSPARENT, 100, Anim.CUBIC_OUT, new Vector3f(), new Vector3f(0, 0, 1)); bubbleAlpha.start(); int[] screenLoc = new int[2]; mListViewItem.getLocationOnScreen(screenLoc); int realIconWidth = mListViewItem.getWidth(); int realIconHeight = mListViewItem.getHeight(); int deltaX = mView.getWidth() / 2 - realIconWidth / 2; int deltaY = mDragViewIcon.getHeight() / 2 - realIconHeight / 2; int x = screenLoc[0] - deltaX; int y = screenLoc[1] - mBubbleText.getHeight() - deltaY; mView.setTranslationX(x); mView.setTranslationY(y); mView.setVisibility(View.VISIBLE); } }); } public CharSequence getDisplayName() { return mSideView.getDraggedListView().getDraggedItem().getDisplayName(); } public void delelte(){ mSideView.getDraggedListView().deleteDraggedSidebarItem(); } public void backToPostion() { mListViewItem.setVisibility(View.VISIBLE); mSideView.getDraggedListView().dropBackSidebarItem(); } public void setBubbleVisibleStatus(int visible) { if (mBubbleText != null) { mBubbleText.setVisibility(visible); } } public void hideBubble() { if (mBubbleText != null) { mBubbleText.setVisibility(View.GONE); } } public void move(float touchX, float touchY) { if (mView.getVisibility() != View.VISIBLE) { return; } int x = (int) (touchX - mView.getWidth() / 2); int y = (int) (touchY - mDragViewIcon.getHeight() / 2 - mBubbleText.getHeight()); mView.setTranslationX(x); mView.setTranslationY(y); } public void showView() { mView.setVisibility(View.INVISIBLE); addView(mView); } public void removeView() { mView.setVisibility(View.GONE); SidebarRootView.this.removeView(mView); } } private class ShowDragViewWhenRelayout implements ViewTreeObserver.OnGlobalLayoutListener { private Drawable iconOrig; public View mListViewItem; private int[] mLoc; public ShowDragViewWhenRelayout(Drawable icon, View view, int[] loc) { iconOrig = icon; mListViewItem = view; mLoc = loc; } @Override public void onGlobalLayout() { getViewTreeObserver().removeOnGlobalLayoutListener(this); mDragging = true; mDragView = new DragView(mContext, iconOrig, mListViewItem, mLoc); mDragView.showView(); mTrash.trashAppearWithAnim(); mShowDragViewWhenRelayout = null; } } private boolean mDragging = false; private ShowDragViewWhenRelayout mShowDragViewWhenRelayout; public void startDrag(Drawable icon, View view, int[] loc) { if(mDragging || mShowDragViewWhenRelayout != null){ return ; } mShowDragViewWhenRelayout = new ShowDragViewWhenRelayout(icon, view, loc); getViewTreeObserver().addOnGlobalLayoutListener(mShowDragViewWhenRelayout); //set sidebar to full screen SidebarController.getInstance(mContext).updateDragWindow(true); } private boolean mDragDeleting = false; public void deleteDrag(){ if (!mDragging) { return; } int trashLocX = (int) mTrash.mTrashView.getTranslationX(); int trashLocY = (int) mTrash.mTrashView.getTranslationY(); mTrash.mTrashForegroundView.setTranslationX(trashLocX); mTrash.mTrashForegroundView.setTranslationY(trashLocY); mTrash.mTrashForegroundView.setVisibility(View.VISIBLE); setChildrenDrawingOrderEnabled(true); requestLayout(); View view = mDragView.mView; Vector3f from = new Vector3f(0, view.getY()); Vector3f to = new Vector3f(0, mTrash.mTrashView.getY() + 20); Anim anim = new Anim(view, Anim.TRANSLATE, 150, Anim.CUBIC_OUT, from, to); anim.setListener(new AnimListener() { @Override public void onStart() { mDragDeleting = true; } @Override public void onComplete(int type) { mDragDeleting = false; mDragging = false; mDragView.removeView(); setChildrenDrawingOrderEnabled(false); mTrash.trashDisappearWithAnim(new Runnable() { @Override public void run() { SidebarController.getInstance(mContext).updateDragWindow(false); } }); } }); anim.start(); } private class DropAnim extends Animation { private DragView mDrag; private View view; private float scaleTo; private int[] moveFrom; private int[] moveTo; public DropAnim(DragView drag) { mDrag = drag; mDrag.hideBubble(); view = mDrag.mView; moveFrom = new int[2]; moveTo = new int[2]; ImageView icon = mDragView.mDragViewIcon; icon.getLocationOnScreen(moveFrom); mDragView.mListViewItem.getLocationOnScreen(moveTo); Resources resources = mContext.getResources(); //list item has padding top, so set real loc Y moveTo[1] = moveTo[1] + resources.getDimensionPixelSize(R.dimen.sidebar_list_item_padding_top); int dragViewSize = resources.getDimensionPixelSize(R.dimen.drag_view_icon_size); int itemViewSize = resources.getDimensionPixelSize(R.dimen.sidebar_list_item_img_size); scaleTo = (float) ((1.0 * itemViewSize) / (1.0 * dragViewSize)); } @Override protected void applyTransformation(float interpolatedTime, Transformation t) { float scale = (1 - scaleTo) * (1 - interpolatedTime) + scaleTo; view.setScaleX(scale); view.setScaleY(scale); int deltaX = moveTo[0] - moveFrom[0]; int deltaY = moveTo[1] - moveFrom[1]; int x = (int) (deltaX * interpolatedTime + moveFrom[0]); int y = (int) (deltaY * interpolatedTime + moveFrom[1]); view.setTranslationX(x); view.setTranslationY(y); if (interpolatedTime == 1) { cancel(); complete(); } } private void complete() { mDragging = false; mDragDroping = false; mDragView.backToPostion(); mDragView.removeView(); SidebarController.getInstance(mContext).updateDragWindow(false); } } private boolean mDragDroping = false; public void dropDrag() { if (!mDragging) { return; } if (mDragView == null) { log.error("dropDrag return by mDragView is null"); return; } mDragDroping = true; //calculate icon loc, bubble will hide, move icon to right loc int[] iconLoc = new int[2]; int deltaX = (mDragView.mView.getWidth() - mDragView.mDragViewIcon.getWidth()) / 2; int deltaY = mDragView.mView.getHeight() - mDragView.mDragViewIcon.getHeight(); mDragView.mView.getLocationOnScreen(iconLoc); iconLoc[0] = iconLoc[0] + deltaX; iconLoc[1] = iconLoc[1] + deltaY; mDragView.mView.setTranslationX(iconLoc[0]); mDragView.mView.setTranslationY(iconLoc[1]); mDragView.hideBubble(); final ViewTreeObserver observer = mDragView.mView.getViewTreeObserver(); observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { observer.removeOnGlobalLayoutListener(this); DropAnim anim = new DropAnim(mDragView); anim.setDuration(200); mDragView.mView.startAnimation(anim); } }); } public DragView getDraggedView() { if(!mDragging){ return null; } return mDragView; } private final boolean ENABLE_TOUCH_LOG = false; @Override public boolean dispatchTouchEvent(MotionEvent ev) { if (mDragDroping || mDragDeleting) { // ignore ! return true; } if (mDragging) { precessTouch(ev); return true; } if (ev.getAction() == MotionEvent.ACTION_DOWN) { if (processResumeSidebar()) { return true; } } return super.dispatchTouchEvent(ev); } private boolean processResumeSidebar() { if (SidebarController.getInstance(mContext).getCurrentContentType() != ContentView.ContentType.NONE) { log.error("processResumeSidebar !"); Utils.resumeSidebar(mContext); return true; } return false; } private void precessTouch(MotionEvent event) { int action = event.getAction(); int x = (int) event.getRawX(); int y = (int) event.getRawY(); long eventTime = event.getEventTime(); switch (action) { case MotionEvent.ACTION_DOWN : { if (ENABLE_TOUCH_LOG) log.error("ACTION_DOWN"); break; } case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP : { if (ENABLE_TOUCH_LOG) log.error("ACTION_UP"); if (mTrash.dragObjectUpOnUp(x, y, mDragView)) { //handle uninstall } else { dropDrag(); mTrash.trashDisappearWithAnim(null); } if (mDragView != null) { // we need action_update to stop scroll ! mSideView.dragObjectMove(event, eventTime); } break; } case MotionEvent.ACTION_MOVE : { if (ENABLE_TOUCH_LOG) log.error("ACTION_MOVE"); if (mDragView != null) { mDragView.move(x, y); mSideView.dragObjectMove(event, eventTime); mTrash.dragObjectMoveTo(x, y); } break; } case MotionEvent.ACTION_SCROLL : { if (ENABLE_TOUCH_LOG) log.error("ACTION_SCROLL"); break; } } } //force stop drag ! public void stopDrag() { if (mDragging) { mDragging = false; mDragDeleting = false; mDragDroping = false; mDragView.backToPostion(); mDragView.removeView(); mTrash.dismissDialog(); SidebarController.getInstance(mContext).updateDragWindow(false); } } public void show(boolean show){ if(show){ if (mExitAnimTimeLine != null) { log.error("mExitAnimTimeLine not null"); mExitAnimTimeLine.cancel(); } setAlpha(0); setVisibility(View.VISIBLE); final ViewTreeObserver observer = getViewTreeObserver(); observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { observer.removeOnGlobalLayoutListener(this); doAnimWhenEnter(); } }); }else{ if (mEnterAnimTimeLine != null) { mEnterAnimTimeLine.cancel(); } doAnimWhenExit(); } } private AnimTimeLine mEnterAnimTimeLine = null; private void doAnimWhenEnter() { final View shadowView = mSideView.getShadowLineView(); if (shadowView != null) { shadowView.setAlpha(0); } boolean isLeft = SidebarController.getInstance(mContext).getSidebarMode() == SidebarMode.MODE_LEFT; int delta = sidebarWidth; int fromX = isLeft ? -delta : delta; int time = 150; Vector3f alphaFrom = new Vector3f(); Vector3f alphaTo = new Vector3f(0, 0, 1); Anim moveAnim = new Anim(this, Anim.MOVE, time, 0, new Vector3f(fromX, 0), new Vector3f()); Anim alphaAnim = new Anim(this, Anim.TRANSPARENT, time, Anim.CUBIC_OUT, alphaFrom, alphaTo); mSideView.setVisibility(View.INVISIBLE); Anim showShadowBg = new Anim(mSideView, Anim.TRANSPARENT, 200, Anim.CUBIC_OUT, alphaFrom, alphaTo); showShadowBg.setListener(new AnimListener() { @Override public void onStart() { mSideView.setVisibility(View.VISIBLE); } @Override public void onComplete(int type) { mSideView.setAlpha(1); } }); showShadowBg.setDelay(100); showShadowBg.start(); mEnterAnimTimeLine = new AnimTimeLine(); mEnterAnimTimeLine.addAnim(moveAnim); mEnterAnimTimeLine.addAnim(alphaAnim); mEnterAnimTimeLine.setAnimListener(new AnimListener() { @Override public void onStart() { AnimStatusManager.getInstance().setStatus(AnimStatusManager.ON_SIDE_VIEW_ENTER, true); } @Override public void onComplete(int type) { if (mEnterAnimTimeLine != null) { AnimStatusManager.getInstance().setStatus(AnimStatusManager.ON_SIDE_VIEW_ENTER, false); mSideView.setBackgroundResource(R.drawable.background); //setBackgroundResource(R.color.sidebar_root_background); setAlpha(1); setTranslationX(0); if (shadowView != null) { if (type != Anim.ANIM_FINISH_TYPE_CANCELED) { Anim alphaAnim = new Anim(shadowView, Anim.TRANSPARENT, 50, Anim.CUBIC_OUT, new Vector3f(), new Vector3f(0, 0, 1)); alphaAnim.setListener(new AnimListener() { @Override public void onStart() { } @Override public void onComplete(int type) { shadowView.setAlpha(1); } }); alphaAnim.start(); } else { shadowView.setAlpha(1); } } mEnterAnimTimeLine = null; } } }); mEnterAnimTimeLine.start(); } private AnimTimeLine mExitAnimTimeLine = null; private void doAnimWhenExit() { mSideView.setBackgroundResource(android.R.color.transparent); final View shadowView = mSideView.getShadowLineView(); if (shadowView != null) { shadowView.setVisibility(INVISIBLE); } mExitAnimTimeLine = new AnimTimeLine(); boolean isLeft = SidebarController.getInstance(mContext).getSidebarMode() == SidebarMode.MODE_LEFT; int delta = sidebarWidth; int toX = isLeft ? -delta : delta; int time = 200; Anim moveAnim = new Anim(this, Anim.MOVE, time, Anim.CUBIC_OUT, new Vector3f(), new Vector3f(toX, 0)); Anim alphaAnim = new Anim(this, Anim.TRANSPARENT, time, 0, new Vector3f(0, 0, 1), new Vector3f()); mExitAnimTimeLine.addAnim(moveAnim); mExitAnimTimeLine.addAnim(alphaAnim); mExitAnimTimeLine.setAnimListener(new AnimListener() { @Override public void onStart() { AnimStatusManager.getInstance().setStatus(AnimStatusManager.ON_SIDE_VIEW_EXIT, true); } @Override public void onComplete(int type) { if (mExitAnimTimeLine != null) { AnimStatusManager.getInstance().setStatus(AnimStatusManager.ON_SIDE_VIEW_EXIT, false); shadowView.setVisibility(VISIBLE); SidebarRootView.this.setAlpha(1); SidebarRootView.this.setTranslationX(0); setVisibility(View.GONE); stopDrag(); if (mSideView != null) { mSideView.restoreView(); } mExitAnimTimeLine = null; } } }); mExitAnimTimeLine.start(); } @Override protected int getChildDrawingOrder(int childCount, int index) { int id = getChildAt(index).getId(); if (index < childCount - 2) { return index; } if (id == R.id.trash_foreground) { // the most up view return (childCount - 1); } else {// dragview return (childCount - 2); } } public void setEnabled(boolean enabled) { mSideView.setEnabled(enabled); } }