diff --git a/README.md b/README.md index 2f3a2a2..5e85e6b 100644 --- a/README.md +++ b/README.md @@ -6,27 +6,26 @@ ### 已解决的问题 -- [x] 提升item的独立性,完美支持item被多处复用 -- [x] item会根据type来做自动复用 - [x] 支持多种类型的item -- [x] 一个item仅会调用一次setViews(),避免重复建立监听器 -- [x] 一个item仅会触发一次绑定视图的操作,提升效率 +- [x] item会根据type来做自动复用 - [x] ​支持dataBinding和其他第三方注入框架 -- [x] 支持通过item的构造方法来传入Activity对象 -- [x] 支持通过item的构造方法来传入item中事件的回调 -- [x] 提供了getConvertedData(data, type)方法来对item传入的数据做转换,方便拆包和提升item的复用性 -- [x] 支持viewpager的正常加载模式和懒加载模式 +- [x] 支持ViewPager的正常加载模式和懒加载模式 +- [x] 提升item的独立性,完美支持item被多处复用 +- [x] 一个item仅会触发一次绑定视图的操作,提升效率 +- [x] 一个item仅会调用一次setViews(),避免重复建立监听器 - [x] 支持快速将ListView的适配器切换为recyclerView的适配器 - [x] 允许用viewpager的notifyDataSetChanged()来正常更新界面 -- [x] 可以给recyclerView的添加头部和底部(利用了`RcvAdapterWrapper`) -- [x] 支持适配器的数据自动绑定,只用操作数据便可,adapter会自动notify界面(需要配合databinding中的`ObservableList`) +- [x] 可以给recyclerView的添加空状态(利用`RcvAdapterWrapper`) +- [x] 可以给recyclerView的添加头部和底部(利用`RcvAdapterWrapper`) - [x] 提供了getCurrentPosition()来支持根据不同的位置选择不同item的功能 +- [x] 提供了getConvertedData(data, type)方法来对item传入的数据做转换,方便拆包和提升item的复用性 +- [x] 支持适配器的数据自动绑定,只用操作数据便可,adapter会自动notify界面(需要配合databinding中的`ObservableList`) ### 示例 ![](./demo/ios_demo.png) -**上图是在作者的授权下引用了设计师“流浪汉国宝(QQ:515288905)”在UI中国上的作品:http://www.ui.cn/detail/149952.html** +**上图是在作者的授权下引用了设计师“流浪汉国宝(QQ:515288905)”在UI中国上的[作品](http://www.ui.cn/detail/149952.html)** 我觉得这个设计很简洁清爽,未来可能会出这个设计的android实现。 diff --git a/adapter/build.gradle b/adapter/build.gradle index 7857999..84708fc 100644 --- a/adapter/build.gradle +++ b/adapter/build.gradle @@ -1,12 +1,12 @@ apply plugin: 'com.android.library' android { - compileSdkVersion 23 - buildToolsVersion "23.0.2" + compileSdkVersion 24 + buildToolsVersion "24.0.2" defaultConfig { minSdkVersion 8 - targetSdkVersion 23 + targetSdkVersion 24 } buildTypes { @@ -25,6 +25,6 @@ android { dependencies { provided 'com.android.databinding:baseLibrary:1.0' - provided 'com.android.support:recyclerview-v7:23.2.1' + provided 'com.android.support:recyclerview-v7:24.2.1' provided "org.projectlombok:lombok:1.12.6" } diff --git a/adapter/src/main/java/kale/adapter/CommonRcvAdapter.java b/adapter/src/main/java/kale/adapter/CommonRcvAdapter.java index 50e3b22..1b1bc92 100644 --- a/adapter/src/main/java/kale/adapter/CommonRcvAdapter.java +++ b/adapter/src/main/java/kale/adapter/CommonRcvAdapter.java @@ -20,7 +20,7 @@ * @author Jack Tony * @date 2015/5/17 */ -public abstract class CommonRcvAdapter extends RecyclerView.Adapter implements IAdapter { +public abstract class CommonRcvAdapter extends RecyclerView.Adapter implements IAdapter { private List mDataList; @@ -34,7 +34,7 @@ public CommonRcvAdapter(@Nullable List data) { if (data == null) { data = new ArrayList<>(); } - + if (DataBindingJudgement.SUPPORT_DATABINDING && data instanceof ObservableList) { ((ObservableList) data).addOnListChangedCallback(new ObservableList.OnListChangedCallback>() { @Override @@ -50,21 +50,24 @@ public void onItemRangeChanged(ObservableList sender, int positionStart, int @Override public void onItemRangeInserted(ObservableList sender, int positionStart, int itemCount) { notifyItemRangeInserted(positionStart, itemCount); - notifyItemRangeChanged(positionStart, itemCount); + notifyChange(sender, positionStart); } @Override public void onItemRangeRemoved(ObservableList sender, int positionStart, int itemCount) { notifyItemRangeRemoved(positionStart, itemCount); - notifyItemRangeChanged(positionStart, itemCount); + notifyChange(sender, positionStart); } @Override public void onItemRangeMoved(ObservableList sender, int fromPosition, int toPosition, int itemCount) { - // Note:不支持一次性移动"多个"item的情况!!!! - notifyItemMoved(fromPosition, toPosition); - notifyDataSetChanged(); + notifyChange(sender, Math.min(fromPosition, toPosition)); } + + private void notifyChange(ObservableList sender, int start) { + onItemRangeChanged(sender, start, getItemCount() - start); + } + }); } mDataList = data; @@ -111,14 +114,14 @@ public Object getItemType(T t) { } @Override - public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + public RcvAdapterItem onCreateViewHolder(ViewGroup parent, int viewType) { return new RcvAdapterItem(parent.getContext(), parent, createItem(mType)); } @Override - public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { - debug((RcvAdapterItem) holder); - ((RcvAdapterItem) holder).item.handleData(getConvertedData(mDataList.get(position), mType), position); + public void onBindViewHolder(RcvAdapterItem holder, int position) { + debug(holder); + holder.item.handleData(getConvertedData(mDataList.get(position), mType), position); } @NonNull @@ -136,13 +139,13 @@ public int getCurrentPosition() { // 内部用到的viewHold /////////////////////////////////////////////////////////////////////////// - private static class RcvAdapterItem extends RecyclerView.ViewHolder { + static class RcvAdapterItem extends RecyclerView.ViewHolder { protected AdapterItem item; boolean isNew = true; // debug中才用到 - protected RcvAdapterItem(Context context, ViewGroup parent, AdapterItem item) { + RcvAdapterItem(Context context, ViewGroup parent, AdapterItem item) { super(LayoutInflater.from(context).inflate(item.getLayoutResId(), parent, false)); this.item = item; this.item.bindViews(itemView); diff --git a/adapter/src/main/java/kale/adapter/RcvAdapterWrapper.java b/adapter/src/main/java/kale/adapter/RcvAdapterWrapper.java index f99278c..1ea8231 100644 --- a/adapter/src/main/java/kale/adapter/RcvAdapterWrapper.java +++ b/adapter/src/main/java/kale/adapter/RcvAdapterWrapper.java @@ -1,7 +1,9 @@ package kale.adapter; import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import android.support.v7.widget.GridLayoutManager; +import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.StaggeredGridLayoutManager; import android.view.View; @@ -22,17 +24,30 @@ public class RcvAdapterWrapper extends RecyclerView.Adapter - + diff --git a/app/src/main/java/kale/commonadapter/HeaderFooterTestActivity.java b/app/src/main/java/kale/commonadapter/HeaderFooterTestActivity.java new file mode 100644 index 0000000..0820636 --- /dev/null +++ b/app/src/main/java/kale/commonadapter/HeaderFooterTestActivity.java @@ -0,0 +1,173 @@ +package kale.commonadapter; + +import android.graphics.Color; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.GridLayoutManager; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.StaggeredGridLayoutManager; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.widget.AdapterView; +import android.widget.Button; +import android.widget.Toast; + +import kale.adapter.CommonRcvAdapter; +import kale.adapter.RcvAdapterWrapper; +import kale.adapter.item.AdapterItem; +import kale.commonadapter.item.ButtonItem; +import kale.commonadapter.item.ImageItem; +import kale.commonadapter.item.TextItem; +import kale.commonadapter.model.DemoModel; +import kale.commonadapter.util.DataManager; +import kale.commonadapter.util.LayoutUtil; +import kale.commonadapter.util.ObservableArrayList; +import kale.commonadapter.util.RcvOnItemClickListener; + +/** + * @author Kale + * @date 2016/3/16 + */ +public class HeaderFooterTestActivity extends AppCompatActivity { + + private ObservableArrayList data = new ObservableArrayList<>(); + + private RcvAdapterWrapper wrapper; + + private RecyclerView recyclerView; + + private LinearLayoutManager layoutManager; + + private GridLayoutManager layoutManager1; + + private StaggeredGridLayoutManager layoutManager2; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + recyclerView = new RecyclerView(this); + LayoutUtil.setContentView(this, recyclerView); + + layoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false); + layoutManager1 = new GridLayoutManager(this, 2); + layoutManager2 = new StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL); + recyclerView.setLayoutManager(layoutManager); + + data.addAll(DataManager.loadData(getBaseContext())); + + final CommonRcvAdapter adapter = initAdapter(); + + wrapper = new RcvAdapterWrapper(adapter, recyclerView.getLayoutManager()); + + final Button header = new Button(this); + header.setText("Header\n\n (click to add)"); + header.setLayoutParams(new RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, 300)); + + final Button footer = new Button(this); + footer.setText("footer"); + + wrapper.setHeaderView(header); + wrapper.setFooterView(null); + + final Button empty = new Button(this); + empty.setBackgroundColor(Color.RED); + empty.setText("empty text"); + wrapper.setEmptyView(empty, recyclerView); + + recyclerView.setAdapter(wrapper); + + handItemClick(); + + recyclerView.postDelayed(new Runnable() { + @Override + public void run() { + data.reset(DataManager.loadData(getBaseContext(),10)); + wrapper.setFooterView(footer); + } + }, 1000); + } + + private void handItemClick() { + // 建议把点击事件写入item里面,在外面写会有各种各样的不可控的问题。这里仅仅是给出一个实现方案,但是不推荐使用 + recyclerView.addOnItemTouchListener(new RcvOnItemClickListener(this, + new AdapterView.OnItemClickListener() { + @Deprecated + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + position = position - wrapper.getHeaderCount(); + if (position >= 0 && position < data.size()) { + Toast.makeText(HeaderFooterTestActivity.this, "pos = " + position, Toast.LENGTH_SHORT).show(); + data.remove(position); + } + + if (position == -1) { + // click header + DemoModel model = new DemoModel(); + model.type = "text"; + model.content = "kale"; + data.add(0, model); + } + } + })); + } + + @NonNull + private CommonRcvAdapter initAdapter() { + return new CommonRcvAdapter(data) { + @Override + public Object getItemType(DemoModel demoModel) { + return demoModel.type; + } + + @NonNull + @Override + public AdapterItem createItem(Object type) { + switch (((String) type)) { + case "text": + return new TextItem(); + case "button": + return new ButtonItem(); + case "image": + return new ImageItem(); + default: + throw new IllegalArgumentException("不合法的type"); + } + } + }; + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + MenuItem linear = menu.add(0, 0, 0, "L"); + linear.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); + + MenuItem grid = menu.add(1, 1, 0, "G"); + grid.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); + + MenuItem staggered = menu.add(2, 2, 0, "S"); + staggered.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == 0) { + recyclerView.setLayoutManager(layoutManager); + wrapper.setLayoutManager(layoutManager); + return true; + } else if (item.getItemId() == 1) { + recyclerView.setLayoutManager(layoutManager1); + wrapper.setLayoutManager(layoutManager1); + return true; + } else if (item.getItemId() == 2) { + recyclerView.setLayoutManager(layoutManager2); + wrapper.setLayoutManager(layoutManager2); + return true; + } else { + return super.onOptionsItemSelected(item); + } + } +} diff --git a/app/src/main/java/kale/commonadapter/MainActivity.java b/app/src/main/java/kale/commonadapter/MainActivity.java index 376ae11..f80902b 100644 --- a/app/src/main/java/kale/commonadapter/MainActivity.java +++ b/app/src/main/java/kale/commonadapter/MainActivity.java @@ -6,7 +6,7 @@ import android.view.View; -public class MainActivity extends AppCompatActivity implements View.OnClickListener{ +public class MainActivity extends AppCompatActivity implements View.OnClickListener { @Override protected void onCreate(Bundle savedInstanceState) { @@ -29,7 +29,7 @@ public void onClick(View v) { clz = RcvTestActivity.class; break; case R.id.rcv_btn2: - clz = RcvHeaderFooterTestActivity.class; + clz = HeaderFooterTestActivity.class; break; case R.id.viewpager_btn: clz = ViewPagerTestActivity.class; diff --git a/app/src/main/java/kale/commonadapter/RcvHeaderFooterTestActivity.java b/app/src/main/java/kale/commonadapter/RcvHeaderFooterTestActivity.java deleted file mode 100644 index a1e2f4c..0000000 --- a/app/src/main/java/kale/commonadapter/RcvHeaderFooterTestActivity.java +++ /dev/null @@ -1,146 +0,0 @@ -package kale.commonadapter; - -import android.databinding.ObservableArrayList; -import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.GridLayoutManager; -import android.support.v7.widget.LinearLayoutManager; -import android.support.v7.widget.RecyclerView; -import android.support.v7.widget.StaggeredGridLayoutManager; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AdapterView; -import android.widget.Button; -import android.widget.Toast; - -import kale.adapter.CommonRcvAdapter; -import kale.adapter.RcvAdapterWrapper; -import kale.adapter.item.AdapterItem; -import kale.commonadapter.item.ButtonItem; -import kale.commonadapter.item.ImageItem; -import kale.commonadapter.item.TextItem; -import kale.commonadapter.model.DemoModel; -import kale.commonadapter.util.DataManager; -import kale.commonadapter.util.LayoutUtil; -import kale.commonadapter.util.RcvOnItemClickListener; - -/** - * @author Kale - * @date 2016/3/16 - */ -public class RcvHeaderFooterTestActivity extends AppCompatActivity { - - private ObservableArrayList data = new ObservableArrayList<>(); - private RcvAdapterWrapper wrapper; - private GridLayoutManager layoutManager1; - private StaggeredGridLayoutManager layoutManager2; - private RecyclerView recyclerView; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - recyclerView = new RecyclerView(this); - LayoutUtil.setContentView(this, recyclerView); - - LinearLayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false); - layoutManager1 = new GridLayoutManager(this, 2); - layoutManager2 = new StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL); - recyclerView.setLayoutManager(layoutManager1); - - data.addAll(DataManager.loadData(getBaseContext())); - - CommonRcvAdapter adapter = new CommonRcvAdapter(data) { - @Override - public Object getItemType(DemoModel demoModel) { - return demoModel.type; - } - - @NonNull - @Override - public AdapterItem createItem(Object type) { - switch (((String) type)) { - case "text": - return new TextItem(); - case "button": - return new ButtonItem(); - case "image": - return new ImageItem(); - default: - throw new IllegalArgumentException("不合法的type"); - } - } - }; - - wrapper = new RcvAdapterWrapper(adapter, recyclerView.getLayoutManager()); - - Button header = new Button(this); - header.setText("Header"); - header.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 300)); - - final Button footer = new Button(this); - footer.setText("footer"); - - wrapper.setHeaderView(header); - - recyclerView.setAdapter(wrapper); - - // 建议把点击事件写入item里面,在外面写会有各种各样的不可控的问题。这里仅仅是给出一个实现方案,但是不推荐使用 - recyclerView.addOnItemTouchListener(new RcvOnItemClickListener(this, new AdapterView.OnItemClickListener() { - @Deprecated - @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - position = position - wrapper.getHeaderCount(); // 写在外面就得判断是否有头部和底部,还不能集中控制事件 - if (position >= 0) { - Toast.makeText(RcvHeaderFooterTestActivity.this, "pos = " + position, Toast.LENGTH_SHORT).show(); - data.remove(position); - } - } - })); - - recyclerView.postDelayed(new Runnable() { - @Override - public void run() { - data.clear(); - data.addAll(DataManager.loadData(getBaseContext(), 10)); -// View view = LayoutInflater.from(getBaseContext()).inflate(R.layout.list_footer, null); - wrapper.setFooterView(footer); - } - }, 1000); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - //添加菜单项 - MenuItem add = menu.add(0, 0, 0, "add"); - add.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); - - MenuItem change = menu.add(1, 1, 0, "change"); - change.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (item.getItemId() == 0) { - DemoModel model = new DemoModel(); - model.type = "text"; - model.content = "kale"; - data.add(0, model); - return true; - } else if (item.getItemId() == 1) { - if (wrapper.getLayoutManager() instanceof StaggeredGridLayoutManager) { - recyclerView.setLayoutManager(layoutManager1); - wrapper.setLayoutManager(layoutManager1); - } else { - recyclerView.setLayoutManager(layoutManager2); - wrapper.setLayoutManager(layoutManager2); - } - return true; - } else { - return super.onOptionsItemSelected(item); - } - } -} diff --git a/app/src/main/java/kale/commonadapter/RcvTestActivity.java b/app/src/main/java/kale/commonadapter/RcvTestActivity.java index 4d6d59e..1457a61 100644 --- a/app/src/main/java/kale/commonadapter/RcvTestActivity.java +++ b/app/src/main/java/kale/commonadapter/RcvTestActivity.java @@ -5,10 +5,7 @@ import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; -import android.support.v7.widget.StaggeredGridLayoutManager; import android.util.Log; -import android.view.Menu; -import android.view.MenuItem; import android.widget.Toast; import java.util.List; @@ -57,6 +54,10 @@ protected void onCreate(Bundle savedInstanceState) { ((IAdapter) mRecyclerView.getAdapter()).setData(data); // 设置新的数据 mRecyclerView.getAdapter().notifyDataSetChanged(); // 通知数据刷新 + loadNewData(data); + } + + private void loadNewData(final List data) { mRecyclerView.postDelayed(new Runnable() { @Override public void run() { @@ -67,7 +68,7 @@ public void run() { } }, 1000); } - + /** * CommonAdapter的类型和item的类型是一致的 * 这里的都是{@link DemoModel} @@ -100,22 +101,4 @@ public AdapterItem createItem(Object type) { }; } - @Override - public boolean onCreateOptionsMenu(Menu menu) { - //添加菜单项 - MenuItem change = menu.add(0, 0, 0, "change"); - change.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (item.getItemId() == 0) { - mRecyclerView.setLayoutManager(new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)); - return true; - } else { - return super.onOptionsItemSelected(item); - } - } - } diff --git a/app/src/main/java/kale/commonadapter/item/TextItem.java b/app/src/main/java/kale/commonadapter/item/TextItem.java index f77c828..d140178 100644 --- a/app/src/main/java/kale/commonadapter/item/TextItem.java +++ b/app/src/main/java/kale/commonadapter/item/TextItem.java @@ -35,7 +35,7 @@ public void setViews() { @Override public void handleData(DemoModel model, int position) { - textView.setText(model.content); + textView.setText(model.content + " pos=" + position); } } diff --git a/app/src/main/java/kale/commonadapter/util/ObservableArrayList.java b/app/src/main/java/kale/commonadapter/util/ObservableArrayList.java new file mode 100644 index 0000000..3a40550 --- /dev/null +++ b/app/src/main/java/kale/commonadapter/util/ObservableArrayList.java @@ -0,0 +1,174 @@ +package kale.commonadapter.util; + +import android.databinding.ListChangeRegistry; +import android.databinding.ObservableList; +import android.support.annotation.NonNull; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +/** + * @author Kale + * @date 2016/2/21 + * + * Fork from {@link android.databinding.ObservableArrayList} + */ +public class ObservableArrayList extends ArrayList implements ObservableList { + + private transient ListChangeRegistry mListeners = new ListChangeRegistry(); + + @Override + public void addOnListChangedCallback(OnListChangedCallback listener) { + if (mListeners == null) { + mListeners = new ListChangeRegistry(); + } + mListeners.add(listener); + } + + @Override + public void removeOnListChangedCallback(OnListChangedCallback listener) { + if (mListeners != null) { + mListeners.remove(listener); + } + } + + @Override + public boolean add(T object) { + super.add(object); + notifyAdd(size() - 1, 1); + return true; + } + + @Override + public void add(int index, T object) { + super.add(index, object); + notifyAdd(index, 1); + } + + @Override + public boolean addAll(@NonNull Collection collection) { + int oldSize = size(); + boolean added = super.addAll(collection); + if (added) { + notifyAdd(oldSize, size() - oldSize); + } + return added; + } + + @Override + public boolean addAll(int index, @NonNull Collection collection) { + boolean added = super.addAll(index, collection); + if (added) { + notifyAdd(index, collection.size()); + } + return added; + } + + @Override + public void clear() { + int oldSize = size(); + super.clear(); + if (oldSize != 0) { + notifyRemove(0, oldSize); + } + } + + @Override + public T remove(int index) { + T val = super.remove(index); + notifyRemove(index, 1); + return val; + } + + @Override + public boolean remove(Object object) { + int index = indexOf(object); + if (index >= 0) { + remove(index); + return true; + } else { + return false; + } + } + + @Override + public T set(int index, T object) { + T val = super.set(index, object); + if (mListeners != null) { + mListeners.notifyChanged(this, index, 1); + } + return val; + } + + @Override + public void removeRange(int fromIndex, int toIndex) { + super.removeRange(fromIndex, toIndex); + notifyRemove(fromIndex, toIndex - fromIndex); + } + + private void notifyAdd(int start, int count) { + if (mListeners != null) { + mListeners.notifyInserted(this, start, count); + } + } + + private void notifyRemove(int start, int count) { + if (mListeners != null) { + mListeners.notifyRemoved(this, start, count); + } + } + + /////////////////////////////////////////////////////////////////////////// + // custom + /////////////////////////////////////////////////////////////////////////// + + public void removeRange(@NonNull Collection collection) { + Object firstObj = collection.iterator().next(); + int from = indexOf(firstObj); + this.removeRange(from, from + collection.size() - 1); + } + + public void set(int from, Collection collection) { + int i = 0; + for (Iterator iterator = collection.iterator(); iterator.hasNext(); i++) { + T obj = iterator.next(); + super.set(from + i, obj); + } + + if (mListeners != null) { + mListeners.notifyChanged(this, from, collection.size()); + } + } + + public void move(int fromPosition, int toPosition) { + moveRange(fromPosition, toPosition, 1); + } + + public void moveRange(int fromPosition, int toPosition, int itemCount) { + List list = new ArrayList<>(); + for (int i = 0; i < itemCount; i++) { + list.add(super.get(i + fromPosition)); + } + super.removeAll(list); + super.addAll(toPosition, list); + + if (mListeners != null) { + mListeners.notifyMoved(this, fromPosition, toPosition, itemCount); + } + } + + /** + * Reset all data in the list + * + * @param collection new data + */ + public void reset(Collection collection) { + super.clear(); + super.addAll(collection); + if (mListeners != null) { + mListeners.notifyChanged(this); + } + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/list_footer.xml b/app/src/main/res/layout/list_footer.xml deleted file mode 100644 index db03e44..0000000 --- a/app/src/main/res/layout/list_footer.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - \ No newline at end of file