Created
November 20, 2014 20:59
-
-
Save dhenry/c9d0b9a59f6daac380f6 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<resources> | |
<declare-styleable name="OverlapRelativeListView"> | |
<attr name="android:entries"/> | |
<attr name="overlap_margin" format="dimension"/> | |
</declare-styleable> | |
</resources> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* An extension of {@link RelativeLayout}. Displays a series of overlapping items. | |
* Can be populated with data from a {@link android.widget.ListAdapter}. | |
* | |
* Based on: https://github.com/frankiesardo/LinearListView | |
*/ | |
public class OverlapRelativeListView extends RelativeLayout { | |
private int overlapMargin; | |
private ListAdapter mAdapter; | |
private View mEmptyView; | |
private boolean mAreAllItemsSelectable; | |
private OnItemClickListener mOnItemClickListener; | |
private DataSetObserver mDataObserver = new DataSetObserver() { | |
@Override | |
public void onChanged() { | |
setupChildren(); | |
} | |
@Override | |
public void onInvalidated() { | |
setupChildren(); | |
} | |
}; | |
public OverlapRelativeListView(Context context) { | |
this(context, null); | |
} | |
public OverlapRelativeListView(Context context, AttributeSet attrs) { | |
super(context, attrs); | |
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.OverlapRelativeListView); | |
overlapMargin = a.getDimensionPixelSize(R.styleable.OverlapRelativeListView_overlap_margin, 45); | |
CharSequence[] entries = a.getTextArray(R.styleable.OverlapRelativeListView_android_entries); | |
if (entries != null) { | |
setAdapter(new ArrayAdapter<>(context, android.R.layout.simple_list_item_1, entries)); | |
} | |
a.recycle(); | |
} | |
public View getEmptyView() { | |
return mEmptyView; | |
} | |
public void setEmptyView(View emptyView) { | |
mEmptyView = emptyView; | |
final ListAdapter adapter = getAdapter(); | |
final boolean empty = ((adapter == null) || adapter.isEmpty()); | |
updateEmptyStatus(empty); | |
} | |
public int getOverlapMargin() { | |
return overlapMargin; | |
} | |
public void setOverlapMargin(int overlapMargin) { | |
this.overlapMargin = overlapMargin; | |
} | |
public ListAdapter getAdapter() { | |
return mAdapter; | |
} | |
public void setAdapter(ListAdapter adapter) { | |
if (mAdapter != null) { | |
mAdapter.unregisterDataSetObserver(mDataObserver); | |
} | |
mAdapter = adapter; | |
if (mAdapter != null) { | |
mAdapter.registerDataSetObserver(mDataObserver); | |
mAreAllItemsSelectable = mAdapter.areAllItemsEnabled(); | |
} | |
setupChildren(); | |
} | |
@Override | |
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { | |
final int count = getChildCount(); | |
for (int position = 0; position < count; position++) { | |
final View child = getChildAt(position); | |
if (null != child && child.getVisibility() != GONE) { | |
final LayoutParams params = (LayoutParams) child.getLayoutParams(); | |
params.topMargin = overlapMargin * position; | |
} | |
} | |
super.onMeasure(widthMeasureSpec, heightMeasureSpec); | |
} | |
private void updateEmptyStatus(boolean empty) { | |
if (empty) { | |
if (mEmptyView != null) { | |
mEmptyView.setVisibility(View.VISIBLE); | |
setVisibility(View.GONE); | |
} else { | |
// If the caller just removed our empty view, make sure the list | |
// view is visible | |
setVisibility(View.VISIBLE); | |
} | |
} else { | |
if (mEmptyView != null) | |
mEmptyView.setVisibility(View.GONE); | |
setVisibility(View.VISIBLE); | |
} | |
} | |
private void setupChildren() { | |
removeAllViews(); | |
updateEmptyStatus((mAdapter == null) || mAdapter.isEmpty()); | |
if (mAdapter == null) { | |
return; | |
} | |
for (int i = 0; i < mAdapter.getCount(); i++) { | |
View child = mAdapter.getView(i, null, this); | |
if (mAreAllItemsSelectable || mAdapter.isEnabled(i)) { | |
child.setOnClickListener(new InternalOnClickListener(i)); | |
} | |
addViewInLayout(child, -1, child.getLayoutParams(), true); | |
} | |
} | |
public boolean performItemClick(View view, int position, long id) { | |
if (mOnItemClickListener != null) { | |
playSoundEffect(SoundEffectConstants.CLICK); | |
mOnItemClickListener.onItemClick(this, view, position, id); | |
return true; | |
} | |
return false; | |
} | |
public interface OnItemClickListener { | |
void onItemClick(OverlapRelativeListView parent, View view, int position, long id); | |
} | |
public void setOnItemClickListener(OnItemClickListener listener) { | |
mOnItemClickListener = listener; | |
} | |
public final OnItemClickListener getOnItemClickListener() { | |
return mOnItemClickListener; | |
} | |
private class InternalOnClickListener implements OnClickListener { | |
int mPosition; | |
public InternalOnClickListener(int position) { | |
mPosition = position; | |
} | |
@Override | |
public void onClick(View v) { | |
if ((mOnItemClickListener != null) && (mAdapter != null)) { | |
mOnItemClickListener.onItemClick(OverlapRelativeListView.this, v, | |
mPosition, mAdapter.getItemId(mPosition)); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment