package com.smartisanos.sidebar.view; import android.content.Context; import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.view.DragEvent; import android.view.LayoutInflater; import android.view.View; import android.view.ViewTreeObserver; import android.widget.AdapterView; import android.widget.ListAdapter; import android.widget.ListView; import com.smartisanos.sidebar.R; import com.smartisanos.sidebar.SidebarController; import com.smartisanos.sidebar.util.BitmapUtils; import com.smartisanos.sidebar.util.LOG; import com.smartisanos.sidebar.util.SidebarItem; 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 java.util.ArrayList; import java.util.List; public class SidebarListView extends ListView { private static final LOG log = LOG.getInstance(SidebarListView.class); private boolean mNeedDivider = true; private View mDivider; private SideView mSideView; private SidebarAdapter mAdapter; private SidebarItem mDraggedItem; private int mDragPosition = -1; private int mUnDragNumber = 0; private AnimTimeLine mDatasetChangeTimeLine; private AnimListener mListener = new AnimListener() { @Override public void onStart() { } @Override public void onComplete(int type) { if(mAdapter != null) { mAdapter.updateData(); } } }; public SidebarListView(Context context) { this(context, null); } public SidebarListView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public SidebarListView(Context context, AttributeSet attrs, int defStyleAttr) { this(context, attrs, defStyleAttr, 0); } public SidebarListView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); mDivider = LayoutInflater.from(context).inflate(R.layout.sidebar_view_divider, null); setOnItemLongClickListener(mOnLongClickListener); } public void setSideView(SideView view) { mSideView = view; } @Override public void setAdapter(ListAdapter adapter) { super.setAdapter(adapter); if (adapter != null && adapter instanceof SidebarAdapter) { mAdapter = (SidebarAdapter) adapter; } } public void onDragStart(DragEvent event) { if (mAdapter != null) { mAdapter.onDragStart(event); } } public void onDragEnd() { if (mAdapter != null) { mAdapter.onDragEnd(); } } private AdapterView.OnItemLongClickListener mOnLongClickListener = new AdapterView.OnItemLongClickListener() { @Override public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { if (position < getHeaderViewsCount() + mUnDragNumber || position >= getChildCount() - getFooterViewsCount()) { return false; } int[] viewLoc = new int[2]; view.getLocationOnScreen(viewLoc); viewLoc[0] = viewLoc[0] + view.getWidth() / 2; viewLoc[1] = viewLoc[1] + view.getHeight() / 2; mDraggedItem = (SidebarItem) SidebarListView.this.getAdapter().getItem(position); if (mDraggedItem == null) { // see ticket 136616 http://mantis.smartisan.cn/view.php?id=136616 log.error("mDraggedItem == null ! position -> " + position + ", count -> " + SidebarListView.this.getAdapter().getCount()); } mDragPosition = position; //Drawable icon = mDraggedItem.getAvatar(); Drawable icon = new BitmapDrawable(mContext.getResources(), BitmapUtils.drawableToBitmap(mDraggedItem.getAvatar())); SidebarController.getInstance(mContext).getSidebarRootView().startDrag(icon, view, viewLoc); mSideView.setDraggedList(SidebarListView.this); view.setVisibility(View.INVISIBLE); AnimStatusManager.getInstance().setStatus(AnimStatusManager.SIDEBAR_ITEM_DRAGGING, true); return false; } }; public SidebarItem getDraggedItem() { return mDraggedItem; } public void deleteDraggedSidebarItem() { if (mDraggedItem != null) { mDraggedItem.delete(); dragEnd(); } } public void dropBackSidebarItem() { if (mDraggedItem != null) { if (mAdapter != null) { mAdapter.moveItemPostion(mDraggedItem, mDragPosition - this.getHeaderViewsCount()); } dragEnd(); } } private void dragEnd() { mDragPosition = -1; mDraggedItem = null; AnimStatusManager.getInstance().setStatus(AnimStatusManager.SIDEBAR_ITEM_DRAGGING, false); } private int[] convertToLocalCoordinate(int x, int y, Rect drawingRect) { int[] viewLoc = new int[2]; getLocationOnScreen(viewLoc); int[] loc = new int[2]; loc[0] = x - viewLoc[0]; loc[1] = y - viewLoc[1]; loc[0] = loc[0] + drawingRect.left; loc[1] = loc[1] + drawingRect.top; return loc; } public void dragObjectMove(int rawX, int rawY) { if (Utils.inArea(rawX, rawY, this)) { int count = getAdapter().getCount() - getHeaderViewsCount() - getFooterViewsCount(); if (count > 0) { // convert global coordinate to view local coordinate Rect drawingRect = new Rect(); getDrawingRect(drawingRect); int[] localLoc = convertToLocalCoordinate(rawX, rawY, drawingRect); int subViewHeight = drawingRect.bottom / getChildCount(); int position = localLoc[1] / subViewHeight; pointToNewPositionWithAnim(position); } } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST); super.onMeasure(widthMeasureSpec, expandSpec); } public void setNeedFootView(boolean needFootView) { if (needFootView != mNeedDivider) { mNeedDivider = needFootView; requestLayout(); } } @Override public void requestLayout() { super.requestLayout(); if (mDivider == null) { // this means the construcor is going on ! return; } ListAdapter adapter = this.getAdapter(); if (adapter != null && adapter.getCount() == getHeaderViewsCount()) { // we are empty actually.. removeHeaderView(mDivider); return; } if (mNeedDivider) { if (getHeaderViewsCount() == 0) { addHeaderView(mDivider); } } else { if (getHeaderViewsCount() > 0) { removeHeaderView(mDivider); } } } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); getViewTreeObserver().addOnGlobalLayoutListener(mAddItemWithAnimListener); } public void animWhenDatasetChange() { if(mDatasetChangeTimeLine != null && mDatasetChangeTimeLine.isRunning()) { mDatasetChangeTimeLine.cancel(); } int time = 200; mDatasetChangeTimeLine = new AnimTimeLine(); ListAdapter adapter = getAdapter(); if (adapter != null) { for (int i = 0; i < adapter.getCount(); ++i) { Object obj = adapter.getItem(i); View view = getChildAt(i); if(view == null) { continue; } if (obj != null && obj instanceof SidebarItem) { SidebarItem item = (SidebarItem) obj; if (item.newAdded) { item.newAdded = false; Anim alphaAnim = new Anim(view, Anim.TRANSPARENT, time, Anim.CUBIC_OUT, new Vector3f(), new Vector3f(0, 0, 1)); Anim scaleBigAnim = new Anim(view, Anim.SCALE, time, Anim.CUBIC_OUT, new Vector3f(0.3f, 0.3f), new Vector3f( 1.2f, 1.2f)); Anim scaleNormal = new Anim(view, Anim.SCALE, time, Anim.CUBIC_OUT, new Vector3f(1.2f, 1.2f), new Vector3f( 1, 1)); scaleNormal.setDelay(time); mDatasetChangeTimeLine.addAnim(alphaAnim); mDatasetChangeTimeLine.addAnim(scaleBigAnim); mDatasetChangeTimeLine.addAnim(scaleNormal); } else if(item.newRemoved) { item.newRemoved = false; Anim alphaAnim = new Anim(view, Anim.TRANSPARENT, time, Anim.CUBIC_OUT, new Vector3f(0, 0, 1), new Vector3f()); Anim scaleBigAnim = new Anim(view, Anim.SCALE, time, Anim.CUBIC_OUT, new Vector3f(1.0f, 1.0f), new Vector3f( 0.3f, 0.3f)); mDatasetChangeTimeLine.addAnim(alphaAnim); mDatasetChangeTimeLine.addAnim(scaleBigAnim); } else { view.setAlpha(1.0f); view.setScaleX(1.0f); view.setScaleY(1.0f); } } } } if (mListener != null) { if (mDatasetChangeTimeLine.getAnimList() == null || mDatasetChangeTimeLine.getAnimList().size() == 0) { mListener.onComplete(0); } else { mDatasetChangeTimeLine.setAnimListener(mListener); } } mDatasetChangeTimeLine.start(); } private ViewTreeObserver.OnGlobalLayoutListener mAddItemWithAnimListener = new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { getViewTreeObserver().removeOnGlobalLayoutListener(this); animWhenDatasetChange(); } }; public void setUnDragNumber(int unDragNumber) { mUnDragNumber = unDragNumber; } private void pointToNewPositionWithAnim(int position) { int headViewCount = getHeaderViewsCount(); int count = getCount() - getFooterViewsCount() - headViewCount; if (position < this.getHeaderViewsCount() + mUnDragNumber || position >= this.getChildCount() - this.getFooterViewsCount() || mDragPosition == position) { return ; } int begin = headViewCount; int end = begin + count; // check invisible count int invisibleViewCount = 0; for (int i = begin; i < end; i++) { View view = getChildAt(i); if (view.getVisibility() != View.VISIBLE) { invisibleViewCount++; } } if (invisibleViewCount != 1) { for (int i = begin; i < end; i++) { View view = getChildAt(i); if (view.getVisibility() == View.INVISIBLE) { log.error("dump INVISIBLE VIEW " + view); } } if (invisibleViewCount != 1) { for (int i = begin; i < end; i++) { View view = getChildAt(i); if (view.getVisibility() == View.INVISIBLE) { log.error("dump INVISIBLE VIEW " + view); } } } throw new IllegalArgumentException("invisibleViewCount != 1"); } mDragPosition = position; position -= this.getHeaderViewsCount(); View[] viewArr = new View[count]; int index = 0; for (int i = begin; i < end; i++) { View view = getChildAt(i); if (view.getVisibility() == View.INVISIBLE) { viewArr[position] = view; } else { if (index == position) { index++; } viewArr[index++] = view; } } AnimTimeLine moveAnimTimeLine = new AnimTimeLine(); int toY = 0; for (int i = 0; i < headViewCount; ++i) { toY += getChildAt(i).getHeight(); } for (int i = 0; i < viewArr.length; i++) { View view = viewArr[i]; int fromY = (int) view.getY(); if (fromY != toY) { Vector3f from = new Vector3f(0, fromY); Vector3f to = new Vector3f(0, toY); Anim anim = new Anim(view, Anim.TRANSLATE, 200, Anim.CUBIC_OUT, from, to); moveAnimTimeLine.addAnim(anim); } toY += view.getHeight(); } moveAnimTimeLine.start(); } public List<View> getViewList() { List<View> views = new ArrayList<View>(); int count = getChildCount(); for (int i = 0; i < count; i++) { View view = getChildAt(i); if (view == null) { continue; } views.add(view); } return views; } }