Skip to content

Commit

Permalink
Initial release
Browse files Browse the repository at this point in the history
  • Loading branch information
davideas committed May 2, 2015
1 parent 7ab2740 commit 82dc374
Show file tree
Hide file tree
Showing 3 changed files with 351 additions and 0 deletions.
100 changes: 100 additions & 0 deletions eu.davidea.flexibleadapter/ExampleAdapter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package eu.davidea.flexibleadapter;

import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;


public class ExampleAdapter extends FlexibleAdapter<ManageLabelsAdapter.ViewHolder, Label> {

private static final String TAG = ManageLabelsAdapter.class.getSimpleName();

public interface OnItemClickListener {
public void onListItemClick(int position);
public boolean onListItemLongClick(int position);
}

private LayoutInflater mInflater;

private OnItemClickListener mClickListener;

public ManageLabelsAdapter(OnItemClickListener listener) {
this.mClickListener = listener;
updateDataSet();
}

public void updateDataSet() {
this.mItems = DatabaseService.getInstance().getUserLabelsList();
}

public Label getItem(int position) {
return mItems.get(position);
}

@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Log.d(TAG, "onCreateViewHolder for viewType "+viewType);
if (mInflater == null) {
mInflater = LayoutInflater.from(parent.getContext());
}
//NOTE: Example for multiple layout. getItemViewType needs to be Overridden
//final int layout = viewType == XXX ? R.layout.item : R.layout.item2;

View view = mInflater.inflate(R.layout.drawer_list_row, parent, false);
//Eventually set the view's size, margins, paddings and layout parameters
return new ViewHolder(view, mClickListener);
}

@Override
public void onBindViewHolder(ViewHolder holder, final int position) {
Log.d(TAG, "onBindViewHolder for position "+position);
final Label label = mItems.get(position);
//TODO: Set the proper Icon with tint
holder.mImageView.setImageResource(label.getIconResource()!=null?label.getIconResource():R.drawable.ic_label_grey600_24dp);
holder.mTextView.setText(label.getName());
holder.mCounterView.setText(String.valueOf(label.getCounter()));
holder.itemView.setActivated(isSelected(position));
}

/**
* Provide a reference to the views for each data item.
* Complex data labels may need more than one view per item, and
* you provide access to all the views for a data item in a view holder.
*/
static final class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener,
View.OnLongClickListener {

ImageView mImageView;
TextView mTextView;
TextView mCounterView;
private OnItemClickListener mClickListener;

public ViewHolder(View view, OnItemClickListener listener) {
super(view);
mClickListener = listener;

this.mImageView = (ImageView) view.findViewById(R.id.icon);
this.mTextView = (TextView) view.findViewById(R.id.name);
this.mCounterView = (TextView) view.findViewById(R.id.counter);

this.itemView.setOnClickListener(this);
this.itemView.setOnLongClickListener(this);
}

@Override
public void onClick(View view) {
mClickListener.onListItemClick(getAdapterPosition());
}

@Override
public boolean onLongClick(View view) {
return mClickListener.onListItemLongClick(getAdapterPosition());
}

}

}
107 changes: 107 additions & 0 deletions eu.davidea.flexibleadapter/FlexibleAdapter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package eu.davidea.flexibleadapter;

import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.ViewGroup;

/**
* This class provides a set of standard methods to handle changes on the data set
* such as adding, removing, moving an item.
*
* Remember to call {@link RecyclerView#scheduleLayoutAnimation()} after adding or
* removing an item from the Adapter when the activity is paused.
*
* <strong>VH</strong> is your implementation of {@link RecyclerView#ViewHolder}.
* <strong>T</strong> is your domain object containing the data.
*
* @author Davide Steduto
*/
public abstract class FlexibleAdapter<VH extends RecyclerView.ViewHolder, T> extends SelectableAdapter<VH> {

private static final String TAG = FlexibleAdapter.class.getSimpleName();

protected List<T> mItems;
//TODO: Handling the undo functionality

public FlexibleAdapter() {

}

public abstract void updateDataSet();

public abstract T getItem(int position);

@Override
public abstract VH onCreateViewHolder(ViewGroup parent, int viewType);

@Override
public abstract void onBindViewHolder(VH holder, final int position);

@Override
public int getItemCount() {
return mItems.size();
}

public void addItem(int position, T item) {
mItems.add(position, item);
Log.d(TAG, "addItem notifyItemInserted on position "+position);
notifyItemInserted(position);
}

private void removeItem(int position) {
Log.d(TAG, "removeItem on position "+position);
mItems.remove(position);
Log.d(TAG, "removeItem notifyItemRemoved on position "+position);
notifyItemRemoved(position);
}

public void removeItems(List<Integer> selectedPositions) {
Log.d(TAG, "removeItems Sorting positions --------------");
// Reverse-sort the list
Collections.sort(selectedPositions, new Comparator<Integer>() {
@Override
public int compare(Integer lhs, Integer rhs) {
return rhs - lhs;
}
});

// Split the list in ranges
while (!selectedPositions.isEmpty()) {
if (selectedPositions.size() == 1) {
removeItem(selectedPositions.get(0));
//Align the selection list when removing the item
selectedPositions.remove(0);
} else {
int count = 1;
while (selectedPositions.size() > count && selectedPositions.get(count).equals(selectedPositions.get(count - 1) - 1)) {
++count;
}

if (count == 1) {
removeItem(selectedPositions.get(0));
} else {
removeRange(selectedPositions.get(count - 1), count);
}

for (int i = 0; i < count; ++i) {
selectedPositions.remove(0);
}
}
Log.d(TAG, "removeItems current selection " + getSelectedItems());
}
}

private void removeRange(int positionStart, int itemCount) {
Log.d(TAG, "removeRange positionStart="+positionStart+ " itemCount="+itemCount);
for (int i = 0; i < itemCount; ++i) {
mItems.remove(positionStart);
}
Log.d(TAG, "removeRange notifyItemRangeRemoved");
notifyItemRangeRemoved(positionStart, itemCount);
}

}
144 changes: 144 additions & 0 deletions eu.davidea.flexibleadapter/SelectableAdapter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
package eu.davidea.flexibleadapter;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import android.os.Bundle;
import android.support.v7.widget.RecyclerView;
import android.util.Log;

/**
* This class provides a set of standard methods to handle the selection on the items of an Adapter.
*
* @author Davide Steduto
*/
public abstract class SelectableAdapter<VH extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<VH> {

private static final String TAG = SelectableAdapter.class.getSimpleName();

private ArrayList<Integer> selectedItems;

public SelectableAdapter() {
selectedItems = new ArrayList<Integer>();
}

/**
* Indicates if the item at position position is selected
* @param position Position of the item to check
* @return true if the item is selected, false otherwise
*/
protected boolean isSelected(int position) {
return selectedItems.contains(Integer.valueOf(position));
}

/**
* Toggle the selection status of the item at a given position
* @param position Position of the item to toggle the selection status for
*/
public void toggleSelection(int position) {
Integer positionTapped = Integer.valueOf(position);
int index = selectedItems.indexOf(positionTapped);
if (index != -1) {
Log.d(TAG, "toggleSelection removing selection on position "+position);
selectedItems.remove(index);
} else {
Log.d(TAG, "toggleSelection adding selection on position "+position);
selectedItems.add(positionTapped);
}
Log.d(TAG, "toggleSelection notifyItemChanged on position "+position);
notifyItemChanged(position);
Log.d(TAG, "toggleSelection current selection "+selectedItems);
}

/**
* This method remove the selection if at the specified
* position the item was previously selected.
* Note: notifyItemChanged on the position is NOT called!
* This is useful when an item is mainly removed from the
* implementation of the Adapter
* @param position
*/
protected void removeSelection(int position) {
Log.d(TAG, "removeSelection on position "+position);
int index = selectedItems.indexOf(Integer.valueOf(position));
if (index != -1) selectedItems.remove(index);
//The notification is made outside this method
//notifyItemChanged(position);
}

/**
* Add the selection status for all items.
* The selector container is sequentially filled with All items positions.
*/
public void selectAll() {
Log.d(TAG, "selectAll");
selectedItems = new ArrayList<Integer>(getItemCount());
for (int i = 0; i < getItemCount(); i++) {
selectedItems.add(Integer.valueOf(i));
Log.d(TAG, "selectAll notifyItemChanged on position "+i);
notifyItemChanged(i);
}
//TODO: Not sure about this call notifyDataSetChanged() when ALL items needs to be refreshed.
//notifyDataSetChanged();
}

/**
* Clear the selection status for all items.
* If Adapter size match with the size of the selection list,
* then fast clear is performed.
*/
public void clearSelection() {
if (selectedItems.size() == getItemCount()) {
selectedItems.clear();
//TODO: Not sure about this call notifyDataSetChanged() when ALL items needs to be refreshed.
Log.d(TAG, "clearSelection notifyDataSetChanged on all position");
notifyDataSetChanged();
} else {
Iterator<Integer> iterator = selectedItems.iterator();
while (iterator.hasNext()) {
//The notification is done only on items that are currently selected.
//Clearing all items on selectedItems, we loose the position to notify.
//TODO: To verify: Clearing all after the notification actually it does any effect because
// the position called rely on the selectionItems that still contains that position
int i = iterator.next();
iterator.remove();
Log.d(TAG, "clearSelection notifyItemChanged on position "+i);
notifyItemChanged(i);
}
}
}

/**
* Count the selected items
* @return Selected items count
*/
public int getSelectedItemCount() {
return selectedItems.size();
}

/**
* Indicates the list of selected items
* @return List of selected items ids
*/
public List<Integer> getSelectedItems() {
return selectedItems;
}

/**
* Save the state of the current selection on the items.
* @param outState
*/
public void onSaveInstanceState(Bundle outState) {
outState.putIntegerArrayList(TAG, selectedItems);
}

/**
* Restore the previous state of the selection on the items.
* @param savedInstanceState
*/
public void onRestoreInstanceState(Bundle savedInstanceState) {
selectedItems = savedInstanceState.getIntegerArrayList(TAG);
}

}

0 comments on commit 82dc374

Please sign in to comment.