Skip to content

Instantly share code, notes, and snippets.

@dhenry
Created November 20, 2014 20:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dhenry/c9d0b9a59f6daac380f6 to your computer and use it in GitHub Desktop.
Save dhenry/c9d0b9a59f6daac380f6 to your computer and use it in GitHub Desktop.
<?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>
/**
* 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