package dev.dworks.libs.actionbarplus.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.database.DataSetObserver;
import android.support.v7.internal.widget.LinearLayoutICS;
import android.util.AttributeSet;
import android.view.SoundEffectConstants;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListAdapter;
import dev.dworks.libs.actionbarplus.R;
/**
* An extension of a linear layout that supports the divider API of Android
* 4.0+. You can populate this layout with data that comes from a
* {@link android.widget.ListAdapter}
*/
public class LinearListView extends LinearLayoutICS {
private static final int[] R_styleable_LinearListView = new int[] {
/* 0 */android.R.attr.entries,
/* 1 *//*R.attr.dividerThickness*/
};
private static final int LinearListView_entries = 0;
private static final int LinearListView_dividerThickness = 1;
private View mEmptyView;
private ListAdapter mAdapter;
private boolean mAreAllItemsSelectable;
private OnItemClickListener mOnItemClickListener;
private DataSetObserver mDataObserver = new DataSetObserver() {
@Override
public void onChanged() {
setupChildren();
}
@Override
public void onInvalidated() {
setupChildren();
}
};
public LinearListView(Context context) {
this(context, null);
}
public LinearListView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs,
R_styleable_LinearListView);
// Use the thickness specified, zero being the default
final int thickness = a.getDimensionPixelSize(
LinearListView_dividerThickness, 0);
if (thickness != 0) {
setDividerThickness(thickness);
}
CharSequence[] entries = a.getTextArray(LinearListView_entries);
if (entries != null) {
setAdapter(new ArrayAdapter<CharSequence>(context,
android.R.layout.simple_list_item_1, entries));
}
a.recycle();
}
@Override
public void setOrientation(int orientation) {
/* if (orientation != getOrientation()) {
int tmp = mDividerHeight;
mDividerHeight = mDividerWidth;
mDividerWidth = tmp;
}*/
super.setOrientation(orientation);
}
/**
* Set the divider thickness size in pixel. That means setting the divider
* height if the layout has an HORIZONTAL orientation and setting the
* divider width otherwise.
*
* @param thickness
* The divider thickness in pixel.
*/
public void setDividerThickness(int thickness) {
/* if (getOrientation() == VERTICAL) {
mDividerHeight = thickness;
} else {
mDividerWidth = thickness;
}*/
requestLayout();
}
public ListAdapter getAdapter() {
return mAdapter;
}
/**
* Sets the data behind this LinearListView.
*
* @param adapter
* The ListAdapter which is responsible for maintaining the data
* backing this list and for producing a view to represent an
* item in that data set.
*
* @see #getAdapter()
*/
public void setAdapter(ListAdapter adapter) {
if (mAdapter != null) {
mAdapter.unregisterDataSetObserver(mDataObserver);
}
mAdapter = adapter;
if (mAdapter != null) {
mAdapter.registerDataSetObserver(mDataObserver);
mAreAllItemsSelectable = mAdapter.areAllItemsEnabled();
}
setupChildren();
}
/**
* Interface definition for a callback to be invoked when an item in this
* LinearListView has been clicked.
*/
public interface OnItemClickListener {
/**
* Callback method to be invoked when an item in this LinearListView has
* been clicked.
* <p>
* Implementers can call getItemAtPosition(position) if they need to
* access the data associated with the selected item.
*
* @param parent
* The LinearListView where the click happened.
* @param view
* The view within the LinearListView that was clicked (this
* will be a view provided by the adapter)
* @param position
* The position of the view in the adapter.
* @param id
* The row id of the item that was clicked.
*/
void onItemClick(LinearListView parent, View view, int position, long id);
}
/**
* Register a callback to be invoked when an item in this LinearListView has
* been clicked.
*
* @param listener
* The callback that will be invoked.
*/
public void setOnItemClickListener(OnItemClickListener listener) {
mOnItemClickListener = listener;
}
/**
* @return The callback to be invoked with an item in this LinearListView has
* been clicked, or null id no callback has been set.
*/
public final OnItemClickListener getOnItemClickListener() {
return mOnItemClickListener;
}
/**
* Call the OnItemClickListener, if it is defined.
*
* @param view
* The view within the LinearListView that was clicked.
* @param position
* The position of the view in the adapter.
* @param id
* The row id of the item that was clicked.
* @return True if there was an assigned OnItemClickListener that was
* called, false otherwise is returned.
*/
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;
}
/**
* Sets the view to show if the adapter is empty
*/
public void setEmptyView(View emptyView) {
mEmptyView = emptyView;
final ListAdapter adapter = getAdapter();
final boolean empty = ((adapter == null) || adapter.isEmpty());
updateEmptyStatus(empty);
}
/**
* When the current adapter is empty, the LinearListView can display a special
* view call the empty view. The empty view is used to provide feedback to
* the user that no data is available in this LinearListView.
*
* @return The view to show if the adapter is empty.
*/
public View getEmptyView() {
return mEmptyView;
}
/**
* Update the status of the list based on the empty parameter. If empty is
* true and we have an empty view, display it. In all the other cases, make
* sure that the layout is VISIBLE and that the empty view is GONE (if
* it's not null).
*/
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);
}
}
/**
* Internal OnClickListener that this view associate of each of its children
* so that they can respond to OnItemClick listener's events. Avoid setting
* an OnClickListener manually. If you need it you can wrap the child in a
* simple {@link android.widget.FrameLayout}.
*/
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(LinearListView.this, v,
mPosition, mAdapter.getItemId(mPosition));
}
}
}
}