package zrc.widget; import android.annotation.TargetApi; import android.content.Context; import android.database.DataSetObserver; import android.os.Build; import android.os.Parcelable; import android.util.AttributeSet; import android.util.SparseArray; import android.view.SoundEffectConstants; import android.view.View; import android.view.ViewGroup; import android.widget.Adapter; import zrc.util.APIUtil; import zrc.widget.ZrcListView.OnItemClickListener; import zrc.widget.ZrcListView.OnItemLongClickListener; abstract class ZrcAdapterView<T extends Adapter> extends ViewGroup { public static final int ITEM_VIEW_TYPE_IGNORE = -1; public static final int ITEM_VIEW_TYPE_HEADER_OR_FOOTER = -2; int mFirstPosition = 0; int mFirstTop = 0; boolean mInLayout = false; OnItemClickListener mOnItemClickListener; OnItemLongClickListener mOnItemLongClickListener; boolean mDataChanged; private View mEmptyView; int mItemCount; int mOldItemCount; public static final int INVALID_POSITION = -1; public static final long INVALID_ROW_ID = Long.MIN_VALUE; private boolean mDesiredFocusableState; private boolean mDesiredFocusableInTouchModeState; boolean mBlockLayoutRequests = false; public ZrcAdapterView(Context context) { super(context); } public ZrcAdapterView(Context context, AttributeSet attrs) { super(context, attrs); } public ZrcAdapterView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public void setOnItemClickListener(OnItemClickListener listener) { mOnItemClickListener = listener; } public final OnItemClickListener getOnItemClickListener() { return mOnItemClickListener; } public boolean performItemClick(View view, int position, long id) { if (mOnItemClickListener != null) { playSoundEffect(SoundEffectConstants.CLICK); mOnItemClickListener.onItemClick((ZrcListView)this, view, position, id); return true; } return false; } public void setOnItemLongClickListener(OnItemLongClickListener listener) { if (!isLongClickable()) { setLongClickable(true); } mOnItemLongClickListener = listener; } public final OnItemLongClickListener getOnItemLongClickListener() { return mOnItemLongClickListener; } public abstract T getAdapter(); public abstract void setAdapter(T adapter); @Override public void addView(View child) { throw new UnsupportedOperationException(); } @Override public void addView(View child, int index) { throw new UnsupportedOperationException(); } @Override public void addView(View child, LayoutParams params) { throw new UnsupportedOperationException(); } @Override public void addView(View child, int index, LayoutParams params) { throw new UnsupportedOperationException(); } @Override public void removeView(View child) { throw new UnsupportedOperationException(); } @Override public void removeViewAt(int index) { throw new UnsupportedOperationException(); } @Override public void removeAllViews() { throw new UnsupportedOperationException(); } public int getCount() { return mItemCount; } public int getPositionForView(View view) { View listItem = view; try { View v; while (!(v = (View) listItem.getParent()).equals(this)) { listItem = v; } } catch (ClassCastException e) { // We made it up to the window without find this list view return INVALID_POSITION; } // Search the children for the list item final int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { if (getChildAt(i).equals(listItem)) { return mFirstPosition + i; } } return INVALID_POSITION; } public int getFirstVisiblePosition() { return mFirstPosition; } public int getLastVisiblePosition() { return mFirstPosition + getChildCount() - 1; } @TargetApi(Build.VERSION_CODES.JELLY_BEAN) public void setEmptyView(View emptyView) { mEmptyView = emptyView; final T adapter = getAdapter(); final boolean empty = ((adapter == null) || adapter.isEmpty()); updateEmptyStatus(empty); } public View getEmptyView() { return mEmptyView; } @Override public void setFocusable(boolean focusable) { final T adapter = getAdapter(); final boolean empty = adapter == null || adapter.getCount() == 0; mDesiredFocusableState = focusable; if (!focusable) { mDesiredFocusableInTouchModeState = false; } super.setFocusable(focusable && (!empty)); } @Override public void setFocusableInTouchMode(boolean focusable) { final T adapter = getAdapter(); final boolean empty = adapter == null || adapter.getCount() == 0; mDesiredFocusableInTouchModeState = focusable; if (focusable) { mDesiredFocusableState = true; } super.setFocusableInTouchMode(focusable && (!empty)); } void checkFocus() { final T adapter = getAdapter(); final boolean empty = adapter == null || adapter.getCount() == 0; final boolean focusable = !empty; super.setFocusableInTouchMode(focusable && mDesiredFocusableInTouchModeState); super.setFocusable(focusable && mDesiredFocusableState); if (mEmptyView != null) { updateEmptyStatus((adapter == null) || adapter.isEmpty()); } } private void updateEmptyStatus(boolean empty) { if (empty) { if (mEmptyView != null) { mEmptyView.setVisibility(View.VISIBLE); setVisibility(View.GONE); } else { setVisibility(View.VISIBLE); } } else { if (mEmptyView != null) { mEmptyView.setVisibility(View.GONE); } setVisibility(View.VISIBLE); } } public Object getItemAtPosition(int position) { T adapter = getAdapter(); return (adapter == null || position < 0) ? null : adapter.getItem(position); } public long getItemIdAtPosition(int position) { T adapter = getAdapter(); return (adapter == null || position < 0) ? INVALID_ROW_ID : adapter.getItemId(position); } @Override public void setOnClickListener(OnClickListener l) { throw new RuntimeException(); } @Override protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) { dispatchFreezeSelfOnly(container); } @Override protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) { dispatchThawSelfOnly(container); } class AdapterDataSetObserver extends DataSetObserver { @Override public void onChanged() { mDataChanged = true; mOldItemCount = mItemCount; mItemCount = getAdapter().getCount(); checkFocus(); requestLayout(); } @Override public void onInvalidated() { mDataChanged = true; mOldItemCount = mItemCount; mItemCount = 0; checkFocus(); requestLayout(); } } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); } @Override protected boolean canAnimate() { return super.canAnimate() && mItemCount > 0; } @TargetApi(Build.VERSION_CODES.HONEYCOMB) protected boolean isSupportHardwareAccelerated(){ return APIUtil.isSupport(11) && isHardwareAccelerated(); } }