diff --git a/recyclerview_helper/.idea/inspectionProfiles/Project_Default.xml b/recyclerview_helper/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000..a6cb5d5
--- /dev/null
+++ b/recyclerview_helper/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/recyclerview_helper/.idea/inspectionProfiles/profiles_settings.xml b/recyclerview_helper/.idea/inspectionProfiles/profiles_settings.xml
new file mode 100644
index 0000000..3b31283
--- /dev/null
+++ b/recyclerview_helper/.idea/inspectionProfiles/profiles_settings.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/recyclerview_helper/app/src/main/java/com/lvr/recyclerview_helper/sample/AllActivity.java b/recyclerview_helper/app/src/main/java/com/lvr/recyclerview_helper/sample/AllActivity.java
new file mode 100644
index 0000000..071b953
--- /dev/null
+++ b/recyclerview_helper/app/src/main/java/com/lvr/recyclerview_helper/sample/AllActivity.java
@@ -0,0 +1,159 @@
+package com.lvr.recyclerview_helper.sample;
+
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.SystemClock;
+import android.support.v7.app.AlertDialog;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.view.View;
+
+import com.lvr.library.adapter.CommonAdapter;
+import com.lvr.library.anims.adapters.ScaleInAnimationAdapter;
+import com.lvr.library.anims.animators.LandingAnimator;
+import com.lvr.library.holder.BaseViewHolder;
+import com.lvr.library.recyclerview.HRecyclerView;
+import com.lvr.library.recyclerview.OnLoadMoreListener;
+import com.lvr.library.recyclerview.OnRefreshListener;
+import com.lvr.recyclerview_helper.R;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+/**
+ * Created by lvr on 2017/5/25.
+ */
+public class AllActivity extends AppCompatActivity implements OnLoadMoreListener, OnRefreshListener {
+ private String[] mStrings = {
+ "Apple", "Ball", "Camera", "Day", "Egg", "Foo", "Google", "Hello", "Iron", "Japan", "Coke",
+ "Dog", "Cat", "Yahoo", "Sony", "Canon", "Fujitsu", "USA", "Nexus", "LINE", "Haskell", "C++",
+ "Go"
+ };
+ private int[] mImageRes = {R.drawable.image1, R.drawable.image2};
+ private HRecyclerView mRecyclerView;
+ private LoadMoreFooterView mLoadMoreFooterView;
+ private Handler mHandler = new Handler(){
+ @Override
+ public void handleMessage(Message msg) {
+ super.handleMessage(msg);
+ if(msg.what==0){
+ //刷新完毕
+ mRecyclerView.setRefreshing(false);
+ }else if(count==4){
+ //没有更多数据
+ mLoadMoreFooterView.setStatus(LoadMoreFooterView.Status.THE_END);
+ }else{
+ //加载更多完毕
+ mDatas.add("Alibaba");
+ mDatas.add("Java");
+ mDatas.add("Kotlin");
+ mDatas.add("Swift");
+ mAdapter.notifyItemInserted(mDatas.size()+1);
+ mLoadMoreFooterView.setStatus(LoadMoreFooterView.Status.GONE);
+ }
+ }
+ };
+ private List mDatas;
+ private CommonAdapter mAdapter;
+ private int count =1;
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_all);
+ mRecyclerView = (HRecyclerView) findViewById(R.id.list);
+ mDatas = new ArrayList<>();
+ for(int i=0;i(this, R.layout.item_common, mDatas) {
+ @Override
+ public void convert(BaseViewHolder holder, int position) {
+ holder.setText(R.id.tv_content,mDatas.get(position));
+ int number = new Random().nextInt(2);
+ holder.setImageResource(R.id.iv_content,mImageRes[number]);
+ }
+ };
+
+ mRecyclerView.setItemAnimator(new LandingAnimator());
+ mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
+ ScaleInAnimationAdapter scaleAdapter = new ScaleInAnimationAdapter(mAdapter);
+ scaleAdapter.setFirstOnly(false);
+ scaleAdapter.setDuration(500);
+ mRecyclerView.setAdapter(scaleAdapter);
+ mAdapter.setOnItemClickListener(new CommonAdapter.OnItemClickListener() {
+ @Override
+ public void onItemClick(View view, RecyclerView.ViewHolder holder, int position) {
+ System.out.println("点击");
+ showMyDialog("响应点击事件");
+ }
+ });
+ mAdapter.setOnItemLongClickListener(new CommonAdapter.OnItemLongClickListener() {
+ @Override
+ public boolean onItemLongClick(View view, RecyclerView.ViewHolder holder, int position) {
+ showMyDialog("响应长按事件");
+ return false;
+ }
+ });
+ mRecyclerView.setOnRefreshListener(this);
+ mRecyclerView.setOnLoadMoreListener(this);
+ mLoadMoreFooterView = (LoadMoreFooterView) mRecyclerView.getLoadMoreFooterView();
+ mRecyclerView.post(new Runnable() {
+ @Override
+ public void run() {
+ mRecyclerView.setRefreshing(true);
+ }
+ });
+ }
+
+ public void showMyDialog(String message){
+ AlertDialog.Builder builder = new AlertDialog.Builder(AllActivity.this);
+ builder.setTitle("事件类型");
+ builder.setMessage(message);
+ AlertDialog dialog = builder.create();
+ builder.setNegativeButton("知道", new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ dialog.dismiss();
+ }
+ });
+ dialog.show();
+ }
+
+ @Override
+ public void onLoadMore() {
+ if(mLoadMoreFooterView.canLoadMore()){
+ mLoadMoreFooterView.setStatus(LoadMoreFooterView.Status.LOADING);
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ //假装加载耗时数据
+ SystemClock.sleep(1000);
+ Message message = Message.obtain();
+ message.what =count;
+ count++;
+ mHandler.sendMessage(message);
+ }
+ }).start();
+ }
+
+ }
+
+ @Override
+ public void onRefresh() {
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ //假装加载耗时数据
+ SystemClock.sleep(1000);
+ Message msg = Message.obtain();
+ msg.what=0;
+ mHandler.sendMessage(msg);
+ }
+ }).start();
+
+ }
+}
diff --git a/recyclerview_helper/app/src/main/java/com/lvr/recyclerview_helper/sample/ClassicRefreshHeaderView.java b/recyclerview_helper/app/src/main/java/com/lvr/recyclerview_helper/sample/ClassicRefreshHeaderView.java
new file mode 100644
index 0000000..f1645be
--- /dev/null
+++ b/recyclerview_helper/app/src/main/java/com/lvr/recyclerview_helper/sample/ClassicRefreshHeaderView.java
@@ -0,0 +1,121 @@
+package com.lvr.recyclerview_helper.sample;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.animation.Animation;
+import android.view.animation.AnimationUtils;
+import android.widget.ImageView;
+import android.widget.ProgressBar;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+import com.lvr.library.recyclerview.RefreshTrigger;
+import com.lvr.recyclerview_helper.R;
+
+
+public class ClassicRefreshHeaderView extends RelativeLayout implements RefreshTrigger {
+ private ImageView ivArrow;
+
+ private ImageView ivSuccess;
+
+ private TextView tvRefresh;
+
+ private ProgressBar progressBar;
+
+ private Animation rotateUp;
+
+ private Animation rotateDown;
+
+ private boolean rotated = false;
+
+ private int mHeight;
+
+ public ClassicRefreshHeaderView(Context context) {
+ this(context, null);
+ }
+
+ public ClassicRefreshHeaderView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public ClassicRefreshHeaderView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+
+ inflate(context, R.layout.layout_hrecyclerview_classic_refresh_header_view, this);
+
+ tvRefresh = (TextView) findViewById(R.id.tvRefresh);
+
+ ivArrow = (ImageView) findViewById(R.id.ivArrow);
+
+ ivSuccess = (ImageView) findViewById(R.id.ivSuccess);
+
+ progressBar = (ProgressBar) findViewById(R.id.progressbar);
+
+ rotateUp = AnimationUtils.loadAnimation(context, R.anim.rotate_up);
+
+ rotateDown = AnimationUtils.loadAnimation(context, R.anim.rotate_down);
+ }
+
+ @Override
+ public void onStart(boolean automatic, int headerHeight, int finalHeight) {
+ this.mHeight = headerHeight;
+ progressBar.setIndeterminate(false);
+ }
+
+ @Override
+ public void onMove(boolean isComplete, boolean automatic, int moved) {
+ if (!isComplete) {
+ ivArrow.setVisibility(VISIBLE);
+ progressBar.setVisibility(GONE);
+ ivSuccess.setVisibility(GONE);
+ if (moved <= mHeight) {
+ if (rotated) {
+ ivArrow.clearAnimation();
+ ivArrow.startAnimation(rotateDown);
+ rotated = false;
+ }
+ tvRefresh.setText("下拉刷新");
+ } else {
+ tvRefresh.setText("释放刷新");
+ if (!rotated) {
+ ivArrow.clearAnimation();
+ ivArrow.startAnimation(rotateUp);
+ rotated = true;
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onRefresh() {
+ ivSuccess.setVisibility(GONE);
+ ivArrow.clearAnimation();
+ ivArrow.setVisibility(GONE);
+ progressBar.setVisibility(VISIBLE);
+ tvRefresh.setText("正在刷新");
+ }
+
+ @Override
+ public void onRelease() {
+
+ }
+
+ @Override
+ public void onComplete() {
+ rotated = false;
+ ivSuccess.setVisibility(VISIBLE);
+ ivArrow.clearAnimation();
+ ivArrow.setVisibility(GONE);
+ progressBar.setVisibility(GONE);
+ tvRefresh.setText("完成");
+ }
+
+ @Override
+ public void onReset() {
+ rotated = false;
+ ivSuccess.setVisibility(GONE);
+ ivArrow.clearAnimation();
+ ivArrow.setVisibility(GONE);
+ progressBar.setVisibility(GONE);
+ }
+}
diff --git a/recyclerview_helper/app/src/main/java/com/lvr/recyclerview_helper/sample/LoadMoreFooterView.java b/recyclerview_helper/app/src/main/java/com/lvr/recyclerview_helper/sample/LoadMoreFooterView.java
new file mode 100644
index 0000000..5ae3044
--- /dev/null
+++ b/recyclerview_helper/app/src/main/java/com/lvr/recyclerview_helper/sample/LoadMoreFooterView.java
@@ -0,0 +1,105 @@
+package com.lvr.recyclerview_helper.sample;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.FrameLayout;
+
+import com.lvr.recyclerview_helper.R;
+
+
+public class LoadMoreFooterView extends FrameLayout {
+
+ private Status mStatus;
+
+ private View mLoadingView;
+
+ private View mErrorView;
+
+ private View mTheEndView;
+
+ private OnRetryListener mOnRetryListener;
+
+ public LoadMoreFooterView(Context context) {
+ this(context, null);
+ }
+
+ public LoadMoreFooterView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public LoadMoreFooterView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ LayoutInflater.from(context).inflate(R.layout.layout_hrecyclerview_load_more_footer_view, this, true);
+
+ mLoadingView = findViewById(R.id.loadingView);
+ mErrorView = findViewById(R.id.errorView);
+ mTheEndView = findViewById(R.id.theEndView);
+
+ mErrorView.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (mOnRetryListener != null) {
+ mOnRetryListener.onRetry(LoadMoreFooterView.this);
+ }
+ }
+ });
+
+ setStatus(Status.GONE);
+ }
+
+ public void setOnRetryListener(OnRetryListener listener) {
+ this.mOnRetryListener = listener;
+ }
+
+ public Status getStatus() {
+ return mStatus;
+ }
+
+ public void setStatus(Status status) {
+ this.mStatus = status;
+ change();
+ }
+
+ public boolean canLoadMore() {
+ return mStatus == Status.GONE || mStatus == Status.ERROR;
+ }
+
+ private void change() {
+ switch (mStatus) {
+ case GONE:
+ mLoadingView.setVisibility(GONE);
+ mErrorView.setVisibility(GONE);
+ mTheEndView.setVisibility(GONE);
+ break;
+
+ case LOADING:
+ mLoadingView.setVisibility(VISIBLE);
+ mErrorView.setVisibility(GONE);
+ mTheEndView.setVisibility(GONE);
+ break;
+
+ case ERROR:
+ mLoadingView.setVisibility(GONE);
+ mErrorView.setVisibility(VISIBLE);
+ mTheEndView.setVisibility(GONE);
+ break;
+
+ case THE_END:
+ mLoadingView.setVisibility(GONE);
+ mErrorView.setVisibility(GONE);
+ mTheEndView.setVisibility(VISIBLE);
+ break;
+ }
+ }
+
+ public enum Status {
+ GONE, LOADING, ERROR, THE_END
+ }
+
+ public interface OnRetryListener {
+ void onRetry(LoadMoreFooterView view);
+ }
+
+}
diff --git a/recyclerview_helper/app/src/main/java/com/lvr/recyclerview_helper/sample/MainActivity.java b/recyclerview_helper/app/src/main/java/com/lvr/recyclerview_helper/sample/MainActivity.java
new file mode 100644
index 0000000..13e4625
--- /dev/null
+++ b/recyclerview_helper/app/src/main/java/com/lvr/recyclerview_helper/sample/MainActivity.java
@@ -0,0 +1,308 @@
+package com.lvr.recyclerview_helper.sample;
+
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v7.app.AlertDialog;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.Toolbar;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.Spinner;
+
+import com.lvr.library.adapter.CommonAdapter;
+import com.lvr.library.adapter.MultiItemCommonAdapter;
+import com.lvr.library.anims.adapters.ScaleInAnimationAdapter;
+import com.lvr.library.anims.adapters.SlideInBottomAnimationAdapter;
+import com.lvr.library.anims.animators.FlipInLeftYAnimator;
+import com.lvr.library.anims.animators.LandingAnimator;
+import com.lvr.library.holder.BaseViewHolder;
+import com.lvr.library.recyclerview.HRecyclerView;
+import com.lvr.library.support.MultiItemTypeSupport;
+import com.lvr.recyclerview_helper.R;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Random;
+
+public class MainActivity extends AppCompatActivity {
+
+ private HRecyclerView mRecyclerView;
+ private Spinner mSpinner;
+ private Toolbar mToolbar;
+ private String[] mTypes = {"单类型", "多类型", "单类型+动画", "多类型+动画", "单类型+点击", "多类型+点击","单类型+头/尾","多类型+头/尾"};
+ private String[] mStrings = {
+ "Google", "Hello", "Iron", "Japan", "Coke", "Yahoo", "Sony", "Canon", "Fujitsu", "USA", "Nexus", "LINE", "Haskell", "C++",
+ "Java", "Go", "Swift", "Objective-c", "Ruby", "PHP", "Bash", "ksh", "C", "Groovy", "Kotlin"
+ };
+ private int[] mImageRes = {R.drawable.image1, R.drawable.image2,R.drawable.image3,R.drawable.image4,R.drawable.image5,R.drawable.image6};
+ private int TYPE_HEAD = 0;
+ private int TYPE_COMMON = 1;
+
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+ mSpinner = (Spinner) findViewById(R.id.spinner);
+ Button button = (Button) findViewById(R.id.btn_next);
+ button.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Intent intent = new Intent(MainActivity.this,AllActivity.class);
+ startActivity(intent);
+ }
+ });
+ mRecyclerView = (HRecyclerView) findViewById(R.id.list);
+ mRecyclerView.setLayoutManager(new LinearLayoutManager(MainActivity.this));
+ setSupportActionBar(mToolbar);
+ mToolbar = (Toolbar) findViewById(R.id.tool_bar);
+
+ ArrayAdapter spinnerAdapter =
+ new ArrayAdapter<>(this, android.R.layout.simple_list_item_1);
+ spinnerAdapter.addAll(Arrays.asList(mTypes));
+ mSpinner.setAdapter(spinnerAdapter);
+ mSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView> parent, View view, int position, long id) {
+ if (position == 0) {
+ setSingleItem();
+ }
+ if (position == 1) {
+ setMultiItem();
+ }
+ if (position == 2) {
+ setSingleWithAnimItem();
+ }
+ if (position == 3) {
+ setMultiWithAnimItem();
+ }
+ if (position == 4) {
+ setSingleItemWithClick();
+ }
+ if (position == 5) {
+ setMultiItemWithClick();
+ }
+ //每点击一次就会多加一对头尾布局
+ if(position==6){
+ setSingleItemWithView();
+ }
+ //每点击一次就会多加一对头尾布局
+ if(position==7){
+ setMultiItemWithView();
+ }
+
+
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView> parent) {
+
+ }
+ });
+ }
+
+
+
+
+
+ /**
+ * 多类型+头/尾
+ */
+ private void setMultiItemWithView() {
+ MultiItemCommonAdapter adapter = multiSetting();
+
+ View headView = LayoutInflater.from(MainActivity.this).inflate(R.layout.item_head,null,false);
+ View footView = LayoutInflater.from(MainActivity.this).inflate(R.layout.item_foot,null,false);
+ mRecyclerView.addHeaderView(headView);
+ mRecyclerView.addFooterView(footView);
+ mRecyclerView.setAdapter(adapter);
+
+ }
+
+ /**
+ * 单类型+头/尾
+ */
+ private void setSingleItemWithView() {
+ CommonAdapter adapter = singleSetting();
+
+ View headView = LayoutInflater.from(MainActivity.this).inflate(R.layout.item_head,null,false);
+ View footView = LayoutInflater.from(MainActivity.this).inflate(R.layout.item_foot,null,false);
+ mRecyclerView.addHeaderView(headView);
+ mRecyclerView.addFooterView(footView);
+ mRecyclerView.setAdapter(adapter);
+
+ }
+
+ /**
+ * 多类型+点击
+ */
+ private void setMultiItemWithClick() {
+ MultiItemCommonAdapter adapter = multiSetting();
+ adapter.setOnItemClickListener(new CommonAdapter.OnItemClickListener() {
+ @Override
+ public void onItemClick(View view, RecyclerView.ViewHolder holder, int position) {
+ showMyDialog("点击事件");
+ }
+ });
+ adapter.setOnItemLongClickListener(new CommonAdapter.OnItemLongClickListener() {
+ @Override
+ public boolean onItemLongClick(View view, RecyclerView.ViewHolder holder, int position) {
+ showMyDialog("长按事件");
+ return false;
+ }
+ });
+ mRecyclerView.setItemAnimator(new FlipInLeftYAnimator());
+ SlideInBottomAnimationAdapter scaleAdapter = new SlideInBottomAnimationAdapter(adapter);
+ scaleAdapter.setFirstOnly(false);
+ scaleAdapter.setDuration(500);
+ mRecyclerView.setAdapter(scaleAdapter);
+ }
+
+ /**
+ * 单类型+点击
+ */
+ private void setSingleItemWithClick() {
+ CommonAdapter adapter = singleSetting();
+ adapter.setOnItemClickListener(new CommonAdapter.OnItemClickListener() {
+ @Override
+ public void onItemClick(View view, RecyclerView.ViewHolder holder, int position) {
+ System.out.println("点击");
+ showMyDialog("响应点击事件");
+ }
+ });
+ adapter.setOnItemLongClickListener(new CommonAdapter.OnItemLongClickListener() {
+ @Override
+ public boolean onItemLongClick(View view, RecyclerView.ViewHolder holder, int position) {
+ showMyDialog("响应长按事件");
+ return false;
+ }
+ });
+ mRecyclerView.setItemAnimator(new LandingAnimator());
+ ScaleInAnimationAdapter scaleAdapter = new ScaleInAnimationAdapter(adapter);
+ scaleAdapter.setFirstOnly(false);
+ scaleAdapter.setDuration(500);
+ mRecyclerView.setAdapter(scaleAdapter);
+
+ }
+
+ /**
+ * 多类型+动画
+ */
+ private void setMultiWithAnimItem() {
+ MultiItemCommonAdapter adapter = multiSetting();
+ mRecyclerView.setItemAnimator(new FlipInLeftYAnimator());
+ SlideInBottomAnimationAdapter scaleAdapter = new SlideInBottomAnimationAdapter(adapter);
+ scaleAdapter.setFirstOnly(false);
+ scaleAdapter.setDuration(500);
+ mRecyclerView.setAdapter(scaleAdapter);
+ }
+
+ /**
+ * 单类型+动画
+ */
+ private void setSingleWithAnimItem() {
+ CommonAdapter adapter = singleSetting();
+ mRecyclerView.setItemAnimator(new LandingAnimator());
+ ScaleInAnimationAdapter scaleAdapter = new ScaleInAnimationAdapter(adapter);
+ scaleAdapter.setFirstOnly(false);
+ scaleAdapter.setDuration(500);
+ mRecyclerView.setAdapter(scaleAdapter);
+ }
+
+
+ /**
+ * 多类型
+ */
+ private void setMultiItem() {
+ multiSetting();
+ }
+
+ /**
+ * 单类型
+ */
+ public void setSingleItem() {
+ singleSetting();
+ }
+
+ /**
+ * 单类型基本设置
+ */
+ public CommonAdapter singleSetting() {
+ List mDatas = Arrays.asList(mStrings);
+ CommonAdapter mAdapter = new CommonAdapter(this, R.layout.item_common, mDatas) {
+ @Override
+ public void convert(BaseViewHolder holder, int position) {
+ holder.setText(R.id.tv_content,mDatas.get(position));
+ int number = new Random().nextInt(3);
+ holder.setImageResource(R.id.iv_content,mImageRes[number]);
+ }
+ };
+ mRecyclerView.setAdapter(mAdapter);
+ return mAdapter;
+ }
+
+ /**
+ * 多类型基本设置
+ */
+ public MultiItemCommonAdapter multiSetting() {
+ MultiItemTypeSupport support = new MultiItemTypeSupport() {
+ @Override
+ public int getLayoutId(int itemType) {
+ if (itemType == TYPE_HEAD) {
+ return R.layout.item_special;
+ } else {
+ return R.layout.item_common;
+ }
+
+ }
+
+ @Override
+ public int getItemViewType(int position, String s) {
+ if (position%3==0&& position>0) {
+ return TYPE_HEAD;
+ } else {
+ return TYPE_COMMON;
+ }
+ }
+ };
+ List mDatas = Arrays.asList(mStrings);
+ MultiItemCommonAdapter mAdapter = new MultiItemCommonAdapter(this, mDatas, support) {
+ @Override
+ public void convert(BaseViewHolder holder, int position) {
+ if (position%3==0&& position>0) {
+ holder.setImageResource(R.id.iv_head,R.drawable.multi_image);
+ } else {
+ holder.setText(R.id.tv_content,mDatas.get(position));
+ int number = new Random().nextInt(3)+3;
+ holder.setImageResource(R.id.iv_content,mImageRes[number]);
+ }
+ }
+ };
+ mRecyclerView.setAdapter(mAdapter);
+ return mAdapter;
+ }
+ public void showMyDialog(String message){
+ AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
+ builder.setTitle("事件类型");
+ builder.setMessage(message);
+ AlertDialog dialog = builder.create();
+ builder.setNegativeButton("知道", new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ dialog.dismiss();
+ }
+ });
+ dialog.show();
+ }
+
+
+
+
+
+}
diff --git a/recyclerview_helper/app/src/main/res/anim/rotate_down.xml b/recyclerview_helper/app/src/main/res/anim/rotate_down.xml
new file mode 100644
index 0000000..5277db9
--- /dev/null
+++ b/recyclerview_helper/app/src/main/res/anim/rotate_down.xml
@@ -0,0 +1,11 @@
+
+
+
diff --git a/recyclerview_helper/app/src/main/res/anim/rotate_up.xml b/recyclerview_helper/app/src/main/res/anim/rotate_up.xml
new file mode 100644
index 0000000..edc507f
--- /dev/null
+++ b/recyclerview_helper/app/src/main/res/anim/rotate_up.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/recyclerview_helper/app/src/main/res/drawable/image1.jpg b/recyclerview_helper/app/src/main/res/drawable/image1.jpg
new file mode 100644
index 0000000..81a15fb
Binary files /dev/null and b/recyclerview_helper/app/src/main/res/drawable/image1.jpg differ
diff --git a/recyclerview_helper/app/src/main/res/drawable/image2.png b/recyclerview_helper/app/src/main/res/drawable/image2.png
new file mode 100644
index 0000000..9d833cd
Binary files /dev/null and b/recyclerview_helper/app/src/main/res/drawable/image2.png differ
diff --git a/recyclerview_helper/app/src/main/res/drawable/image3.jpg b/recyclerview_helper/app/src/main/res/drawable/image3.jpg
new file mode 100644
index 0000000..9548bc6
Binary files /dev/null and b/recyclerview_helper/app/src/main/res/drawable/image3.jpg differ
diff --git a/recyclerview_helper/app/src/main/res/drawable/image4.jpg b/recyclerview_helper/app/src/main/res/drawable/image4.jpg
new file mode 100644
index 0000000..a5ebe05
Binary files /dev/null and b/recyclerview_helper/app/src/main/res/drawable/image4.jpg differ
diff --git a/recyclerview_helper/app/src/main/res/drawable/image5.jpg b/recyclerview_helper/app/src/main/res/drawable/image5.jpg
new file mode 100644
index 0000000..aa1f3ca
Binary files /dev/null and b/recyclerview_helper/app/src/main/res/drawable/image5.jpg differ
diff --git a/recyclerview_helper/app/src/main/res/drawable/image6.jpg b/recyclerview_helper/app/src/main/res/drawable/image6.jpg
new file mode 100644
index 0000000..bb3bb4e
Binary files /dev/null and b/recyclerview_helper/app/src/main/res/drawable/image6.jpg differ
diff --git a/recyclerview_helper/app/src/main/res/drawable/image_icon.jpeg b/recyclerview_helper/app/src/main/res/drawable/image_icon.jpeg
new file mode 100644
index 0000000..988ff12
Binary files /dev/null and b/recyclerview_helper/app/src/main/res/drawable/image_icon.jpeg differ
diff --git a/recyclerview_helper/app/src/main/res/drawable/multi_image.jpg b/recyclerview_helper/app/src/main/res/drawable/multi_image.jpg
new file mode 100644
index 0000000..e73a300
Binary files /dev/null and b/recyclerview_helper/app/src/main/res/drawable/multi_image.jpg differ
diff --git a/recyclerview_helper/app/src/main/res/layout/activity_all.xml b/recyclerview_helper/app/src/main/res/layout/activity_all.xml
new file mode 100644
index 0000000..fef6f1d
--- /dev/null
+++ b/recyclerview_helper/app/src/main/res/layout/activity_all.xml
@@ -0,0 +1,15 @@
+
+
+
+
\ No newline at end of file
diff --git a/recyclerview_helper/app/src/main/res/layout/item_common.xml b/recyclerview_helper/app/src/main/res/layout/item_common.xml
new file mode 100644
index 0000000..161b65b
--- /dev/null
+++ b/recyclerview_helper/app/src/main/res/layout/item_common.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/recyclerview_helper/app/src/main/res/layout/item_foot.xml b/recyclerview_helper/app/src/main/res/layout/item_foot.xml
new file mode 100644
index 0000000..c4f4fa4
--- /dev/null
+++ b/recyclerview_helper/app/src/main/res/layout/item_foot.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/recyclerview_helper/app/src/main/res/layout/item_head.xml b/recyclerview_helper/app/src/main/res/layout/item_head.xml
new file mode 100644
index 0000000..e44997c
--- /dev/null
+++ b/recyclerview_helper/app/src/main/res/layout/item_head.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/recyclerview_helper/app/src/main/res/layout/item_special.xml b/recyclerview_helper/app/src/main/res/layout/item_special.xml
new file mode 100644
index 0000000..e021082
--- /dev/null
+++ b/recyclerview_helper/app/src/main/res/layout/item_special.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/recyclerview_helper/app/src/main/res/layout/layout_hrecyclerview_classic_refresh_header_view.xml b/recyclerview_helper/app/src/main/res/layout/layout_hrecyclerview_classic_refresh_header_view.xml
new file mode 100644
index 0000000..4a8a084
--- /dev/null
+++ b/recyclerview_helper/app/src/main/res/layout/layout_hrecyclerview_classic_refresh_header_view.xml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/recyclerview_helper/app/src/main/res/layout/layout_hrecyclerview_load_more_footer.xml b/recyclerview_helper/app/src/main/res/layout/layout_hrecyclerview_load_more_footer.xml
new file mode 100644
index 0000000..137bb52
--- /dev/null
+++ b/recyclerview_helper/app/src/main/res/layout/layout_hrecyclerview_load_more_footer.xml
@@ -0,0 +1,4 @@
+
+
\ No newline at end of file
diff --git a/recyclerview_helper/app/src/main/res/layout/layout_hrecyclerview_load_more_footer_error_view.xml b/recyclerview_helper/app/src/main/res/layout/layout_hrecyclerview_load_more_footer_error_view.xml
new file mode 100644
index 0000000..09e109c
--- /dev/null
+++ b/recyclerview_helper/app/src/main/res/layout/layout_hrecyclerview_load_more_footer_error_view.xml
@@ -0,0 +1,8 @@
+
+
\ No newline at end of file
diff --git a/recyclerview_helper/app/src/main/res/layout/layout_hrecyclerview_load_more_footer_loading_view.xml b/recyclerview_helper/app/src/main/res/layout/layout_hrecyclerview_load_more_footer_loading_view.xml
new file mode 100644
index 0000000..101ff01
--- /dev/null
+++ b/recyclerview_helper/app/src/main/res/layout/layout_hrecyclerview_load_more_footer_loading_view.xml
@@ -0,0 +1,7 @@
+
+
\ No newline at end of file
diff --git a/recyclerview_helper/app/src/main/res/layout/layout_hrecyclerview_load_more_footer_the_end_view.xml b/recyclerview_helper/app/src/main/res/layout/layout_hrecyclerview_load_more_footer_the_end_view.xml
new file mode 100644
index 0000000..0dee07b
--- /dev/null
+++ b/recyclerview_helper/app/src/main/res/layout/layout_hrecyclerview_load_more_footer_the_end_view.xml
@@ -0,0 +1,8 @@
+
+
\ No newline at end of file
diff --git a/recyclerview_helper/app/src/main/res/layout/layout_hrecyclerview_load_more_footer_view.xml b/recyclerview_helper/app/src/main/res/layout/layout_hrecyclerview_load_more_footer_view.xml
new file mode 100644
index 0000000..b196e96
--- /dev/null
+++ b/recyclerview_helper/app/src/main/res/layout/layout_hrecyclerview_load_more_footer_view.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/recyclerview_helper/app/src/main/res/layout/layout_hrecyclerview_refresh_header.xml b/recyclerview_helper/app/src/main/res/layout/layout_hrecyclerview_refresh_header.xml
new file mode 100644
index 0000000..5d389c9
--- /dev/null
+++ b/recyclerview_helper/app/src/main/res/layout/layout_hrecyclerview_refresh_header.xml
@@ -0,0 +1,7 @@
+
+
+
+
\ No newline at end of file
diff --git a/recyclerview_helper/app/src/main/res/mipmap-xxhdpi/qq_refresh_success.png b/recyclerview_helper/app/src/main/res/mipmap-xxhdpi/qq_refresh_success.png
new file mode 100644
index 0000000..0584ace
Binary files /dev/null and b/recyclerview_helper/app/src/main/res/mipmap-xxhdpi/qq_refresh_success.png differ
diff --git a/recyclerview_helper/app/src/main/res/mipmap-xxhdpi/twitter_pull_arrow.png b/recyclerview_helper/app/src/main/res/mipmap-xxhdpi/twitter_pull_arrow.png
new file mode 100644
index 0000000..f7268c9
Binary files /dev/null and b/recyclerview_helper/app/src/main/res/mipmap-xxhdpi/twitter_pull_arrow.png differ
diff --git a/recyclerview_helper/app/src/main/res/mipmap-xxhdpi/twitter_pull_arrow_white.png b/recyclerview_helper/app/src/main/res/mipmap-xxhdpi/twitter_pull_arrow_white.png
new file mode 100644
index 0000000..515f8f2
Binary files /dev/null and b/recyclerview_helper/app/src/main/res/mipmap-xxhdpi/twitter_pull_arrow_white.png differ
diff --git a/recyclerview_helper/library/src/main/java/com/lvr/library/adapter/CommonAdapter.java b/recyclerview_helper/library/src/main/java/com/lvr/library/adapter/CommonAdapter.java
new file mode 100644
index 0000000..7ac0d83
--- /dev/null
+++ b/recyclerview_helper/library/src/main/java/com/lvr/library/adapter/CommonAdapter.java
@@ -0,0 +1,79 @@
+package com.lvr.library.adapter;
+
+import android.content.Context;
+import android.support.v7.widget.RecyclerView;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.lvr.library.holder.BaseViewHolder;
+
+import java.util.List;
+
+
+
+/**
+ * Created by lvr on 2017/5/24.
+ */
+
+public abstract class CommonAdapter extends RecyclerView.Adapter {
+ protected Context mContext;
+ protected int mLayoutId;
+ protected List mDatas;
+ protected OnItemClickListener mOnItemClickListener;
+ protected OnItemLongClickListener mOnItemLongClickListener;
+
+ public CommonAdapter(Context context, int layoutId, List datas)
+ {
+ mContext = context;
+ mLayoutId = layoutId;
+ mDatas = datas;
+ }
+ @Override
+ public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ final BaseViewHolder viewHolder = new BaseViewHolder(mContext,parent,mLayoutId);
+ return viewHolder;
+ }
+
+ @Override
+ public void onBindViewHolder(final BaseViewHolder holder, final int position) {
+ holder.itemView.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if(mOnItemClickListener!=null){
+ mOnItemClickListener.onItemClick(v,holder,position);
+ }
+ }
+ });
+ holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
+ @Override
+ public boolean onLongClick(View v) {
+ if(mOnItemLongClickListener!=null){
+ return mOnItemLongClickListener.onItemLongClick(v,holder,position);
+ }
+ return false;
+ }
+ });
+ convert(holder, position);
+ }
+
+ public abstract void convert(BaseViewHolder holder, int position);
+
+ @Override
+ public int getItemCount() {
+ return mDatas.size();
+ }
+
+ public interface OnItemClickListener {
+ void onItemClick(View view, RecyclerView.ViewHolder holder, int position);
+
+ }
+ public interface OnItemLongClickListener{
+ boolean onItemLongClick(View view, RecyclerView.ViewHolder holder, int position);
+ }
+ public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
+ this.mOnItemClickListener = onItemClickListener;
+ }
+ public void setOnItemLongClickListener(OnItemLongClickListener onItemLongClickListener) {
+ this.mOnItemLongClickListener = onItemLongClickListener;
+ }
+}
diff --git a/recyclerview_helper/library/src/main/java/com/lvr/library/adapter/MultiItemCommonAdapter.java b/recyclerview_helper/library/src/main/java/com/lvr/library/adapter/MultiItemCommonAdapter.java
new file mode 100644
index 0000000..cd785cb
--- /dev/null
+++ b/recyclerview_helper/library/src/main/java/com/lvr/library/adapter/MultiItemCommonAdapter.java
@@ -0,0 +1,42 @@
+package com.lvr.library.adapter;
+
+import android.content.Context;
+import android.view.ViewGroup;
+
+import com.lvr.library.holder.BaseViewHolder;
+import com.lvr.library.support.MultiItemTypeSupport;
+
+import java.util.List;
+
+/**
+ * Created by lvr on 2017/5/24.
+ */
+
+public abstract class MultiItemCommonAdapter extends CommonAdapter
+{
+ protected MultiItemTypeSupport mMultiItemTypeSupport;
+
+ public MultiItemCommonAdapter(Context context, List datas,
+ MultiItemTypeSupport multiItemTypeSupport)
+ {
+ super(context, -1, datas);
+ mMultiItemTypeSupport = multiItemTypeSupport;
+ }
+
+ @Override
+ public int getItemViewType(int position)
+ {
+ return mMultiItemTypeSupport.getItemViewType(position, mDatas.get(position));
+ }
+
+ @Override
+ public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
+ {
+ int layoutId = mMultiItemTypeSupport.getLayoutId(viewType);
+ BaseViewHolder holder = new BaseViewHolder(mContext, parent, layoutId);
+ return holder;
+ }
+
+
+
+}
diff --git a/recyclerview_helper/library/src/main/java/com/lvr/library/anims/adapters/AlphaInAnimationAdapter.java b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/adapters/AlphaInAnimationAdapter.java
new file mode 100644
index 0000000..b3bb527
--- /dev/null
+++ b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/adapters/AlphaInAnimationAdapter.java
@@ -0,0 +1,27 @@
+package com.lvr.library.anims.adapters;
+
+import android.animation.Animator;
+import android.animation.ObjectAnimator;
+import android.support.v7.widget.RecyclerView;
+import android.view.View;
+
+
+
+public class AlphaInAnimationAdapter extends AnimationAdapter {
+
+ private static final float DEFAULT_ALPHA_FROM = 0f;
+ private final float mFrom;
+
+ public AlphaInAnimationAdapter(RecyclerView.Adapter adapter) {
+ this(adapter, DEFAULT_ALPHA_FROM);
+ }
+
+ public AlphaInAnimationAdapter(RecyclerView.Adapter adapter, float from) {
+ super(adapter);
+ mFrom = from;
+ }
+
+ @Override protected Animator[] getAnimators(View view) {
+ return new Animator[] { ObjectAnimator.ofFloat(view, "alpha", mFrom, 1f) };
+ }
+}
diff --git a/recyclerview_helper/library/src/main/java/com/lvr/library/anims/adapters/AnimationAdapter.java b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/adapters/AnimationAdapter.java
new file mode 100644
index 0000000..7e4c005
--- /dev/null
+++ b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/adapters/AnimationAdapter.java
@@ -0,0 +1,93 @@
+package com.lvr.library.anims.adapters;
+
+import android.animation.Animator;
+import android.support.v7.widget.RecyclerView;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.Interpolator;
+import android.view.animation.LinearInterpolator;
+
+import com.lvr.library.anims.animators.ViewHelper;
+
+
+public abstract class AnimationAdapter extends RecyclerView.Adapter {
+
+ private RecyclerView.Adapter mAdapter;
+ private int mDuration = 300;
+ private Interpolator mInterpolator = new LinearInterpolator();
+ private int mLastPosition = -1;
+
+ private boolean isFirstOnly = true;
+
+ public AnimationAdapter(RecyclerView.Adapter adapter) {
+ mAdapter = adapter;
+ }
+
+ @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ return mAdapter.onCreateViewHolder(parent, viewType);
+ }
+
+ @Override public void registerAdapterDataObserver(RecyclerView.AdapterDataObserver observer) {
+ super.registerAdapterDataObserver(observer);
+ mAdapter.registerAdapterDataObserver(observer);
+ }
+
+ @Override public void unregisterAdapterDataObserver(RecyclerView.AdapterDataObserver observer) {
+ super.unregisterAdapterDataObserver(observer);
+ mAdapter.unregisterAdapterDataObserver(observer);
+ }
+
+ @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
+ mAdapter.onBindViewHolder(holder, position);
+
+ int adapterPosition = holder.getAdapterPosition();
+ if (!isFirstOnly || adapterPosition > mLastPosition) {
+ for (Animator anim : getAnimators(holder.itemView)) {
+ anim.setDuration(mDuration).start();
+ anim.setInterpolator(mInterpolator);
+ }
+ mLastPosition = adapterPosition;
+ } else {
+ ViewHelper.clear(holder.itemView);
+ }
+ }
+
+ @Override public void onViewRecycled(RecyclerView.ViewHolder holder) {
+ mAdapter.onViewRecycled(holder);
+ super.onViewRecycled(holder);
+ }
+
+ @Override public int getItemCount() {
+ return mAdapter.getItemCount();
+ }
+
+ public void setDuration(int duration) {
+ mDuration = duration;
+ }
+
+ public void setInterpolator(Interpolator interpolator) {
+ mInterpolator = interpolator;
+ }
+
+ public void setStartPosition(int start) {
+ mLastPosition = start;
+ }
+
+ protected abstract Animator[] getAnimators(View view);
+
+ public void setFirstOnly(boolean firstOnly) {
+ isFirstOnly = firstOnly;
+ }
+
+ @Override public int getItemViewType(int position) {
+ return mAdapter.getItemViewType(position);
+ }
+
+ public RecyclerView.Adapter getWrappedAdapter() {
+ return mAdapter;
+ }
+
+ @Override public long getItemId(int position) {
+ return mAdapter.getItemId(position);
+ }
+}
diff --git a/recyclerview_helper/library/src/main/java/com/lvr/library/anims/adapters/ScaleInAnimationAdapter.java b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/adapters/ScaleInAnimationAdapter.java
new file mode 100644
index 0000000..17ee837
--- /dev/null
+++ b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/adapters/ScaleInAnimationAdapter.java
@@ -0,0 +1,29 @@
+package com.lvr.library.anims.adapters;
+
+import android.animation.Animator;
+import android.animation.ObjectAnimator;
+import android.support.v7.widget.RecyclerView;
+import android.view.View;
+
+
+
+public class ScaleInAnimationAdapter extends AnimationAdapter {
+
+ private static final float DEFAULT_SCALE_FROM = .5f;
+ private final float mFrom;
+
+ public ScaleInAnimationAdapter(RecyclerView.Adapter adapter) {
+ this(adapter, DEFAULT_SCALE_FROM);
+ }
+
+ public ScaleInAnimationAdapter(RecyclerView.Adapter adapter, float from) {
+ super(adapter);
+ mFrom = from;
+ }
+
+ @Override protected Animator[] getAnimators(View view) {
+ ObjectAnimator scaleX = ObjectAnimator.ofFloat(view, "scaleX", mFrom, 1f);
+ ObjectAnimator scaleY = ObjectAnimator.ofFloat(view, "scaleY", mFrom, 1f);
+ return new ObjectAnimator[] { scaleX, scaleY };
+ }
+}
diff --git a/recyclerview_helper/library/src/main/java/com/lvr/library/anims/adapters/SlideInBottomAnimationAdapter.java b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/adapters/SlideInBottomAnimationAdapter.java
new file mode 100644
index 0000000..8f9c850
--- /dev/null
+++ b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/adapters/SlideInBottomAnimationAdapter.java
@@ -0,0 +1,35 @@
+package com.lvr.library.anims.adapters;
+
+import android.animation.Animator;
+import android.animation.ObjectAnimator;
+import android.support.v7.widget.RecyclerView;
+import android.view.View;
+
+/**
+ * Copyright (C) 2017 Wasabeef
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class SlideInBottomAnimationAdapter extends AnimationAdapter {
+
+ public SlideInBottomAnimationAdapter(RecyclerView.Adapter adapter) {
+ super(adapter);
+ }
+
+ @Override protected Animator[] getAnimators(View view) {
+ return new Animator[] {
+ ObjectAnimator.ofFloat(view, "translationY", view.getMeasuredHeight(), 0)
+ };
+ }
+}
diff --git a/recyclerview_helper/library/src/main/java/com/lvr/library/anims/adapters/SlideInLeftAnimationAdapter.java b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/adapters/SlideInLeftAnimationAdapter.java
new file mode 100644
index 0000000..a31c81b
--- /dev/null
+++ b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/adapters/SlideInLeftAnimationAdapter.java
@@ -0,0 +1,21 @@
+package com.lvr.library.anims.adapters;
+
+import android.animation.Animator;
+import android.animation.ObjectAnimator;
+import android.support.v7.widget.RecyclerView;
+import android.view.View;
+
+
+
+public class SlideInLeftAnimationAdapter extends AnimationAdapter {
+
+ public SlideInLeftAnimationAdapter(RecyclerView.Adapter adapter) {
+ super(adapter);
+ }
+
+ @Override protected Animator[] getAnimators(View view) {
+ return new Animator[] {
+ ObjectAnimator.ofFloat(view, "translationX", -view.getRootView().getWidth(), 0)
+ };
+ }
+}
diff --git a/recyclerview_helper/library/src/main/java/com/lvr/library/anims/adapters/SlideInRightAnimationAdapter.java b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/adapters/SlideInRightAnimationAdapter.java
new file mode 100644
index 0000000..ecea360
--- /dev/null
+++ b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/adapters/SlideInRightAnimationAdapter.java
@@ -0,0 +1,21 @@
+package com.lvr.library.anims.adapters;
+
+import android.animation.Animator;
+import android.animation.ObjectAnimator;
+import android.support.v7.widget.RecyclerView;
+import android.view.View;
+
+
+
+public class SlideInRightAnimationAdapter extends AnimationAdapter {
+
+ public SlideInRightAnimationAdapter(RecyclerView.Adapter adapter) {
+ super(adapter);
+ }
+
+ @Override protected Animator[] getAnimators(View view) {
+ return new Animator[] {
+ ObjectAnimator.ofFloat(view, "translationX", view.getRootView().getWidth(), 0)
+ };
+ }
+}
diff --git a/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/BaseItemAnimator.java b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/BaseItemAnimator.java
new file mode 100644
index 0000000..7018946
--- /dev/null
+++ b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/BaseItemAnimator.java
@@ -0,0 +1,708 @@
+package com.lvr.library.anims.animators;
+/*
+ * Copyright (C) 2017 Wasabeef
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+import android.support.v4.view.ViewCompat;
+import android.support.v4.view.ViewPropertyAnimatorCompat;
+import android.support.v4.view.ViewPropertyAnimatorListener;
+import android.support.v7.widget.RecyclerView.ViewHolder;
+import android.support.v7.widget.SimpleItemAnimator;
+import android.view.View;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.Interpolator;
+
+import com.lvr.library.anims.animators.holder.AnimateViewHolder;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+public abstract class BaseItemAnimator extends SimpleItemAnimator {
+
+ private static final boolean DEBUG = false;
+
+ private ArrayList mPendingRemovals = new ArrayList<>();
+ private ArrayList mPendingAdditions = new ArrayList<>();
+ private ArrayList mPendingMoves = new ArrayList<>();
+ private ArrayList mPendingChanges = new ArrayList<>();
+
+ private ArrayList> mAdditionsList = new ArrayList<>();
+ private ArrayList> mMovesList = new ArrayList<>();
+ private ArrayList> mChangesList = new ArrayList<>();
+
+ protected ArrayList mAddAnimations = new ArrayList<>();
+ private ArrayList mMoveAnimations = new ArrayList<>();
+ protected ArrayList mRemoveAnimations = new ArrayList<>();
+ private ArrayList mChangeAnimations = new ArrayList<>();
+
+ protected Interpolator mInterpolator = new DecelerateInterpolator();
+
+ private static class MoveInfo {
+
+ public ViewHolder holder;
+ public int fromX, fromY, toX, toY;
+
+ private MoveInfo(ViewHolder holder, int fromX, int fromY, int toX, int toY) {
+ this.holder = holder;
+ this.fromX = fromX;
+ this.fromY = fromY;
+ this.toX = toX;
+ this.toY = toY;
+ }
+ }
+
+ private static class ChangeInfo {
+
+ public ViewHolder oldHolder, newHolder;
+ public int fromX, fromY, toX, toY;
+
+ private ChangeInfo(ViewHolder oldHolder, ViewHolder newHolder) {
+ this.oldHolder = oldHolder;
+ this.newHolder = newHolder;
+ }
+
+ private ChangeInfo(ViewHolder oldHolder, ViewHolder newHolder, int fromX, int fromY, int toX,
+ int toY) {
+ this(oldHolder, newHolder);
+ this.fromX = fromX;
+ this.fromY = fromY;
+ this.toX = toX;
+ this.toY = toY;
+ }
+
+ @Override public String toString() {
+ return "ChangeInfo{" +
+ "oldHolder=" + oldHolder +
+ ", newHolder=" + newHolder +
+ ", fromX=" + fromX +
+ ", fromY=" + fromY +
+ ", toX=" + toX +
+ ", toY=" + toY +
+ '}';
+ }
+ }
+
+ public BaseItemAnimator() {
+ super();
+ setSupportsChangeAnimations(false);
+ }
+
+ public void setInterpolator(Interpolator mInterpolator) {
+ this.mInterpolator = mInterpolator;
+ }
+
+ @Override public void runPendingAnimations() {
+ boolean removalsPending = !mPendingRemovals.isEmpty();
+ boolean movesPending = !mPendingMoves.isEmpty();
+ boolean changesPending = !mPendingChanges.isEmpty();
+ boolean additionsPending = !mPendingAdditions.isEmpty();
+ if (!removalsPending && !movesPending && !additionsPending && !changesPending) {
+ // nothing to animate
+ return;
+ }
+ // First, remove stuff
+ for (ViewHolder holder : mPendingRemovals) {
+ doAnimateRemove(holder);
+ }
+ mPendingRemovals.clear();
+ // Next, move stuff
+ if (movesPending) {
+ final ArrayList moves = new ArrayList();
+ moves.addAll(mPendingMoves);
+ mMovesList.add(moves);
+ mPendingMoves.clear();
+ Runnable mover = new Runnable() {
+ @Override public void run() {
+ boolean removed = mMovesList.remove(moves);
+ if (!removed) {
+ // already canceled
+ return;
+ }
+ for (MoveInfo moveInfo : moves) {
+ animateMoveImpl(moveInfo.holder, moveInfo.fromX, moveInfo.fromY, moveInfo.toX,
+ moveInfo.toY);
+ }
+ moves.clear();
+ }
+ };
+ if (removalsPending) {
+ View view = moves.get(0).holder.itemView;
+ ViewCompat.postOnAnimationDelayed(view, mover, getRemoveDuration());
+ } else {
+ mover.run();
+ }
+ }
+ // Next, change stuff, to run in parallel with move animations
+ if (changesPending) {
+ final ArrayList changes = new ArrayList();
+ changes.addAll(mPendingChanges);
+ mChangesList.add(changes);
+ mPendingChanges.clear();
+ Runnable changer = new Runnable() {
+ @Override public void run() {
+ boolean removed = mChangesList.remove(changes);
+ if (!removed) {
+ // already canceled
+ return;
+ }
+ for (ChangeInfo change : changes) {
+ animateChangeImpl(change);
+ }
+ changes.clear();
+ }
+ };
+ if (removalsPending) {
+ ViewHolder holder = changes.get(0).oldHolder;
+ ViewCompat.postOnAnimationDelayed(holder.itemView, changer, getRemoveDuration());
+ } else {
+ changer.run();
+ }
+ }
+ // Next, add stuff
+ if (additionsPending) {
+ final ArrayList additions = new ArrayList();
+ additions.addAll(mPendingAdditions);
+ mAdditionsList.add(additions);
+ mPendingAdditions.clear();
+ Runnable adder = new Runnable() {
+ public void run() {
+ boolean removed = mAdditionsList.remove(additions);
+ if (!removed) {
+ // already canceled
+ return;
+ }
+ for (ViewHolder holder : additions) {
+ doAnimateAdd(holder);
+ }
+ additions.clear();
+ }
+ };
+ if (removalsPending || movesPending || changesPending) {
+ long removeDuration = removalsPending ? getRemoveDuration() : 0;
+ long moveDuration = movesPending ? getMoveDuration() : 0;
+ long changeDuration = changesPending ? getChangeDuration() : 0;
+ long totalDelay = removeDuration + Math.max(moveDuration, changeDuration);
+ View view = additions.get(0).itemView;
+ ViewCompat.postOnAnimationDelayed(view, adder, totalDelay);
+ } else {
+ adder.run();
+ }
+ }
+ }
+
+ protected void preAnimateRemoveImpl(final ViewHolder holder) {
+ }
+
+ protected void preAnimateAddImpl(final ViewHolder holder) {
+ }
+
+ protected abstract void animateRemoveImpl(final ViewHolder holder);
+
+ protected abstract void animateAddImpl(final ViewHolder holder);
+
+ private void preAnimateRemove(final ViewHolder holder) {
+ ViewHelper.clear(holder.itemView);
+
+ if (holder instanceof AnimateViewHolder) {
+ ((AnimateViewHolder) holder).preAnimateRemoveImpl(holder);
+ } else {
+ preAnimateRemoveImpl(holder);
+ }
+ }
+
+ private void preAnimateAdd(final ViewHolder holder) {
+ ViewHelper.clear(holder.itemView);
+
+ if (holder instanceof AnimateViewHolder) {
+ ((AnimateViewHolder) holder).preAnimateAddImpl(holder);
+ } else {
+ preAnimateAddImpl(holder);
+ }
+ }
+
+ private void doAnimateRemove(final ViewHolder holder) {
+ if (holder instanceof AnimateViewHolder) {
+ ((AnimateViewHolder) holder).animateRemoveImpl(holder, new DefaultRemoveVpaListener(holder));
+ } else {
+ animateRemoveImpl(holder);
+ }
+
+ mRemoveAnimations.add(holder);
+ }
+
+ private void doAnimateAdd(final ViewHolder holder) {
+ if (holder instanceof AnimateViewHolder) {
+ ((AnimateViewHolder) holder).animateAddImpl(holder, new DefaultAddVpaListener(holder));
+ } else {
+ animateAddImpl(holder);
+ }
+
+ mAddAnimations.add(holder);
+ }
+
+ @Override public boolean animateRemove(final ViewHolder holder) {
+ endAnimation(holder);
+ preAnimateRemove(holder);
+ mPendingRemovals.add(holder);
+ return true;
+ }
+
+ protected long getRemoveDelay(final ViewHolder holder) {
+ return Math.abs(holder.getOldPosition() * getRemoveDuration() / 4);
+ }
+
+ @Override public boolean animateAdd(final ViewHolder holder) {
+ endAnimation(holder);
+ preAnimateAdd(holder);
+ mPendingAdditions.add(holder);
+ return true;
+ }
+
+ protected long getAddDelay(final ViewHolder holder) {
+ return Math.abs(holder.getAdapterPosition() * getAddDuration() / 4);
+ }
+
+ @Override
+ public boolean animateMove(final ViewHolder holder, int fromX, int fromY, int toX, int toY) {
+ final View view = holder.itemView;
+ fromX += ViewCompat.getTranslationX(holder.itemView);
+ fromY += ViewCompat.getTranslationY(holder.itemView);
+ endAnimation(holder);
+ int deltaX = toX - fromX;
+ int deltaY = toY - fromY;
+ if (deltaX == 0 && deltaY == 0) {
+ dispatchMoveFinished(holder);
+ return false;
+ }
+ if (deltaX != 0) {
+ ViewCompat.setTranslationX(view, -deltaX);
+ }
+ if (deltaY != 0) {
+ ViewCompat.setTranslationY(view, -deltaY);
+ }
+ mPendingMoves.add(new MoveInfo(holder, fromX, fromY, toX, toY));
+ return true;
+ }
+
+ private void animateMoveImpl(final ViewHolder holder, int fromX, int fromY, int toX, int toY) {
+ final View view = holder.itemView;
+ final int deltaX = toX - fromX;
+ final int deltaY = toY - fromY;
+ if (deltaX != 0) {
+ ViewCompat.animate(view).translationX(0);
+ }
+ if (deltaY != 0) {
+ ViewCompat.animate(view).translationY(0);
+ }
+ // TODO: make EndActions end listeners instead, since end actions aren't called when
+ // vpas are canceled (and can't end them. why?)
+ // need listener functionality in VPACompat for this. Ick.
+ mMoveAnimations.add(holder);
+ final ViewPropertyAnimatorCompat animation = ViewCompat.animate(view);
+ animation.setDuration(getMoveDuration()).setListener(new VpaListenerAdapter() {
+ @Override public void onAnimationStart(View view) {
+ dispatchMoveStarting(holder);
+ }
+
+ @Override public void onAnimationCancel(View view) {
+ if (deltaX != 0) {
+ ViewCompat.setTranslationX(view, 0);
+ }
+ if (deltaY != 0) {
+ ViewCompat.setTranslationY(view, 0);
+ }
+ }
+
+ @Override public void onAnimationEnd(View view) {
+ animation.setListener(null);
+ dispatchMoveFinished(holder);
+ mMoveAnimations.remove(holder);
+ dispatchFinishedWhenDone();
+ }
+ }).start();
+ }
+
+ @Override
+ public boolean animateChange(ViewHolder oldHolder, ViewHolder newHolder, int fromX, int fromY,
+ int toX, int toY) {
+ final float prevTranslationX = ViewCompat.getTranslationX(oldHolder.itemView);
+ final float prevTranslationY = ViewCompat.getTranslationY(oldHolder.itemView);
+ final float prevAlpha = ViewCompat.getAlpha(oldHolder.itemView);
+ endAnimation(oldHolder);
+ int deltaX = (int) (toX - fromX - prevTranslationX);
+ int deltaY = (int) (toY - fromY - prevTranslationY);
+ // recover prev translation state after ending animation
+ ViewCompat.setTranslationX(oldHolder.itemView, prevTranslationX);
+ ViewCompat.setTranslationY(oldHolder.itemView, prevTranslationY);
+ ViewCompat.setAlpha(oldHolder.itemView, prevAlpha);
+ if (newHolder != null && newHolder.itemView != null) {
+ // carry over translation values
+ endAnimation(newHolder);
+ ViewCompat.setTranslationX(newHolder.itemView, -deltaX);
+ ViewCompat.setTranslationY(newHolder.itemView, -deltaY);
+ ViewCompat.setAlpha(newHolder.itemView, 0);
+ }
+ mPendingChanges.add(new ChangeInfo(oldHolder, newHolder, fromX, fromY, toX, toY));
+ return true;
+ }
+
+ private void animateChangeImpl(final ChangeInfo changeInfo) {
+ final ViewHolder holder = changeInfo.oldHolder;
+ final View view = holder == null ? null : holder.itemView;
+ final ViewHolder newHolder = changeInfo.newHolder;
+ final View newView = newHolder != null ? newHolder.itemView : null;
+ if (view != null) {
+ mChangeAnimations.add(changeInfo.oldHolder);
+ final ViewPropertyAnimatorCompat oldViewAnim =
+ ViewCompat.animate(view).setDuration(getChangeDuration());
+ oldViewAnim.translationX(changeInfo.toX - changeInfo.fromX);
+ oldViewAnim.translationY(changeInfo.toY - changeInfo.fromY);
+ oldViewAnim.alpha(0).setListener(new VpaListenerAdapter() {
+ @Override public void onAnimationStart(View view) {
+ dispatchChangeStarting(changeInfo.oldHolder, true);
+ }
+
+ @Override public void onAnimationEnd(View view) {
+ oldViewAnim.setListener(null);
+ ViewCompat.setAlpha(view, 1);
+ ViewCompat.setTranslationX(view, 0);
+ ViewCompat.setTranslationY(view, 0);
+ dispatchChangeFinished(changeInfo.oldHolder, true);
+ mChangeAnimations.remove(changeInfo.oldHolder);
+ dispatchFinishedWhenDone();
+ }
+ }).start();
+ }
+ if (newView != null) {
+ mChangeAnimations.add(changeInfo.newHolder);
+ final ViewPropertyAnimatorCompat newViewAnimation = ViewCompat.animate(newView);
+ newViewAnimation.translationX(0).translationY(0).setDuration(getChangeDuration()).
+ alpha(1).setListener(new VpaListenerAdapter() {
+ @Override public void onAnimationStart(View view) {
+ dispatchChangeStarting(changeInfo.newHolder, false);
+ }
+
+ @Override public void onAnimationEnd(View view) {
+ newViewAnimation.setListener(null);
+ ViewCompat.setAlpha(newView, 1);
+ ViewCompat.setTranslationX(newView, 0);
+ ViewCompat.setTranslationY(newView, 0);
+ dispatchChangeFinished(changeInfo.newHolder, false);
+ mChangeAnimations.remove(changeInfo.newHolder);
+ dispatchFinishedWhenDone();
+ }
+ }).start();
+ }
+ }
+
+ private void endChangeAnimation(List infoList, ViewHolder item) {
+ for (int i = infoList.size() - 1; i >= 0; i--) {
+ ChangeInfo changeInfo = infoList.get(i);
+ if (endChangeAnimationIfNecessary(changeInfo, item)) {
+ if (changeInfo.oldHolder == null && changeInfo.newHolder == null) {
+ infoList.remove(changeInfo);
+ }
+ }
+ }
+ }
+
+ private void endChangeAnimationIfNecessary(ChangeInfo changeInfo) {
+ if (changeInfo.oldHolder != null) {
+ endChangeAnimationIfNecessary(changeInfo, changeInfo.oldHolder);
+ }
+ if (changeInfo.newHolder != null) {
+ endChangeAnimationIfNecessary(changeInfo, changeInfo.newHolder);
+ }
+ }
+
+ private boolean endChangeAnimationIfNecessary(ChangeInfo changeInfo, ViewHolder item) {
+ boolean oldItem = false;
+ if (changeInfo.newHolder == item) {
+ changeInfo.newHolder = null;
+ } else if (changeInfo.oldHolder == item) {
+ changeInfo.oldHolder = null;
+ oldItem = true;
+ } else {
+ return false;
+ }
+ ViewCompat.setAlpha(item.itemView, 1);
+ ViewCompat.setTranslationX(item.itemView, 0);
+ ViewCompat.setTranslationY(item.itemView, 0);
+ dispatchChangeFinished(item, oldItem);
+ return true;
+ }
+
+ @Override public void endAnimation(ViewHolder item) {
+ final View view = item.itemView;
+ // this will trigger end callback which should set properties to their target values.
+ ViewCompat.animate(view).cancel();
+ // TODO if some other animations are chained to end, how do we cancel them as well?
+ for (int i = mPendingMoves.size() - 1; i >= 0; i--) {
+ MoveInfo moveInfo = mPendingMoves.get(i);
+ if (moveInfo.holder == item) {
+ ViewCompat.setTranslationY(view, 0);
+ ViewCompat.setTranslationX(view, 0);
+ dispatchMoveFinished(item);
+ mPendingMoves.remove(i);
+ }
+ }
+ endChangeAnimation(mPendingChanges, item);
+ if (mPendingRemovals.remove(item)) {
+ ViewHelper.clear(item.itemView);
+ dispatchRemoveFinished(item);
+ }
+ if (mPendingAdditions.remove(item)) {
+ ViewHelper.clear(item.itemView);
+ dispatchAddFinished(item);
+ }
+
+ for (int i = mChangesList.size() - 1; i >= 0; i--) {
+ ArrayList changes = mChangesList.get(i);
+ endChangeAnimation(changes, item);
+ if (changes.isEmpty()) {
+ mChangesList.remove(i);
+ }
+ }
+ for (int i = mMovesList.size() - 1; i >= 0; i--) {
+ ArrayList moves = mMovesList.get(i);
+ for (int j = moves.size() - 1; j >= 0; j--) {
+ MoveInfo moveInfo = moves.get(j);
+ if (moveInfo.holder == item) {
+ ViewCompat.setTranslationY(view, 0);
+ ViewCompat.setTranslationX(view, 0);
+ dispatchMoveFinished(item);
+ moves.remove(j);
+ if (moves.isEmpty()) {
+ mMovesList.remove(i);
+ }
+ break;
+ }
+ }
+ }
+ for (int i = mAdditionsList.size() - 1; i >= 0; i--) {
+ ArrayList additions = mAdditionsList.get(i);
+ if (additions.remove(item)) {
+ ViewHelper.clear(item.itemView);
+ dispatchAddFinished(item);
+ if (additions.isEmpty()) {
+ mAdditionsList.remove(i);
+ }
+ }
+ }
+
+ // animations should be ended by the cancel above.
+ if (mRemoveAnimations.remove(item) && DEBUG) {
+ throw new IllegalStateException(
+ "after animation is cancelled, item should not be in " + "mRemoveAnimations list");
+ }
+
+ if (mAddAnimations.remove(item) && DEBUG) {
+ throw new IllegalStateException(
+ "after animation is cancelled, item should not be in " + "mAddAnimations list");
+ }
+
+ if (mChangeAnimations.remove(item) && DEBUG) {
+ throw new IllegalStateException(
+ "after animation is cancelled, item should not be in " + "mChangeAnimations list");
+ }
+
+ if (mMoveAnimations.remove(item) && DEBUG) {
+ throw new IllegalStateException(
+ "after animation is cancelled, item should not be in " + "mMoveAnimations list");
+ }
+ dispatchFinishedWhenDone();
+ }
+
+ @Override public boolean isRunning() {
+ return (!mPendingAdditions.isEmpty() ||
+ !mPendingChanges.isEmpty() ||
+ !mPendingMoves.isEmpty() ||
+ !mPendingRemovals.isEmpty() ||
+ !mMoveAnimations.isEmpty() ||
+ !mRemoveAnimations.isEmpty() ||
+ !mAddAnimations.isEmpty() ||
+ !mChangeAnimations.isEmpty() ||
+ !mMovesList.isEmpty() ||
+ !mAdditionsList.isEmpty() ||
+ !mChangesList.isEmpty());
+ }
+
+ /**
+ * Check the state of currently pending and running animations. If there are none
+ * pending/running, call #dispatchAnimationsFinished() to notify any
+ * listeners.
+ */
+ private void dispatchFinishedWhenDone() {
+ if (!isRunning()) {
+ dispatchAnimationsFinished();
+ }
+ }
+
+ @Override public void endAnimations() {
+ int count = mPendingMoves.size();
+ for (int i = count - 1; i >= 0; i--) {
+ MoveInfo item = mPendingMoves.get(i);
+ View view = item.holder.itemView;
+ ViewCompat.setTranslationY(view, 0);
+ ViewCompat.setTranslationX(view, 0);
+ dispatchMoveFinished(item.holder);
+ mPendingMoves.remove(i);
+ }
+ count = mPendingRemovals.size();
+ for (int i = count - 1; i >= 0; i--) {
+ ViewHolder item = mPendingRemovals.get(i);
+ dispatchRemoveFinished(item);
+ mPendingRemovals.remove(i);
+ }
+ count = mPendingAdditions.size();
+ for (int i = count - 1; i >= 0; i--) {
+ ViewHolder item = mPendingAdditions.get(i);
+ ViewHelper.clear(item.itemView);
+ dispatchAddFinished(item);
+ mPendingAdditions.remove(i);
+ }
+ count = mPendingChanges.size();
+ for (int i = count - 1; i >= 0; i--) {
+ endChangeAnimationIfNecessary(mPendingChanges.get(i));
+ }
+ mPendingChanges.clear();
+ if (!isRunning()) {
+ return;
+ }
+
+ int listCount = mMovesList.size();
+ for (int i = listCount - 1; i >= 0; i--) {
+ ArrayList moves = mMovesList.get(i);
+ count = moves.size();
+ for (int j = count - 1; j >= 0; j--) {
+ MoveInfo moveInfo = moves.get(j);
+ ViewHolder item = moveInfo.holder;
+ View view = item.itemView;
+ ViewCompat.setTranslationY(view, 0);
+ ViewCompat.setTranslationX(view, 0);
+ dispatchMoveFinished(moveInfo.holder);
+ moves.remove(j);
+ if (moves.isEmpty()) {
+ mMovesList.remove(moves);
+ }
+ }
+ }
+ listCount = mAdditionsList.size();
+ for (int i = listCount - 1; i >= 0; i--) {
+ ArrayList additions = mAdditionsList.get(i);
+ count = additions.size();
+ for (int j = count - 1; j >= 0; j--) {
+ ViewHolder item = additions.get(j);
+ View view = item.itemView;
+ ViewCompat.setAlpha(view, 1);
+ dispatchAddFinished(item);
+ //this check prevent exception when removal already happened during finishing animation
+ if (j < additions.size()) {
+ additions.remove(j);
+ }
+ if (additions.isEmpty()) {
+ mAdditionsList.remove(additions);
+ }
+ }
+ }
+ listCount = mChangesList.size();
+ for (int i = listCount - 1; i >= 0; i--) {
+ ArrayList changes = mChangesList.get(i);
+ count = changes.size();
+ for (int j = count - 1; j >= 0; j--) {
+ endChangeAnimationIfNecessary(changes.get(j));
+ if (changes.isEmpty()) {
+ mChangesList.remove(changes);
+ }
+ }
+ }
+
+ cancelAll(mRemoveAnimations);
+ cancelAll(mMoveAnimations);
+ cancelAll(mAddAnimations);
+ cancelAll(mChangeAnimations);
+
+ dispatchAnimationsFinished();
+ }
+
+ void cancelAll(List viewHolders) {
+ for (int i = viewHolders.size() - 1; i >= 0; i--) {
+ ViewCompat.animate(viewHolders.get(i).itemView).cancel();
+ }
+ }
+
+ private static class VpaListenerAdapter implements ViewPropertyAnimatorListener {
+
+ @Override public void onAnimationStart(View view) {
+ }
+
+ @Override public void onAnimationEnd(View view) {
+ }
+
+ @Override public void onAnimationCancel(View view) {
+ }
+ }
+
+ protected class DefaultAddVpaListener extends VpaListenerAdapter {
+
+ ViewHolder mViewHolder;
+
+ public DefaultAddVpaListener(final ViewHolder holder) {
+ mViewHolder = holder;
+ }
+
+ @Override public void onAnimationStart(View view) {
+ dispatchAddStarting(mViewHolder);
+ }
+
+ @Override public void onAnimationCancel(View view) {
+ ViewHelper.clear(view);
+ }
+
+ @Override public void onAnimationEnd(View view) {
+ ViewHelper.clear(view);
+ dispatchAddFinished(mViewHolder);
+ mAddAnimations.remove(mViewHolder);
+ dispatchFinishedWhenDone();
+ }
+ }
+
+ protected class DefaultRemoveVpaListener extends VpaListenerAdapter {
+
+ ViewHolder mViewHolder;
+
+ public DefaultRemoveVpaListener(final ViewHolder holder) {
+ mViewHolder = holder;
+ }
+
+ @Override public void onAnimationStart(View view) {
+ dispatchRemoveStarting(mViewHolder);
+ }
+
+ @Override public void onAnimationCancel(View view) {
+ ViewHelper.clear(view);
+ }
+
+ @Override public void onAnimationEnd(View view) {
+ ViewHelper.clear(view);
+ dispatchRemoveFinished(mViewHolder);
+ mRemoveAnimations.remove(mViewHolder);
+ dispatchFinishedWhenDone();
+ }
+ }
+}
diff --git a/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/FadeInAnimator.java b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/FadeInAnimator.java
new file mode 100644
index 0000000..fd7310e
--- /dev/null
+++ b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/FadeInAnimator.java
@@ -0,0 +1,55 @@
+package com.lvr.library.anims.animators;
+
+/**
+ * Copyright (C) 2017 Wasabeef
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import android.support.v4.view.ViewCompat;
+import android.support.v7.widget.RecyclerView;
+import android.view.animation.Interpolator;
+
+public class FadeInAnimator extends BaseItemAnimator {
+
+ public FadeInAnimator() {
+ }
+
+ public FadeInAnimator(Interpolator interpolator) {
+ mInterpolator = interpolator;
+ }
+
+ @Override protected void animateRemoveImpl(final RecyclerView.ViewHolder holder) {
+ ViewCompat.animate(holder.itemView)
+ .alpha(0)
+ .setDuration(getRemoveDuration())
+ .setInterpolator(mInterpolator)
+ .setListener(new DefaultRemoveVpaListener(holder))
+ .setStartDelay(getRemoveDelay(holder))
+ .start();
+ }
+
+ @Override protected void preAnimateAddImpl(RecyclerView.ViewHolder holder) {
+ ViewCompat.setAlpha(holder.itemView, 0);
+ }
+
+ @Override protected void animateAddImpl(final RecyclerView.ViewHolder holder) {
+ ViewCompat.animate(holder.itemView)
+ .alpha(1)
+ .setDuration(getAddDuration())
+ .setInterpolator(mInterpolator)
+ .setListener(new DefaultAddVpaListener(holder))
+ .setStartDelay(getAddDelay(holder))
+ .start();
+ }
+}
diff --git a/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/FadeInDownAnimator.java b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/FadeInDownAnimator.java
new file mode 100644
index 0000000..a04d45e
--- /dev/null
+++ b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/FadeInDownAnimator.java
@@ -0,0 +1,58 @@
+package com.lvr.library.anims.animators;
+
+/**
+ * Copyright (C) 2017 Wasabeef
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import android.support.v4.view.ViewCompat;
+import android.support.v7.widget.RecyclerView;
+import android.view.animation.Interpolator;
+
+public class FadeInDownAnimator extends BaseItemAnimator {
+
+ public FadeInDownAnimator() {
+ }
+
+ public FadeInDownAnimator(Interpolator interpolator) {
+ mInterpolator = interpolator;
+ }
+
+ @Override protected void animateRemoveImpl(final RecyclerView.ViewHolder holder) {
+ ViewCompat.animate(holder.itemView)
+ .translationY(-holder.itemView.getHeight() * .25f)
+ .alpha(0)
+ .setDuration(getRemoveDuration())
+ .setInterpolator(mInterpolator)
+ .setListener(new DefaultRemoveVpaListener(holder))
+ .setStartDelay(getRemoveDelay(holder))
+ .start();
+ }
+
+ @Override protected void preAnimateAddImpl(RecyclerView.ViewHolder holder) {
+ ViewCompat.setTranslationY(holder.itemView, -holder.itemView.getHeight() * .25f);
+ ViewCompat.setAlpha(holder.itemView, 0);
+ }
+
+ @Override protected void animateAddImpl(final RecyclerView.ViewHolder holder) {
+ ViewCompat.animate(holder.itemView)
+ .translationY(0)
+ .alpha(1)
+ .setDuration(getAddDuration())
+ .setInterpolator(mInterpolator)
+ .setListener(new DefaultAddVpaListener(holder))
+ .setStartDelay(getAddDelay(holder))
+ .start();
+ }
+}
diff --git a/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/FadeInLeftAnimator.java b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/FadeInLeftAnimator.java
new file mode 100644
index 0000000..3b4f53a
--- /dev/null
+++ b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/FadeInLeftAnimator.java
@@ -0,0 +1,58 @@
+package com.lvr.library.anims.animators;
+
+/**
+ * Copyright (C) 2017 Wasabeef
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import android.support.v4.view.ViewCompat;
+import android.support.v7.widget.RecyclerView;
+import android.view.animation.Interpolator;
+
+public class FadeInLeftAnimator extends BaseItemAnimator {
+
+ public FadeInLeftAnimator() {
+ }
+
+ public FadeInLeftAnimator(Interpolator interpolator) {
+ mInterpolator = interpolator;
+ }
+
+ @Override protected void animateRemoveImpl(final RecyclerView.ViewHolder holder) {
+ ViewCompat.animate(holder.itemView)
+ .translationX(-holder.itemView.getRootView().getWidth() * .25f)
+ .alpha(0)
+ .setDuration(getRemoveDuration())
+ .setInterpolator(mInterpolator)
+ .setListener(new DefaultRemoveVpaListener(holder))
+ .setStartDelay(getRemoveDelay(holder))
+ .start();
+ }
+
+ @Override protected void preAnimateAddImpl(RecyclerView.ViewHolder holder) {
+ ViewCompat.setTranslationX(holder.itemView, -holder.itemView.getRootView().getWidth() * .25f);
+ ViewCompat.setAlpha(holder.itemView, 0);
+ }
+
+ @Override protected void animateAddImpl(final RecyclerView.ViewHolder holder) {
+ ViewCompat.animate(holder.itemView)
+ .translationX(0)
+ .alpha(1)
+ .setDuration(getAddDuration())
+ .setInterpolator(mInterpolator)
+ .setListener(new DefaultAddVpaListener(holder))
+ .setStartDelay(getAddDelay(holder))
+ .start();
+ }
+}
diff --git a/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/FadeInRightAnimator.java b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/FadeInRightAnimator.java
new file mode 100644
index 0000000..04d825f
--- /dev/null
+++ b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/FadeInRightAnimator.java
@@ -0,0 +1,58 @@
+package com.lvr.library.anims.animators;
+
+/**
+ * Copyright (C) 2017 Wasabeef
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import android.support.v4.view.ViewCompat;
+import android.support.v7.widget.RecyclerView;
+import android.view.animation.Interpolator;
+
+public class FadeInRightAnimator extends BaseItemAnimator {
+
+ public FadeInRightAnimator() {
+ }
+
+ public FadeInRightAnimator(Interpolator interpolator) {
+ mInterpolator = interpolator;
+ }
+
+ @Override protected void animateRemoveImpl(final RecyclerView.ViewHolder holder) {
+ ViewCompat.animate(holder.itemView)
+ .translationX(holder.itemView.getRootView().getWidth() * .25f)
+ .alpha(0)
+ .setDuration(getRemoveDuration())
+ .setInterpolator(mInterpolator)
+ .setListener(new DefaultRemoveVpaListener(holder))
+ .setStartDelay(getRemoveDelay(holder))
+ .start();
+ }
+
+ @Override protected void preAnimateAddImpl(RecyclerView.ViewHolder holder) {
+ ViewCompat.setTranslationX(holder.itemView, holder.itemView.getRootView().getWidth() * .25f);
+ ViewCompat.setAlpha(holder.itemView, 0);
+ }
+
+ @Override protected void animateAddImpl(final RecyclerView.ViewHolder holder) {
+ ViewCompat.animate(holder.itemView)
+ .translationX(0)
+ .alpha(1)
+ .setDuration(getAddDuration())
+ .setInterpolator(mInterpolator)
+ .setListener(new DefaultAddVpaListener(holder))
+ .setStartDelay(getAddDelay(holder))
+ .start();
+ }
+}
diff --git a/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/FadeInUpAnimator.java b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/FadeInUpAnimator.java
new file mode 100644
index 0000000..9f9d074
--- /dev/null
+++ b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/FadeInUpAnimator.java
@@ -0,0 +1,58 @@
+package com.lvr.library.anims.animators;
+
+/**
+ * Copyright (C) 2017 Wasabeef
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import android.support.v4.view.ViewCompat;
+import android.support.v7.widget.RecyclerView;
+import android.view.animation.Interpolator;
+
+public class FadeInUpAnimator extends BaseItemAnimator {
+
+ public FadeInUpAnimator() {
+ }
+
+ public FadeInUpAnimator(Interpolator interpolator) {
+ mInterpolator = interpolator;
+ }
+
+ @Override protected void animateRemoveImpl(final RecyclerView.ViewHolder holder) {
+ ViewCompat.animate(holder.itemView)
+ .translationY(holder.itemView.getHeight() * .25f)
+ .alpha(0)
+ .setDuration(getRemoveDuration())
+ .setInterpolator(mInterpolator)
+ .setListener(new DefaultRemoveVpaListener(holder))
+ .setStartDelay(getRemoveDelay(holder))
+ .start();
+ }
+
+ @Override protected void preAnimateAddImpl(RecyclerView.ViewHolder holder) {
+ ViewCompat.setTranslationY(holder.itemView, holder.itemView.getHeight() * .25f);
+ ViewCompat.setAlpha(holder.itemView, 0);
+ }
+
+ @Override protected void animateAddImpl(final RecyclerView.ViewHolder holder) {
+ ViewCompat.animate(holder.itemView)
+ .translationY(0)
+ .alpha(1)
+ .setDuration(getAddDuration())
+ .setInterpolator(mInterpolator)
+ .setListener(new DefaultAddVpaListener(holder))
+ .setStartDelay(getAddDelay(holder))
+ .start();
+ }
+}
diff --git a/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/FlipInBottomXAnimator.java b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/FlipInBottomXAnimator.java
new file mode 100644
index 0000000..c9c744b
--- /dev/null
+++ b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/FlipInBottomXAnimator.java
@@ -0,0 +1,55 @@
+package com.lvr.library.anims.animators;
+
+/**
+ * Copyright (C) 2017 Wasabeef
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import android.support.v4.view.ViewCompat;
+import android.support.v7.widget.RecyclerView;
+import android.view.animation.Interpolator;
+
+public class FlipInBottomXAnimator extends BaseItemAnimator {
+
+ public FlipInBottomXAnimator() {
+ }
+
+ public FlipInBottomXAnimator(Interpolator interpolator) {
+ mInterpolator = interpolator;
+ }
+
+ @Override protected void animateRemoveImpl(final RecyclerView.ViewHolder holder) {
+ ViewCompat.animate(holder.itemView)
+ .rotationX(-90)
+ .setDuration(getRemoveDuration())
+ .setInterpolator(mInterpolator)
+ .setListener(new DefaultRemoveVpaListener(holder))
+ .setStartDelay(getRemoveDelay(holder))
+ .start();
+ }
+
+ @Override protected void preAnimateAddImpl(RecyclerView.ViewHolder holder) {
+ ViewCompat.setRotationX(holder.itemView, -90);
+ }
+
+ @Override protected void animateAddImpl(final RecyclerView.ViewHolder holder) {
+ ViewCompat.animate(holder.itemView)
+ .rotationX(0)
+ .setDuration(getAddDuration())
+ .setInterpolator(mInterpolator)
+ .setListener(new DefaultAddVpaListener(holder))
+ .setStartDelay(getAddDelay(holder))
+ .start();
+ }
+}
diff --git a/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/FlipInLeftYAnimator.java b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/FlipInLeftYAnimator.java
new file mode 100644
index 0000000..aa8f40b
--- /dev/null
+++ b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/FlipInLeftYAnimator.java
@@ -0,0 +1,55 @@
+package com.lvr.library.anims.animators;
+
+/**
+ * Copyright (C) 2017 Wasabeef
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import android.support.v4.view.ViewCompat;
+import android.support.v7.widget.RecyclerView;
+import android.view.animation.Interpolator;
+
+public class FlipInLeftYAnimator extends BaseItemAnimator {
+
+ public FlipInLeftYAnimator() {
+ }
+
+ public FlipInLeftYAnimator(Interpolator interpolator) {
+ mInterpolator = interpolator;
+ }
+
+ @Override protected void animateRemoveImpl(final RecyclerView.ViewHolder holder) {
+ ViewCompat.animate(holder.itemView)
+ .rotationY(90)
+ .setDuration(getRemoveDuration())
+ .setInterpolator(mInterpolator)
+ .setListener(new DefaultRemoveVpaListener(holder))
+ .setStartDelay(getRemoveDelay(holder))
+ .start();
+ }
+
+ @Override protected void preAnimateAddImpl(RecyclerView.ViewHolder holder) {
+ ViewCompat.setRotationY(holder.itemView, 90);
+ }
+
+ @Override protected void animateAddImpl(final RecyclerView.ViewHolder holder) {
+ ViewCompat.animate(holder.itemView)
+ .rotationY(0)
+ .setDuration(getAddDuration())
+ .setInterpolator(mInterpolator)
+ .setListener(new DefaultAddVpaListener(holder))
+ .setStartDelay(getAddDelay(holder))
+ .start();
+ }
+}
diff --git a/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/FlipInRightYAnimator.java b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/FlipInRightYAnimator.java
new file mode 100644
index 0000000..060c372
--- /dev/null
+++ b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/FlipInRightYAnimator.java
@@ -0,0 +1,55 @@
+package com.lvr.library.anims.animators;
+
+/**
+ * Copyright (C) 2017 Wasabeef
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import android.support.v4.view.ViewCompat;
+import android.support.v7.widget.RecyclerView;
+import android.view.animation.Interpolator;
+
+public class FlipInRightYAnimator extends BaseItemAnimator {
+
+ public FlipInRightYAnimator() {
+ }
+
+ public FlipInRightYAnimator(Interpolator interpolator) {
+ mInterpolator = interpolator;
+ }
+
+ @Override protected void animateRemoveImpl(final RecyclerView.ViewHolder holder) {
+ ViewCompat.animate(holder.itemView)
+ .rotationY(-90)
+ .setDuration(getRemoveDuration())
+ .setInterpolator(mInterpolator)
+ .setListener(new DefaultRemoveVpaListener(holder))
+ .setStartDelay(getRemoveDelay(holder))
+ .start();
+ }
+
+ @Override protected void preAnimateAddImpl(RecyclerView.ViewHolder holder) {
+ ViewCompat.setRotationY(holder.itemView, -90);
+ }
+
+ @Override protected void animateAddImpl(final RecyclerView.ViewHolder holder) {
+ ViewCompat.animate(holder.itemView)
+ .rotationY(0)
+ .setDuration(getAddDuration())
+ .setInterpolator(mInterpolator)
+ .setListener(new DefaultAddVpaListener(holder))
+ .setStartDelay(getAddDelay(holder))
+ .start();
+ }
+}
diff --git a/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/FlipInTopXAnimator.java b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/FlipInTopXAnimator.java
new file mode 100644
index 0000000..5b35245
--- /dev/null
+++ b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/FlipInTopXAnimator.java
@@ -0,0 +1,55 @@
+package com.lvr.library.anims.animators;
+
+/**
+ * Copyright (C) 2017 Wasabeef
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import android.support.v4.view.ViewCompat;
+import android.support.v7.widget.RecyclerView;
+import android.view.animation.Interpolator;
+
+public class FlipInTopXAnimator extends BaseItemAnimator {
+
+ public FlipInTopXAnimator() {
+ }
+
+ public FlipInTopXAnimator(Interpolator interpolator) {
+ mInterpolator = interpolator;
+ }
+
+ @Override protected void animateRemoveImpl(final RecyclerView.ViewHolder holder) {
+ ViewCompat.animate(holder.itemView)
+ .rotationX(90)
+ .setDuration(getRemoveDuration())
+ .setInterpolator(mInterpolator)
+ .setListener(new DefaultRemoveVpaListener(holder))
+ .setStartDelay(getRemoveDelay(holder))
+ .start();
+ }
+
+ @Override protected void preAnimateAddImpl(RecyclerView.ViewHolder holder) {
+ ViewCompat.setRotationX(holder.itemView, 90);
+ }
+
+ @Override protected void animateAddImpl(final RecyclerView.ViewHolder holder) {
+ ViewCompat.animate(holder.itemView)
+ .rotationX(0)
+ .setDuration(getAddDuration())
+ .setInterpolator(mInterpolator)
+ .setListener(new DefaultAddVpaListener(holder))
+ .setStartDelay(getAddDelay(holder))
+ .start();
+ }
+}
diff --git a/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/LandingAnimator.java b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/LandingAnimator.java
new file mode 100644
index 0000000..3b7405c
--- /dev/null
+++ b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/LandingAnimator.java
@@ -0,0 +1,61 @@
+package com.lvr.library.anims.animators;
+
+/**
+ * Copyright (C) 2017 Wasabeef
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import android.support.v4.view.ViewCompat;
+import android.support.v7.widget.RecyclerView;
+import android.view.animation.Interpolator;
+
+public class LandingAnimator extends BaseItemAnimator {
+
+ public LandingAnimator() {
+ }
+
+ public LandingAnimator(Interpolator interpolator) {
+ mInterpolator = interpolator;
+ }
+
+ @Override protected void animateRemoveImpl(final RecyclerView.ViewHolder holder) {
+ ViewCompat.animate(holder.itemView)
+ .alpha(0)
+ .scaleX(1.5f)
+ .scaleY(1.5f)
+ .setDuration(getRemoveDuration())
+ .setInterpolator(mInterpolator)
+ .setListener(new DefaultRemoveVpaListener(holder))
+ .setStartDelay(getRemoveDelay(holder))
+ .start();
+ }
+
+ @Override protected void preAnimateAddImpl(RecyclerView.ViewHolder holder) {
+ ViewCompat.setAlpha(holder.itemView, 0);
+ ViewCompat.setScaleX(holder.itemView, 1.5f);
+ ViewCompat.setScaleY(holder.itemView, 1.5f);
+ }
+
+ @Override protected void animateAddImpl(final RecyclerView.ViewHolder holder) {
+ ViewCompat.animate(holder.itemView)
+ .alpha(1)
+ .scaleX(1)
+ .scaleY(1)
+ .setDuration(getAddDuration())
+ .setInterpolator(mInterpolator)
+ .setListener(new DefaultAddVpaListener(holder))
+ .setStartDelay(getAddDelay(holder))
+ .start();
+ }
+}
diff --git a/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/OvershootInLeftAnimator.java b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/OvershootInLeftAnimator.java
new file mode 100644
index 0000000..602ba05
--- /dev/null
+++ b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/OvershootInLeftAnimator.java
@@ -0,0 +1,58 @@
+package com.lvr.library.anims.animators;
+
+/**
+ * Copyright (C) 2017 Wasabeef
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import android.support.v4.view.ViewCompat;
+import android.support.v7.widget.RecyclerView;
+import android.view.animation.OvershootInterpolator;
+
+public class OvershootInLeftAnimator extends BaseItemAnimator {
+
+ private final float mTension;
+
+ public OvershootInLeftAnimator() {
+ mTension = 2.0f;
+ }
+
+ public OvershootInLeftAnimator(float mTension) {
+ this.mTension = mTension;
+ }
+
+ @Override protected void animateRemoveImpl(final RecyclerView.ViewHolder holder) {
+ ViewCompat.animate(holder.itemView)
+ .translationX(-holder.itemView.getRootView().getWidth())
+ .setDuration(getRemoveDuration())
+ .setListener(new DefaultRemoveVpaListener(holder))
+ .setStartDelay(getRemoveDelay(holder))
+ .start();
+ }
+
+ @Override protected void preAnimateAddImpl(RecyclerView.ViewHolder holder) {
+ ViewCompat.setTranslationX(holder.itemView, -holder.itemView.getRootView().getWidth());
+ }
+
+ @Override protected void animateAddImpl(final RecyclerView.ViewHolder holder) {
+ ViewCompat.animate(holder.itemView)
+ .translationX(0)
+ .setDuration(getAddDuration())
+ .setListener(new DefaultAddVpaListener(holder))
+ .setInterpolator(new OvershootInterpolator(mTension))
+ .setStartDelay(getAddDelay(holder))
+ .start();
+ }
+}
+
diff --git a/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/OvershootInRightAnimator.java b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/OvershootInRightAnimator.java
new file mode 100644
index 0000000..8ca573b
--- /dev/null
+++ b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/OvershootInRightAnimator.java
@@ -0,0 +1,57 @@
+package com.lvr.library.anims.animators;
+
+/**
+ * Copyright (C) 2017 Wasabeef
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import android.support.v4.view.ViewCompat;
+import android.support.v7.widget.RecyclerView;
+import android.view.animation.OvershootInterpolator;
+
+public class OvershootInRightAnimator extends BaseItemAnimator {
+
+ private final float mTension;
+
+ public OvershootInRightAnimator() {
+ mTension = 2.0f;
+ }
+
+ public OvershootInRightAnimator(float mTension) {
+ this.mTension = mTension;
+ }
+
+ @Override protected void animateRemoveImpl(final RecyclerView.ViewHolder holder) {
+ ViewCompat.animate(holder.itemView)
+ .translationX(holder.itemView.getRootView().getWidth())
+ .setDuration(getRemoveDuration())
+ .setListener(new DefaultRemoveVpaListener(holder))
+ .setStartDelay(getRemoveDelay(holder))
+ .start();
+ }
+
+ @Override protected void preAnimateAddImpl(RecyclerView.ViewHolder holder) {
+ ViewCompat.setTranslationX(holder.itemView, holder.itemView.getRootView().getWidth());
+ }
+
+ @Override protected void animateAddImpl(final RecyclerView.ViewHolder holder) {
+ ViewCompat.animate(holder.itemView)
+ .translationX(0)
+ .setDuration(getAddDuration())
+ .setInterpolator(new OvershootInterpolator(mTension))
+ .setListener(new DefaultAddVpaListener(holder))
+ .setStartDelay(getAddDelay(holder))
+ .start();
+ }
+}
diff --git a/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/ScaleInAnimator.java b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/ScaleInAnimator.java
new file mode 100644
index 0000000..7fa5048
--- /dev/null
+++ b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/ScaleInAnimator.java
@@ -0,0 +1,58 @@
+package com.lvr.library.anims.animators;
+
+/**
+ * Copyright (C) 2017 Wasabeef
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import android.support.v4.view.ViewCompat;
+import android.support.v7.widget.RecyclerView;
+import android.view.animation.Interpolator;
+
+public class ScaleInAnimator extends BaseItemAnimator {
+
+ public ScaleInAnimator() {
+ }
+
+ public ScaleInAnimator(Interpolator interpolator) {
+ mInterpolator = interpolator;
+ }
+
+ @Override protected void animateRemoveImpl(final RecyclerView.ViewHolder holder) {
+ ViewCompat.animate(holder.itemView)
+ .scaleX(0)
+ .scaleY(0)
+ .setDuration(getRemoveDuration())
+ .setInterpolator(mInterpolator)
+ .setListener(new DefaultRemoveVpaListener(holder))
+ .setStartDelay(getRemoveDelay(holder))
+ .start();
+ }
+
+ @Override protected void preAnimateAddImpl(RecyclerView.ViewHolder holder) {
+ ViewCompat.setScaleX(holder.itemView, 0);
+ ViewCompat.setScaleY(holder.itemView, 0);
+ }
+
+ @Override protected void animateAddImpl(final RecyclerView.ViewHolder holder) {
+ ViewCompat.animate(holder.itemView)
+ .scaleX(1)
+ .scaleY(1)
+ .setDuration(getAddDuration())
+ .setInterpolator(mInterpolator)
+ .setListener(new DefaultAddVpaListener(holder))
+ .setStartDelay(getAddDelay(holder))
+ .start();
+ }
+}
diff --git a/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/ScaleInBottomAnimator.java b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/ScaleInBottomAnimator.java
new file mode 100644
index 0000000..eff42fb
--- /dev/null
+++ b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/ScaleInBottomAnimator.java
@@ -0,0 +1,67 @@
+package com.lvr.library.anims.animators;
+
+/**
+ * Copyright (C) 2017 Wasabeef
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import android.support.v4.view.ViewCompat;
+import android.support.v7.widget.RecyclerView;
+import android.view.animation.Interpolator;
+
+public class ScaleInBottomAnimator extends BaseItemAnimator {
+
+ public ScaleInBottomAnimator() {
+ }
+
+ public ScaleInBottomAnimator(Interpolator interpolator) {
+ mInterpolator = interpolator;
+ }
+
+ @Override protected void preAnimateRemoveImpl(RecyclerView.ViewHolder holder) {
+ // @TODO https://code.google.com/p/android/issues/detail?id=80863
+ // ViewCompat.setPivotY(holder.itemView, holder.itemView.getHeight());
+ holder.itemView.setPivotY(holder.itemView.getHeight());
+ }
+
+ @Override protected void animateRemoveImpl(final RecyclerView.ViewHolder holder) {
+ ViewCompat.animate(holder.itemView)
+ .scaleX(0)
+ .scaleY(0)
+ .setDuration(getRemoveDuration())
+ .setInterpolator(mInterpolator)
+ .setListener(new DefaultRemoveVpaListener(holder))
+ .setStartDelay(getRemoveDelay(holder))
+ .start();
+ }
+
+ @Override protected void preAnimateAddImpl(RecyclerView.ViewHolder holder) {
+ // @TODO https://code.google.com/p/android/issues/detail?id=80863
+ // ViewCompat.setPivotY(holder.itemView, holder.itemView.getHeight());
+ holder.itemView.setPivotY(holder.itemView.getHeight());
+ ViewCompat.setScaleX(holder.itemView, 0);
+ ViewCompat.setScaleY(holder.itemView, 0);
+ }
+
+ @Override protected void animateAddImpl(final RecyclerView.ViewHolder holder) {
+ ViewCompat.animate(holder.itemView)
+ .scaleX(1)
+ .scaleY(1)
+ .setDuration(getAddDuration())
+ .setInterpolator(mInterpolator)
+ .setListener(new DefaultAddVpaListener(holder))
+ .setStartDelay(getAddDelay(holder))
+ .start();
+ }
+}
diff --git a/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/ScaleInLeftAnimator.java b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/ScaleInLeftAnimator.java
new file mode 100644
index 0000000..aeba1cd
--- /dev/null
+++ b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/ScaleInLeftAnimator.java
@@ -0,0 +1,63 @@
+package com.lvr.library.anims.animators;
+
+/**
+ * Copyright (C) 2017 Wasabeef
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import android.support.v4.view.ViewCompat;
+import android.support.v7.widget.RecyclerView;
+import android.view.animation.Interpolator;
+
+public class ScaleInLeftAnimator extends BaseItemAnimator {
+
+ public ScaleInLeftAnimator() {
+ }
+
+ public ScaleInLeftAnimator(Interpolator interpolator) {
+ mInterpolator = interpolator;
+ }
+
+ @Override protected void preAnimateRemoveImpl(RecyclerView.ViewHolder holder) {
+ ViewCompat.setPivotX(holder.itemView, 0);
+ }
+
+ @Override protected void animateRemoveImpl(final RecyclerView.ViewHolder holder) {
+ ViewCompat.animate(holder.itemView)
+ .scaleX(0)
+ .scaleY(0)
+ .setDuration(getRemoveDuration())
+ .setInterpolator(mInterpolator)
+ .setListener(new DefaultRemoveVpaListener(holder))
+ .setStartDelay(getRemoveDelay(holder))
+ .start();
+ }
+
+ @Override protected void preAnimateAddImpl(RecyclerView.ViewHolder holder) {
+ ViewCompat.setPivotX(holder.itemView, 0);
+ ViewCompat.setScaleX(holder.itemView, 0);
+ ViewCompat.setScaleY(holder.itemView, 0);
+ }
+
+ @Override protected void animateAddImpl(final RecyclerView.ViewHolder holder) {
+ ViewCompat.animate(holder.itemView)
+ .scaleX(1)
+ .scaleY(1)
+ .setDuration(getAddDuration())
+ .setInterpolator(mInterpolator)
+ .setListener(new DefaultAddVpaListener(holder))
+ .setStartDelay(getAddDelay(holder))
+ .start();
+ }
+}
diff --git a/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/ScaleInRightAnimator.java b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/ScaleInRightAnimator.java
new file mode 100644
index 0000000..9376a84
--- /dev/null
+++ b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/ScaleInRightAnimator.java
@@ -0,0 +1,63 @@
+package com.lvr.library.anims.animators;
+
+/**
+ * Copyright (C) 2017 Wasabeef
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import android.support.v4.view.ViewCompat;
+import android.support.v7.widget.RecyclerView;
+import android.view.animation.Interpolator;
+
+public class ScaleInRightAnimator extends BaseItemAnimator {
+
+ public ScaleInRightAnimator() {
+ }
+
+ public ScaleInRightAnimator(Interpolator interpolator) {
+ mInterpolator = interpolator;
+ }
+
+ @Override protected void preAnimateRemoveImpl(RecyclerView.ViewHolder holder) {
+ ViewCompat.setPivotX(holder.itemView, holder.itemView.getWidth());
+ }
+
+ @Override protected void animateRemoveImpl(final RecyclerView.ViewHolder holder) {
+ ViewCompat.animate(holder.itemView)
+ .scaleX(0)
+ .scaleY(0)
+ .setDuration(getRemoveDuration())
+ .setInterpolator(mInterpolator)
+ .setListener(new DefaultRemoveVpaListener(holder))
+ .setStartDelay(getRemoveDelay(holder))
+ .start();
+ }
+
+ @Override protected void preAnimateAddImpl(RecyclerView.ViewHolder holder) {
+ ViewCompat.setPivotX(holder.itemView, holder.itemView.getWidth());
+ ViewCompat.setScaleX(holder.itemView, 0);
+ ViewCompat.setScaleY(holder.itemView, 0);
+ }
+
+ @Override protected void animateAddImpl(final RecyclerView.ViewHolder holder) {
+ ViewCompat.animate(holder.itemView)
+ .scaleX(1)
+ .scaleY(1)
+ .setDuration(getAddDuration())
+ .setInterpolator(mInterpolator)
+ .setListener(new DefaultAddVpaListener(holder))
+ .setStartDelay(getAddDelay(holder))
+ .start();
+ }
+}
diff --git a/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/ScaleInTopAnimator.java b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/ScaleInTopAnimator.java
new file mode 100644
index 0000000..57d1c41
--- /dev/null
+++ b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/ScaleInTopAnimator.java
@@ -0,0 +1,67 @@
+package com.lvr.library.anims.animators;
+
+/**
+ * Copyright (C) 2017 Wasabeef
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import android.support.v4.view.ViewCompat;
+import android.support.v7.widget.RecyclerView;
+import android.view.animation.Interpolator;
+
+public class ScaleInTopAnimator extends BaseItemAnimator {
+
+ public ScaleInTopAnimator() {
+ }
+
+ public ScaleInTopAnimator(Interpolator interpolator) {
+ mInterpolator = interpolator;
+ }
+
+ @Override protected void preAnimateRemoveImpl(RecyclerView.ViewHolder holder) {
+ // @TODO https://code.google.com/p/android/issues/detail?id=80863
+ // ViewCompat.setPivotY(holder.itemView, 0);
+ holder.itemView.setPivotY(0);
+ }
+
+ @Override protected void animateRemoveImpl(final RecyclerView.ViewHolder holder) {
+ ViewCompat.animate(holder.itemView)
+ .scaleX(0)
+ .scaleY(0)
+ .setDuration(getRemoveDuration())
+ .setInterpolator(mInterpolator)
+ .setListener(new DefaultRemoveVpaListener(holder))
+ .setStartDelay(getRemoveDelay(holder))
+ .start();
+ }
+
+ @Override protected void preAnimateAddImpl(RecyclerView.ViewHolder holder) {
+ // @TODO https://code.google.com/p/android/issues/detail?id=80863
+ // ViewCompat.setPivotY(holder.itemView, 0);
+ holder.itemView.setPivotY(0);
+ ViewCompat.setScaleX(holder.itemView, 0);
+ ViewCompat.setScaleY(holder.itemView, 0);
+ }
+
+ @Override protected void animateAddImpl(final RecyclerView.ViewHolder holder) {
+ ViewCompat.animate(holder.itemView)
+ .scaleX(1)
+ .scaleY(1)
+ .setDuration(getAddDuration())
+ .setInterpolator(mInterpolator)
+ .setListener(new DefaultAddVpaListener(holder))
+ .setStartDelay(getAddDelay(holder))
+ .start();
+ }
+}
diff --git a/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/SlideInDownAnimator.java b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/SlideInDownAnimator.java
new file mode 100644
index 0000000..c74945e
--- /dev/null
+++ b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/SlideInDownAnimator.java
@@ -0,0 +1,59 @@
+package com.lvr.library.anims.animators;
+
+/**
+ * Copyright (C) 2017 Wasabeef
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import android.support.v4.view.ViewCompat;
+import android.support.v7.widget.RecyclerView;
+import android.view.animation.Interpolator;
+
+public class SlideInDownAnimator extends BaseItemAnimator {
+
+ public SlideInDownAnimator() {
+
+ }
+
+ public SlideInDownAnimator(Interpolator interpolator) {
+ mInterpolator = interpolator;
+ }
+
+ @Override protected void animateRemoveImpl(final RecyclerView.ViewHolder holder) {
+ ViewCompat.animate(holder.itemView)
+ .translationY(-holder.itemView.getHeight())
+ .alpha(0)
+ .setDuration(getRemoveDuration())
+ .setInterpolator(mInterpolator)
+ .setListener(new DefaultRemoveVpaListener(holder))
+ .setStartDelay(getRemoveDelay(holder))
+ .start();
+ }
+
+ @Override protected void preAnimateAddImpl(RecyclerView.ViewHolder holder) {
+ ViewCompat.setTranslationY(holder.itemView, -holder.itemView.getHeight());
+ ViewCompat.setAlpha(holder.itemView, 0);
+ }
+
+ @Override protected void animateAddImpl(final RecyclerView.ViewHolder holder) {
+ ViewCompat.animate(holder.itemView)
+ .translationY(0)
+ .alpha(1)
+ .setDuration(getAddDuration())
+ .setInterpolator(mInterpolator)
+ .setListener(new DefaultAddVpaListener(holder))
+ .setStartDelay(getAddDelay(holder))
+ .start();
+ }
+}
diff --git a/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/SlideInLeftAnimator.java b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/SlideInLeftAnimator.java
new file mode 100644
index 0000000..e65ddbb
--- /dev/null
+++ b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/SlideInLeftAnimator.java
@@ -0,0 +1,56 @@
+package com.lvr.library.anims.animators;
+
+/**
+ * Copyright (C) 2017 Wasabeef
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import android.support.v4.view.ViewCompat;
+import android.support.v7.widget.RecyclerView;
+import android.view.animation.Interpolator;
+
+public class SlideInLeftAnimator extends BaseItemAnimator {
+
+ public SlideInLeftAnimator() {
+
+ }
+
+ public SlideInLeftAnimator(Interpolator interpolator) {
+ mInterpolator = interpolator;
+ }
+
+ @Override protected void animateRemoveImpl(final RecyclerView.ViewHolder holder) {
+ ViewCompat.animate(holder.itemView)
+ .translationX(-holder.itemView.getRootView().getWidth())
+ .setDuration(getRemoveDuration())
+ .setInterpolator(mInterpolator)
+ .setListener(new DefaultRemoveVpaListener(holder))
+ .setStartDelay(getRemoveDelay(holder))
+ .start();
+ }
+
+ @Override protected void preAnimateAddImpl(RecyclerView.ViewHolder holder) {
+ ViewCompat.setTranslationX(holder.itemView, -holder.itemView.getRootView().getWidth());
+ }
+
+ @Override protected void animateAddImpl(final RecyclerView.ViewHolder holder) {
+ ViewCompat.animate(holder.itemView)
+ .translationX(0)
+ .setDuration(getAddDuration())
+ .setInterpolator(mInterpolator)
+ .setListener(new DefaultAddVpaListener(holder))
+ .setStartDelay(getAddDelay(holder))
+ .start();
+ }
+}
diff --git a/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/SlideInRightAnimator.java b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/SlideInRightAnimator.java
new file mode 100644
index 0000000..eb09ff1
--- /dev/null
+++ b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/SlideInRightAnimator.java
@@ -0,0 +1,56 @@
+package com.lvr.library.anims.animators;
+
+/**
+ * Copyright (C) 2017 Wasabeef
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import android.support.v4.view.ViewCompat;
+import android.support.v7.widget.RecyclerView;
+import android.view.animation.Interpolator;
+
+public class SlideInRightAnimator extends BaseItemAnimator {
+
+ public SlideInRightAnimator() {
+
+ }
+
+ public SlideInRightAnimator(Interpolator interpolator) {
+ mInterpolator = interpolator;
+ }
+
+ @Override protected void animateRemoveImpl(final RecyclerView.ViewHolder holder) {
+ ViewCompat.animate(holder.itemView)
+ .translationX(holder.itemView.getRootView().getWidth())
+ .setDuration(getRemoveDuration())
+ .setInterpolator(mInterpolator)
+ .setListener(new DefaultRemoveVpaListener(holder))
+ .setStartDelay(getRemoveDelay(holder))
+ .start();
+ }
+
+ @Override protected void preAnimateAddImpl(RecyclerView.ViewHolder holder) {
+ ViewCompat.setTranslationX(holder.itemView, holder.itemView.getRootView().getWidth());
+ }
+
+ @Override protected void animateAddImpl(final RecyclerView.ViewHolder holder) {
+ ViewCompat.animate(holder.itemView)
+ .translationX(0)
+ .setDuration(getAddDuration())
+ .setInterpolator(mInterpolator)
+ .setListener(new DefaultAddVpaListener(holder))
+ .setStartDelay(getAddDelay(holder))
+ .start();
+ }
+}
diff --git a/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/SlideInUpAnimator.java b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/SlideInUpAnimator.java
new file mode 100644
index 0000000..e2dab17
--- /dev/null
+++ b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/SlideInUpAnimator.java
@@ -0,0 +1,59 @@
+package com.lvr.library.anims.animators;
+
+/**
+ * Copyright (C) 2017 Wasabeef
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import android.support.v4.view.ViewCompat;
+import android.support.v7.widget.RecyclerView;
+import android.view.animation.Interpolator;
+
+public class SlideInUpAnimator extends BaseItemAnimator {
+
+ public SlideInUpAnimator() {
+
+ }
+
+ public SlideInUpAnimator(Interpolator interpolator) {
+ mInterpolator = interpolator;
+ }
+
+ @Override protected void animateRemoveImpl(final RecyclerView.ViewHolder holder) {
+ ViewCompat.animate(holder.itemView)
+ .translationY(holder.itemView.getHeight())
+ .alpha(0)
+ .setDuration(getRemoveDuration())
+ .setInterpolator(mInterpolator)
+ .setListener(new DefaultRemoveVpaListener(holder))
+ .setStartDelay(getRemoveDelay(holder))
+ .start();
+ }
+
+ @Override protected void preAnimateAddImpl(RecyclerView.ViewHolder holder) {
+ ViewCompat.setTranslationY(holder.itemView, holder.itemView.getHeight());
+ ViewCompat.setAlpha(holder.itemView, 0);
+ }
+
+ @Override protected void animateAddImpl(final RecyclerView.ViewHolder holder) {
+ ViewCompat.animate(holder.itemView)
+ .translationY(0)
+ .alpha(1)
+ .setDuration(getAddDuration())
+ .setInterpolator(mInterpolator)
+ .setListener(new DefaultAddVpaListener(holder))
+ .setStartDelay(getAddDelay(holder))
+ .start();
+ }
+}
diff --git a/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/ViewHelper.java b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/ViewHelper.java
new file mode 100644
index 0000000..ebe1f70
--- /dev/null
+++ b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/ViewHelper.java
@@ -0,0 +1,37 @@
+package com.lvr.library.anims.animators;
+
+import android.support.v4.view.ViewCompat;
+import android.view.View;
+
+/**
+ * Copyright (C) 2017 Wasabeef
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public final class ViewHelper {
+
+ public static void clear(View v) {
+ ViewCompat.setAlpha(v, 1);
+ ViewCompat.setScaleY(v, 1);
+ ViewCompat.setScaleX(v, 1);
+ ViewCompat.setTranslationY(v, 0);
+ ViewCompat.setTranslationX(v, 0);
+ ViewCompat.setRotation(v, 0);
+ ViewCompat.setRotationY(v, 0);
+ ViewCompat.setRotationX(v, 0);
+ ViewCompat.setPivotY(v, v.getMeasuredHeight() / 2);
+ ViewCompat.setPivotX(v, v.getMeasuredWidth() / 2);
+ ViewCompat.animate(v).setInterpolator(null).setStartDelay(0);
+ }
+}
diff --git a/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/holder/AnimateViewHolder.java b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/holder/AnimateViewHolder.java
new file mode 100644
index 0000000..ecdc535
--- /dev/null
+++ b/recyclerview_helper/library/src/main/java/com/lvr/library/anims/animators/holder/AnimateViewHolder.java
@@ -0,0 +1,16 @@
+package com.lvr.library.anims.animators.holder;
+
+import android.support.v4.view.ViewPropertyAnimatorListener;
+import android.support.v7.widget.RecyclerView;
+
+public interface AnimateViewHolder {
+
+ void preAnimateAddImpl(final RecyclerView.ViewHolder holder);
+
+ void preAnimateRemoveImpl(final RecyclerView.ViewHolder holder);
+
+ void animateAddImpl(final RecyclerView.ViewHolder holder, ViewPropertyAnimatorListener listener);
+
+ void animateRemoveImpl(final RecyclerView.ViewHolder holder,
+ ViewPropertyAnimatorListener listener);
+}
diff --git a/recyclerview_helper/library/src/main/java/com/lvr/library/holder/BaseViewHolder.java b/recyclerview_helper/library/src/main/java/com/lvr/library/holder/BaseViewHolder.java
new file mode 100644
index 0000000..836b71c
--- /dev/null
+++ b/recyclerview_helper/library/src/main/java/com/lvr/library/holder/BaseViewHolder.java
@@ -0,0 +1,102 @@
+package com.lvr.library.holder;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.IdRes;
+import android.support.annotation.LayoutRes;
+import android.support.v7.widget.RecyclerView;
+import android.util.SparseArray;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+/**
+ * 基础的ViewHolder
+ * ViewHolder只作View的缓存,避免每次findViewById,从而提升运行的效率
+ */
+public class BaseViewHolder extends RecyclerView.ViewHolder {
+ private SparseArray viewArray;
+ private View mItemView;
+
+ /**
+ * 构造ViewHolder
+ *
+ * @param parent 父类容器
+ * @param resId 布局资源文件id
+ */
+ public BaseViewHolder(Context context, ViewGroup parent, @LayoutRes int resId) {
+ super(LayoutInflater.from(context).inflate(resId, parent, false));
+ viewArray = new SparseArray<>();
+ }
+
+ /**
+ * 获取ItemView
+ * @return ItemView
+ */
+ public View getItemView(){
+ return this.itemView;
+ }
+
+ /**
+ * 获取布局中的View
+ *
+ * @param viewId view的Id
+ * @param View的类型
+ * @return view
+ */
+ public T getView(@IdRes int viewId) {
+ View view = viewArray.get(viewId);
+ if (view == null) {
+ view = itemView.findViewById(viewId);
+ viewArray.put(viewId, view);
+ }
+ return (T) view;
+ }
+
+ /**
+ * 给TextView设置内容
+ *
+ * @param viewId TextView的id
+ * @param text 字符串内容
+ */
+ public void setText(int viewId, String text) {
+ TextView tv = getView(viewId);
+ tv.setText(text);
+ }
+
+ /**
+ * 给ImageView设置图片
+ *
+ * @param viewId ImageView的id
+ * @param drawableId 图片资源
+ */
+ public void setImageResource(int viewId, int drawableId) {
+ ImageView iv = getView(viewId);
+ iv.setImageResource(drawableId);
+ }
+
+ /**
+ * 给ImageView设置图片
+ *
+ * @param viewId ImageView的id
+ * @param bitmap 图片资源
+ */
+ public void setImageBitmap(int viewId, Bitmap bitmap) {
+ ImageView iv = getView(viewId);
+ iv.setImageBitmap(bitmap);
+ }
+ /**
+ * 给ImageView设置图片
+ *
+ * @param viewId ImageView的id
+ * @param drawable 图片资源
+ */
+ public void setImageBitmap(int viewId, Drawable drawable) {
+ ImageView iv = getView(viewId);
+ iv.setImageDrawable(drawable);
+ }
+
+}
diff --git a/recyclerview_helper/library/src/main/java/com/lvr/library/recyclerview/HRecyclerView.java b/recyclerview_helper/library/src/main/java/com/lvr/library/recyclerview/HRecyclerView.java
new file mode 100644
index 0000000..bcdb05a
--- /dev/null
+++ b/recyclerview_helper/library/src/main/java/com/lvr/library/recyclerview/HRecyclerView.java
@@ -0,0 +1,727 @@
+package com.lvr.library.recyclerview;
+
+import android.animation.Animator;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.support.annotation.LayoutRes;
+import android.support.annotation.Nullable;
+import android.support.v4.view.MotionEventCompat;
+import android.support.v7.widget.RecyclerView;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.Interpolator;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+
+import com.lvr.library.R;
+
+
+/**
+ * Created by lvr on 2017/5/25.
+ */
+
+public class HRecyclerView extends RecyclerView {
+ private static final String TAG = HRecyclerView.class.getSimpleName();
+
+ private static final int STATUS_DEFAULT = 0;
+
+ private static final int STATUS_SWIPING_TO_REFRESH = 1;
+
+ private static final int STATUS_RELEASE_TO_REFRESH = 2;
+
+ private static final int STATUS_REFRESHING = 3;
+
+ private static final boolean DEBUG = false;
+
+ private int mStatus;
+
+ private boolean mIsAutoRefreshing;
+
+ private boolean mRefreshEnabled;
+
+ private boolean mLoadMoreEnabled;
+
+ private int mRefreshFinalMoveOffset;
+
+ private OnRefreshListener mOnRefreshListener;
+
+ private OnLoadMoreListener mOnLoadMoreListener;
+
+ private RefreshHeaderLayout mRefreshHeaderContainer;
+
+ private FrameLayout mLoadMoreFooterContainer;
+
+ private LinearLayout mHeaderViewContainer;
+
+ private LinearLayout mFooterViewContainer;
+
+ private View mRefreshHeaderView;
+
+ private View mLoadMoreFooterView;
+
+ private Adapter mOriginAdapter;
+
+ public HRecyclerView(Context context) {
+ this(context, null);
+ }
+
+ public HRecyclerView(Context context, @Nullable AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public HRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.HRecyclerView, defStyle, 0);
+ @LayoutRes int refreshHeaderLayoutRes = -1;
+ @LayoutRes int loadMoreFooterLayoutRes = -1;
+ int refreshFinalMoveOffset = -1;
+ boolean refreshEnabled;
+ boolean loadMoreEnabled;
+
+ try {
+ refreshEnabled = a.getBoolean(R.styleable.HRecyclerView_refreshEnabled, false);
+ loadMoreEnabled = a.getBoolean(R.styleable.HRecyclerView_loadMoreEnabled, false);
+ refreshHeaderLayoutRes = a.getResourceId(R.styleable.HRecyclerView_refreshHeaderLayout, -1);
+ loadMoreFooterLayoutRes = a.getResourceId(R.styleable.HRecyclerView_loadMoreFooterLayout, -1);
+ refreshFinalMoveOffset = a.getDimensionPixelOffset(R.styleable.HRecyclerView_refreshFinalMoveOffset, -1);
+ } finally {
+ a.recycle();
+ }
+
+ setRefreshEnabled(refreshEnabled);
+
+ setLoadMoreEnabled(loadMoreEnabled);
+
+ if (refreshHeaderLayoutRes != -1) {
+ setRefreshHeaderView(refreshHeaderLayoutRes);
+ }
+ if (loadMoreFooterLayoutRes != -1) {
+ setLoadMoreFooterView(loadMoreFooterLayoutRes);
+ }
+ if (refreshFinalMoveOffset != -1) {
+ setRefreshFinalMoveOffset(refreshFinalMoveOffset);
+ }
+ setStatus(STATUS_DEFAULT);
+ }
+
+ @Override
+ protected void onMeasure(int widthSpec, int heightSpec) {
+ super.onMeasure(widthSpec, heightSpec);
+ if (mRefreshHeaderView != null) {
+ if (mRefreshHeaderView.getMeasuredHeight() > mRefreshFinalMoveOffset) {
+ mRefreshFinalMoveOffset = 0;
+ }
+ }
+ }
+
+ public void setRefreshEnabled(boolean enabled) {
+ this.mRefreshEnabled = enabled;
+ }
+
+ public void setLoadMoreEnabled(boolean enabled) {
+ this.mLoadMoreEnabled = enabled;
+ if (mLoadMoreEnabled) {
+ removeOnScrollListener(mOnLoadMoreScrollListener);
+ addOnScrollListener(mOnLoadMoreScrollListener);
+ } else {
+ removeOnScrollListener(mOnLoadMoreScrollListener);
+ }
+ }
+
+ public void setOnRefreshListener(OnRefreshListener listener) {
+ this.mOnRefreshListener = listener;
+ }
+
+ public void setOnLoadMoreListener(OnLoadMoreListener listener) {
+ this.mOnLoadMoreListener = listener;
+ }
+
+ public void setRefreshing(boolean refreshing) {
+ if (mStatus == STATUS_DEFAULT && refreshing) {
+ this.mIsAutoRefreshing = true;
+ setStatus(STATUS_SWIPING_TO_REFRESH);
+ startScrollDefaultStatusToRefreshingStatus();
+ } else if (mStatus == STATUS_REFRESHING && !refreshing) {
+ this.mIsAutoRefreshing = false;
+ startScrollRefreshingStatusToDefaultStatus();
+
+ } else {
+ this.mIsAutoRefreshing = false;
+ Log.w(TAG, "isRefresh = " + refreshing + " current status = " + mStatus);
+ }
+ }
+
+ public void setRefreshFinalMoveOffset(int refreshFinalMoveOffset) {
+ this.mRefreshFinalMoveOffset = refreshFinalMoveOffset;
+ }
+
+ public void setRefreshHeaderView(View refreshHeaderView) {
+ if (!(refreshHeaderView instanceof RefreshTrigger)) {
+ throw new ClassCastException("Refresh header view must be an implement of RefreshTrigger");
+ }
+
+ if (mRefreshHeaderView != null) {
+ removeRefreshHeaderView();
+ }
+ if (mRefreshHeaderView != refreshHeaderView) {
+ this.mRefreshHeaderView = refreshHeaderView;
+ ensureRefreshHeaderContainer();
+ mRefreshHeaderContainer.addView(refreshHeaderView);
+ }
+ }
+
+ public void setRefreshHeaderView(@LayoutRes int refreshHeaderLayoutRes) {
+ ensureRefreshHeaderContainer();
+ final View refreshHeader = LayoutInflater.from(getContext()).inflate(refreshHeaderLayoutRes, mRefreshHeaderContainer, false);
+ if (refreshHeader != null) {
+ setRefreshHeaderView(refreshHeader);
+ }
+ }
+
+ public void setLoadMoreFooterView(View loadMoreFooterView) {
+ if (mLoadMoreFooterView != null) {
+ removeLoadMoreFooterView();
+ }
+ if (mLoadMoreFooterView != loadMoreFooterView) {
+ this.mLoadMoreFooterView = loadMoreFooterView;
+ ensureLoadMoreFooterContainer();
+ mLoadMoreFooterContainer.addView(loadMoreFooterView);
+ }
+ }
+
+ public void setLoadMoreFooterView(@LayoutRes int loadMoreFooterLayoutRes) {
+ ensureLoadMoreFooterContainer();
+ final View loadMoreFooter = LayoutInflater.from(getContext()).inflate(loadMoreFooterLayoutRes, mLoadMoreFooterContainer, false);
+ if (loadMoreFooter != null) {
+ setLoadMoreFooterView(loadMoreFooter);
+ }
+ }
+
+ public View getRefreshHeaderView() {
+ return mRefreshHeaderView;
+ }
+
+ public View getLoadMoreFooterView() {
+ return mLoadMoreFooterView;
+ }
+
+ public LinearLayout getHeaderContainer() {
+ ensureHeaderViewContainer();
+ return mHeaderViewContainer;
+ }
+
+ public LinearLayout getFooterContainer() {
+ ensureFooterViewContainer();
+ return mFooterViewContainer;
+ }
+
+ public void addHeaderView(View headerView) {
+ ensureHeaderViewContainer();
+ mHeaderViewContainer.addView(headerView);
+ Adapter adapter = getAdapter();
+ if (adapter != null) {
+ adapter.notifyItemChanged(1);
+ }
+ }
+
+ public void addFooterView(View footerView) {
+ ensureFooterViewContainer();
+ mFooterViewContainer.addView(footerView);
+ Adapter adapter = getAdapter();
+ if (adapter != null) {
+ adapter.notifyItemChanged(adapter.getItemCount() - 2);
+ }
+ }
+
+
+ @Override
+ public void setAdapter(Adapter adapter) {
+ mOriginAdapter =adapter;
+ ensureRefreshHeaderContainer();
+ ensureHeaderViewContainer();
+ ensureFooterViewContainer();
+ ensureLoadMoreFooterContainer();
+ super.setAdapter(new WrapperAdapter(adapter, mRefreshHeaderContainer, mHeaderViewContainer, mFooterViewContainer, mLoadMoreFooterContainer));
+ }
+
+ private void ensureRefreshHeaderContainer() {
+ if (mRefreshHeaderContainer == null) {
+ mRefreshHeaderContainer = new RefreshHeaderLayout(getContext());
+ mRefreshHeaderContainer.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 0));
+ }
+ }
+
+ private void ensureLoadMoreFooterContainer() {
+ if (mLoadMoreFooterContainer == null) {
+ mLoadMoreFooterContainer = new FrameLayout(getContext());
+ mLoadMoreFooterContainer.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
+ }
+ }
+
+ private void ensureHeaderViewContainer() {
+ if (mHeaderViewContainer == null) {
+ mHeaderViewContainer = new LinearLayout(getContext());
+ mHeaderViewContainer.setOrientation(LinearLayout.VERTICAL);
+ mHeaderViewContainer.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
+ }
+ }
+
+ private void ensureFooterViewContainer() {
+ if (mFooterViewContainer == null) {
+ mFooterViewContainer = new LinearLayout(getContext());
+ mFooterViewContainer.setOrientation(LinearLayout.VERTICAL);
+ mFooterViewContainer.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
+ }
+ }
+
+ private void removeRefreshHeaderView() {
+ if (mRefreshHeaderContainer != null) {
+ mRefreshHeaderContainer.removeView(mRefreshHeaderView);
+ }
+ }
+
+ private void removeLoadMoreFooterView() {
+ if (mLoadMoreFooterContainer != null) {
+ mLoadMoreFooterContainer.removeView(mLoadMoreFooterView);
+ }
+ }
+
+ private int mActivePointerId = -1;
+ private int mLastTouchX = 0;
+ private int mLastTouchY = 0;
+
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent e) {
+ final int action = MotionEventCompat.getActionMasked(e);
+ final int actionIndex = MotionEventCompat.getActionIndex(e);
+ switch (action) {
+ case MotionEvent.ACTION_DOWN: {
+ mActivePointerId = MotionEventCompat.getPointerId(e, 0);
+ mLastTouchX = (int) (MotionEventCompat.getX(e, actionIndex) + 0.5f);
+ mLastTouchY = (int) (MotionEventCompat.getY(e, actionIndex) + 0.5f);
+ }
+ break;
+
+ case MotionEvent.ACTION_POINTER_DOWN: {
+ mActivePointerId = MotionEventCompat.getPointerId(e, actionIndex);
+ mLastTouchX = (int) (MotionEventCompat.getX(e, actionIndex) + 0.5f);
+ mLastTouchY = (int) (MotionEventCompat.getY(e, actionIndex) + 0.5f);
+ }
+ break;
+
+ case MotionEventCompat.ACTION_POINTER_UP: {
+ onPointerUp(e);
+ }
+ break;
+ }
+
+ return super.onInterceptTouchEvent(e);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent e) {
+ final int action = MotionEventCompat.getActionMasked(e);
+ switch (action) {
+ case MotionEvent.ACTION_DOWN: {
+ final int index = MotionEventCompat.getActionIndex(e);
+ mActivePointerId = MotionEventCompat.getPointerId(e, 0);
+ mLastTouchX = getMotionEventX(e, index);
+ mLastTouchY = getMotionEventY(e, index);
+ }
+ break;
+
+ case MotionEvent.ACTION_MOVE: {
+ final int index = MotionEventCompat.findPointerIndex(e, mActivePointerId);
+ if (index < 0) {
+ Log.e(TAG, "Error processing scroll; pointer index for id " + index + " not found. Did any MotionEvents get skipped?");
+ return false;
+ }
+
+ final int x = getMotionEventX(e, index);
+ final int y = getMotionEventY(e, index);
+
+ final int dx = x - mLastTouchX;
+ final int dy = y - mLastTouchY;
+
+ mLastTouchX = x;
+ mLastTouchY = y;
+
+ final boolean triggerCondition = isEnabled() && mRefreshEnabled && mRefreshHeaderView != null && isFingerDragging() && canTriggerRefresh();
+ if (DEBUG) {
+ Log.i(TAG, "triggerCondition = " + triggerCondition + "; mStatus = " + mStatus + "; dy = " + dy);
+ }
+ if (triggerCondition) {
+
+ final int refreshHeaderContainerHeight = mRefreshHeaderContainer.getMeasuredHeight();
+ final int refreshHeaderViewHeight = mRefreshHeaderView.getMeasuredHeight();
+
+ if (dy > 0 && mStatus == STATUS_DEFAULT) {
+ //下拉 设置成下拉刷新状态
+ setStatus(STATUS_SWIPING_TO_REFRESH);
+ mRefreshTrigger.onStart(false, refreshHeaderViewHeight, mRefreshFinalMoveOffset);
+ } else if (dy < 0) {
+ //收缩瞬间 设置成默认状态
+ if (mStatus == STATUS_SWIPING_TO_REFRESH && refreshHeaderContainerHeight <= 0) {
+ setStatus(STATUS_DEFAULT);
+ }
+ if (mStatus == STATUS_DEFAULT) {
+ break;
+ }
+ }
+
+ if (mStatus == STATUS_SWIPING_TO_REFRESH || mStatus == STATUS_RELEASE_TO_REFRESH) {
+ if (refreshHeaderContainerHeight >= refreshHeaderViewHeight) {
+ setStatus(STATUS_RELEASE_TO_REFRESH);
+ } else {
+ setStatus(STATUS_SWIPING_TO_REFRESH);
+ }
+ fingerMove(dy);
+ return true;
+ }
+ }
+ }
+ break;
+
+ case MotionEventCompat.ACTION_POINTER_DOWN: {
+ final int index = MotionEventCompat.getActionIndex(e);
+ mActivePointerId = MotionEventCompat.getPointerId(e, index);
+ mLastTouchX = getMotionEventX(e, index);
+ mLastTouchY = getMotionEventY(e, index);
+ }
+ break;
+
+ case MotionEventCompat.ACTION_POINTER_UP: {
+ onPointerUp(e);
+ }
+ break;
+
+ case MotionEvent.ACTION_UP: {
+ onFingerUpStartAnimating();
+ }
+ break;
+
+ case MotionEvent.ACTION_CANCEL: {
+ onFingerUpStartAnimating();
+ }
+ break;
+ }
+ return super.onTouchEvent(e);
+ }
+
+ private boolean isFingerDragging() {
+ return getScrollState() == SCROLL_STATE_DRAGGING;
+ }
+
+ public boolean canTriggerRefresh() {
+
+ if (mOriginAdapter == null || mOriginAdapter.getItemCount() <= 0) {
+ return true;
+ }
+ View firstChild = getChildAt(0);
+ int position = getChildLayoutPosition(firstChild);
+ if (position == 0) {
+ if (firstChild.getTop() == mRefreshHeaderContainer.getTop()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private int getMotionEventX(MotionEvent e, int pointerIndex) {
+ return (int) (MotionEventCompat.getX(e, pointerIndex) + 0.5f);
+ }
+
+ private int getMotionEventY(MotionEvent e, int pointerIndex) {
+ return (int) (MotionEventCompat.getY(e, pointerIndex) + 0.5f);
+ }
+
+ private void onFingerUpStartAnimating() {
+ if (mStatus == STATUS_RELEASE_TO_REFRESH) {
+ startScrollReleaseStatusToRefreshingStatus();
+ } else if (mStatus == STATUS_SWIPING_TO_REFRESH) {
+ startScrollSwipingToRefreshStatusToDefaultStatus();
+ }
+ }
+
+ private void onPointerUp(MotionEvent e) {
+ final int actionIndex = MotionEventCompat.getActionIndex(e);
+ if (MotionEventCompat.getPointerId(e, actionIndex) == mActivePointerId) {
+ // Pick a new pointer to pick up the slack.
+ final int newIndex = actionIndex == 0 ? 1 : 0;
+ mActivePointerId = MotionEventCompat.getPointerId(e, newIndex);
+ mLastTouchX = getMotionEventX(e, newIndex);
+ mLastTouchY = getMotionEventY(e, newIndex);
+ }
+ }
+
+ private void fingerMove(int dy) {
+ int ratioDy = (int) (dy * 0.5f + 0.5f);
+ int offset = mRefreshHeaderContainer.getMeasuredHeight();
+ int finalDragOffset = mRefreshFinalMoveOffset;
+
+ int nextOffset = offset + ratioDy;
+ if (finalDragOffset > 0) {
+ if (nextOffset > finalDragOffset) {
+ ratioDy = finalDragOffset - offset;
+ }
+ }
+
+ if (nextOffset < 0) {
+ ratioDy = -offset;
+ }
+ move(ratioDy);
+ }
+
+ private void move(int dy) {
+ if (dy != 0) {
+ int height = mRefreshHeaderContainer.getMeasuredHeight() + dy;
+ setRefreshHeaderContainerHeight(height);
+ mRefreshTrigger.onMove(false, false, height);
+ }
+ }
+
+ private void setRefreshHeaderContainerHeight(int height) {
+ mRefreshHeaderContainer.getLayoutParams().height = height;
+ mRefreshHeaderContainer.requestLayout();
+ }
+
+ /**
+ * 强制刷新的状态 状态是STATUS_SWIPING_TO_REFRESH
+ */
+ private void startScrollDefaultStatusToRefreshingStatus() {
+ mRefreshTrigger.onStart(true, mRefreshHeaderView.getMeasuredHeight(), mRefreshFinalMoveOffset);
+
+ int targetHeight = mRefreshHeaderView.getMeasuredHeight();
+ int currentHeight = mRefreshHeaderContainer.getMeasuredHeight();
+ startScrollAnimation(400, new AccelerateInterpolator(), currentHeight, targetHeight);
+ }
+
+ /**
+ * 没达到刷新要求,默认恢复 状态是STATUS_SWIPING_TO_REFRESH
+ */
+ private void startScrollSwipingToRefreshStatusToDefaultStatus() {
+ final int targetHeight = 0;
+ final int currentHeight = mRefreshHeaderContainer.getMeasuredHeight();
+ startScrollAnimation(300, new DecelerateInterpolator(), currentHeight, targetHeight);
+ }
+
+ /**
+ * 释放刷新 状态是STATUS_RELEASE_TO_REFRESH
+ */
+ private void startScrollReleaseStatusToRefreshingStatus() {
+ mRefreshTrigger.onRelease();
+
+ final int targetHeight = mRefreshHeaderView.getMeasuredHeight();
+ final int currentHeight = mRefreshHeaderContainer.getMeasuredHeight();
+ startScrollAnimation(300, new DecelerateInterpolator(), currentHeight, targetHeight);
+ }
+
+ /**
+ * 强制关闭刷新 状态是STATUS_REFRESHING
+ */
+ private void startScrollRefreshingStatusToDefaultStatus() {
+ mRefreshTrigger.onComplete();
+
+ final int targetHeight = 0;
+ final int currentHeight = mRefreshHeaderContainer.getMeasuredHeight();
+ startScrollAnimation(400, new DecelerateInterpolator(), currentHeight, targetHeight);
+ }
+
+ private ValueAnimator mScrollAnimator;
+
+ private void startScrollAnimation(final int time, final Interpolator interpolator, int value, int toValue) {
+ if (mScrollAnimator == null) {
+ mScrollAnimator = new ValueAnimator();
+ }
+ //cancel
+ mScrollAnimator.removeAllUpdateListeners();
+ mScrollAnimator.removeAllListeners();
+ mScrollAnimator.cancel();
+
+ //reset new value
+ mScrollAnimator.setIntValues(value, toValue);
+ mScrollAnimator.setDuration(time);
+ mScrollAnimator.setInterpolator(interpolator);
+ mScrollAnimator.addUpdateListener(mAnimatorUpdateListener);
+ mScrollAnimator.addListener(mAnimationListener);
+ mScrollAnimator.start();
+ }
+
+ private ValueAnimator.AnimatorUpdateListener mAnimatorUpdateListener = new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ final int height = (Integer) animation.getAnimatedValue();
+ setRefreshHeaderContainerHeight(height);
+ switch (mStatus) {
+ case STATUS_SWIPING_TO_REFRESH: {
+ mRefreshTrigger.onMove(false, true, height);
+ }
+ break;
+
+ case STATUS_RELEASE_TO_REFRESH: {
+ mRefreshTrigger.onMove(false, true, height);
+ }
+ break;
+
+ case STATUS_REFRESHING: {
+ mRefreshTrigger.onMove(true, true, height);
+ }
+ break;
+ }
+
+ }
+ };
+
+ private Animator.AnimatorListener mAnimationListener = new SimpleAnimatorListener() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ int lastStatus = mStatus;
+
+ switch (mStatus) {
+ case STATUS_SWIPING_TO_REFRESH: {
+ //对应强制刷新的状态
+ if (mIsAutoRefreshing) {
+ mRefreshHeaderContainer.getLayoutParams().height = mRefreshHeaderView.getMeasuredHeight();
+ mRefreshHeaderContainer.requestLayout();
+ setStatus(STATUS_REFRESHING);
+ if (mOnRefreshListener != null) {
+ mOnRefreshListener.onRefresh();
+ mRefreshTrigger.onRefresh();
+ }
+ } else {
+ //对应恢复原有情况
+ mRefreshHeaderContainer.getLayoutParams().height = 0;
+ mRefreshHeaderContainer.requestLayout();
+ setStatus(STATUS_DEFAULT);
+ }
+ }
+ break;
+ //对应释放刷新
+ case STATUS_RELEASE_TO_REFRESH: {
+ mRefreshHeaderContainer.getLayoutParams().height = mRefreshHeaderView.getMeasuredHeight();
+ mRefreshHeaderContainer.requestLayout();
+ setStatus(STATUS_REFRESHING);
+ if (mOnRefreshListener != null) {
+ mOnRefreshListener.onRefresh();
+ mRefreshTrigger.onRefresh();
+ }
+ }
+ break;
+ //对应强制关闭
+ case STATUS_REFRESHING: {
+ mIsAutoRefreshing = false;
+ mRefreshHeaderContainer.getLayoutParams().height = 0;
+ mRefreshHeaderContainer.requestLayout();
+ setStatus(STATUS_DEFAULT);
+ mRefreshTrigger.onReset();
+ }
+ break;
+ }
+ if (DEBUG) {
+ Log.i(TAG, "onAnimationEnd " + getStatusLog(lastStatus) + " -> " + getStatusLog(mStatus) + " ;refresh view height:" + mRefreshHeaderContainer.getMeasuredHeight());
+ }
+ }
+ };
+
+ private RefreshTrigger mRefreshTrigger = new RefreshTrigger() {
+ @Override
+ public void onStart(boolean automatic, int headerHeight, int finalHeight) {
+ if (mRefreshHeaderView != null && mRefreshHeaderView instanceof RefreshTrigger) {
+ RefreshTrigger trigger = (RefreshTrigger) mRefreshHeaderView;
+ trigger.onStart(automatic, headerHeight, finalHeight);
+ }
+ }
+
+ @Override
+ public void onMove(boolean finished, boolean automatic, int moved) {
+ if (mRefreshHeaderView != null && mRefreshHeaderView instanceof RefreshTrigger) {
+ RefreshTrigger trigger = (RefreshTrigger) mRefreshHeaderView;
+ trigger.onMove(finished, automatic, moved);
+ }
+ }
+
+ @Override
+ public void onRefresh() {
+ if (mRefreshHeaderView != null && mRefreshHeaderView instanceof RefreshTrigger) {
+ RefreshTrigger trigger = (RefreshTrigger) mRefreshHeaderView;
+ trigger.onRefresh();
+ }
+ }
+
+ @Override
+ public void onRelease() {
+ if (mRefreshHeaderView != null && mRefreshHeaderView instanceof RefreshTrigger) {
+ RefreshTrigger trigger = (RefreshTrigger) mRefreshHeaderView;
+ trigger.onRelease();
+ }
+ }
+
+ @Override
+ public void onComplete() {
+ if (mRefreshHeaderView != null && mRefreshHeaderView instanceof RefreshTrigger) {
+ RefreshTrigger trigger = (RefreshTrigger) mRefreshHeaderView;
+ trigger.onComplete();
+ }
+ }
+
+ @Override
+ public void onReset() {
+ if (mRefreshHeaderView != null && mRefreshHeaderView instanceof RefreshTrigger) {
+ RefreshTrigger trigger = (RefreshTrigger) mRefreshHeaderView;
+ trigger.onReset();
+ }
+ }
+ };
+
+ private OnLoadMoreScrollListener mOnLoadMoreScrollListener = new OnLoadMoreScrollListener() {
+ @Override
+ public void onLoadMore(RecyclerView recyclerView) {
+ if (mOnLoadMoreListener != null && mStatus == STATUS_DEFAULT) {
+ mOnLoadMoreListener.onLoadMore();
+ }
+ }
+ };
+
+ private void setStatus(int status) {
+ this.mStatus = status;
+ if (DEBUG) {
+ printStatusLog();
+ }
+ }
+
+ private void printStatusLog() {
+ Log.i(TAG, getStatusLog(mStatus));
+ }
+
+ private String getStatusLog(int status) {
+ final String statusLog;
+ switch (status) {
+ case STATUS_DEFAULT:
+ statusLog = "status_default";
+ break;
+
+ case STATUS_SWIPING_TO_REFRESH:
+ statusLog = "status_swiping_to_refresh";
+ break;
+
+ case STATUS_RELEASE_TO_REFRESH:
+ statusLog = "status_release_to_refresh";
+ break;
+
+ case STATUS_REFRESHING:
+ statusLog = "status_refreshing";
+ break;
+ default:
+ statusLog = "status_illegal!";
+ break;
+ }
+ return statusLog;
+ }
+}
\ No newline at end of file
diff --git a/recyclerview_helper/library/src/main/java/com/lvr/library/recyclerview/OnLoadMoreListener.java b/recyclerview_helper/library/src/main/java/com/lvr/library/recyclerview/OnLoadMoreListener.java
new file mode 100644
index 0000000..44d467c
--- /dev/null
+++ b/recyclerview_helper/library/src/main/java/com/lvr/library/recyclerview/OnLoadMoreListener.java
@@ -0,0 +1,8 @@
+package com.lvr.library.recyclerview;
+
+
+public interface OnLoadMoreListener {
+
+ void onLoadMore();
+
+}
diff --git a/recyclerview_helper/library/src/main/java/com/lvr/library/recyclerview/OnLoadMoreScrollListener.java b/recyclerview_helper/library/src/main/java/com/lvr/library/recyclerview/OnLoadMoreScrollListener.java
new file mode 100644
index 0000000..40ce577
--- /dev/null
+++ b/recyclerview_helper/library/src/main/java/com/lvr/library/recyclerview/OnLoadMoreScrollListener.java
@@ -0,0 +1,37 @@
+package com.lvr.library.recyclerview;
+
+import android.support.v7.widget.RecyclerView;
+import android.view.View;
+
+
+public abstract class OnLoadMoreScrollListener extends RecyclerView.OnScrollListener {
+
+ @Override
+ public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
+ }
+
+ @Override
+ public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
+ RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
+ int visibleItemCount = layoutManager.getChildCount();
+
+
+ boolean triggerCondition = visibleItemCount > 0
+ && newState == RecyclerView.SCROLL_STATE_IDLE
+ && canTriggerLoadMore(recyclerView);
+
+ if (triggerCondition) {
+ onLoadMore(recyclerView);
+ }
+ }
+
+ public boolean canTriggerLoadMore(RecyclerView recyclerView) {
+ View lastChild = recyclerView.getChildAt(recyclerView.getChildCount() - 1);
+ int position = recyclerView.getChildLayoutPosition(lastChild);
+ RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
+ int totalItemCount = layoutManager.getItemCount();
+ return totalItemCount - 1 == position;
+ }
+
+ public abstract void onLoadMore(RecyclerView recyclerView);
+}
diff --git a/recyclerview_helper/library/src/main/java/com/lvr/library/recyclerview/OnRefreshListener.java b/recyclerview_helper/library/src/main/java/com/lvr/library/recyclerview/OnRefreshListener.java
new file mode 100644
index 0000000..67f1c67
--- /dev/null
+++ b/recyclerview_helper/library/src/main/java/com/lvr/library/recyclerview/OnRefreshListener.java
@@ -0,0 +1,6 @@
+package com.lvr.library.recyclerview;
+
+
+public interface OnRefreshListener {
+ void onRefresh();
+}
diff --git a/recyclerview_helper/library/src/main/java/com/lvr/library/recyclerview/RefreshHeaderLayout.java b/recyclerview_helper/library/src/main/java/com/lvr/library/recyclerview/RefreshHeaderLayout.java
new file mode 100644
index 0000000..d2c6bd2
--- /dev/null
+++ b/recyclerview_helper/library/src/main/java/com/lvr/library/recyclerview/RefreshHeaderLayout.java
@@ -0,0 +1,113 @@
+package com.lvr.library.recyclerview;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * Created by aspsine on 16/3/7.
+ */
+public class RefreshHeaderLayout extends ViewGroup {
+
+ public RefreshHeaderLayout(Context context) {
+ this(context, null);
+ }
+
+ public RefreshHeaderLayout(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public RefreshHeaderLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ /**
+ * LayoutParams of RefreshHeaderLayout
+ */
+ public static class LayoutParams extends MarginLayoutParams {
+
+ public LayoutParams(Context c, AttributeSet attrs) {
+ super(c, attrs);
+ }
+
+ public LayoutParams(int width, int height) {
+ super(width, height);
+ }
+
+ public LayoutParams(MarginLayoutParams source) {
+ super(source);
+ }
+
+ public LayoutParams(ViewGroup.LayoutParams source) {
+ super(source);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
+ return new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
+ return new LayoutParams(p);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
+ return new LayoutParams(getContext(), attrs);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ int childCount = getChildCount();
+ if (childCount > 0) {
+ int childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+ View view = getChildAt(0);
+ measureChildWithMargins(view, widthMeasureSpec, 0, childHeightSpec, 0);
+ }
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ layoutChildren();
+ }
+
+ private void layoutChildren() {
+ final int width = getMeasuredWidth();
+ final int height = getMeasuredHeight();
+
+ final int paddingLeft = getPaddingLeft();
+ final int paddingTop = getPaddingTop();
+ final int paddingRight = getPaddingRight();
+ final int paddintBottom = getPaddingBottom();
+
+ int childCount = getChildCount();
+
+ if (childCount > 0) {
+ View child = getChildAt(0);
+ int childWidth = child.getMeasuredWidth();
+ int childHeight = child.getMeasuredHeight();
+
+ MarginLayoutParams marginLp = (MarginLayoutParams) child.getLayoutParams();
+
+ int childLeft = paddingLeft + marginLp.leftMargin;
+ int childTop = paddingTop + marginLp.topMargin - (childHeight - height);
+ int childRight = childLeft + childWidth;
+ int childBottom = childTop + childHeight;
+
+ child.layout(childLeft, childTop, childRight, childBottom);
+ }
+ }
+}
diff --git a/recyclerview_helper/library/src/main/java/com/lvr/library/recyclerview/RefreshTrigger.java b/recyclerview_helper/library/src/main/java/com/lvr/library/recyclerview/RefreshTrigger.java
new file mode 100644
index 0000000..43ade0d
--- /dev/null
+++ b/recyclerview_helper/library/src/main/java/com/lvr/library/recyclerview/RefreshTrigger.java
@@ -0,0 +1,17 @@
+package com.lvr.library.recyclerview;
+
+
+public interface RefreshTrigger {
+
+ void onStart(boolean automatic, int headerHeight, int finalHeight);
+
+ void onMove(boolean finished, boolean automatic, int moved);
+
+ void onRefresh();
+
+ void onRelease();
+
+ void onComplete();
+
+ void onReset();
+}
diff --git a/recyclerview_helper/library/src/main/java/com/lvr/library/recyclerview/SimpleAnimatorListener.java b/recyclerview_helper/library/src/main/java/com/lvr/library/recyclerview/SimpleAnimatorListener.java
new file mode 100644
index 0000000..63f4ec5
--- /dev/null
+++ b/recyclerview_helper/library/src/main/java/com/lvr/library/recyclerview/SimpleAnimatorListener.java
@@ -0,0 +1,25 @@
+package com.lvr.library.recyclerview;
+
+import android.animation.Animator;
+
+public class SimpleAnimatorListener implements Animator.AnimatorListener {
+ @Override
+ public void onAnimationStart(Animator animation) {
+
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animation) {
+
+ }
+}
diff --git a/recyclerview_helper/library/src/main/java/com/lvr/library/recyclerview/WrapperAdapter.java b/recyclerview_helper/library/src/main/java/com/lvr/library/recyclerview/WrapperAdapter.java
new file mode 100644
index 0000000..2e9b365
--- /dev/null
+++ b/recyclerview_helper/library/src/main/java/com/lvr/library/recyclerview/WrapperAdapter.java
@@ -0,0 +1,184 @@
+package com.lvr.library.recyclerview;
+
+import android.support.v7.widget.GridLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.StaggeredGridLayoutManager;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+
+
+public class WrapperAdapter extends RecyclerView.Adapter {
+ protected static final int REFRESH_HEADER = Integer.MIN_VALUE;
+ protected static final int HEADER = Integer.MIN_VALUE + 1;
+ protected static final int FOOTER = Integer.MAX_VALUE - 1;
+ protected static final int LOAD_MORE_FOOTER = Integer.MAX_VALUE;
+
+ private final RecyclerView.Adapter mAdapter;
+
+ private final RefreshHeaderLayout mRefreshHeaderContainer;
+
+ private final FrameLayout mLoadMoreFooterContainer;
+
+ private final LinearLayout mHeaderContainer;
+
+ private final LinearLayout mFooterContainer;
+
+ private RecyclerView.AdapterDataObserver mObserver = new RecyclerView.AdapterDataObserver() {
+ @Override
+ public void onChanged() {
+ WrapperAdapter.this.notifyDataSetChanged();
+ }
+
+ @Override
+ public void onItemRangeChanged(int positionStart, int itemCount) {
+ WrapperAdapter.this.notifyItemRangeChanged(positionStart + 2, itemCount);
+ }
+
+ @Override
+ public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
+ WrapperAdapter.this.notifyItemRangeChanged(positionStart + 2, itemCount, payload);
+ }
+
+ @Override
+ public void onItemRangeInserted(int positionStart, int itemCount) {
+ WrapperAdapter.this.notifyItemRangeInserted(positionStart + 2, itemCount);
+ }
+
+ @Override
+ public void onItemRangeRemoved(int positionStart, int itemCount) {
+ WrapperAdapter.this.notifyItemRangeRemoved(positionStart + 2, itemCount);
+ }
+
+ @Override
+ public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
+ WrapperAdapter.this.notifyDataSetChanged();
+ }
+ };
+
+ public WrapperAdapter(RecyclerView.Adapter adapter, RefreshHeaderLayout refreshHeaderContainer, LinearLayout headerContainer, LinearLayout footerContainer, FrameLayout loadMoreFooterContainer) {
+ this.mAdapter = adapter;
+ this.mRefreshHeaderContainer = refreshHeaderContainer;
+ this.mHeaderContainer = headerContainer;
+ this.mFooterContainer = footerContainer;
+ this.mLoadMoreFooterContainer = loadMoreFooterContainer;
+
+ mAdapter.registerAdapterDataObserver(mObserver);
+ }
+
+ public RecyclerView.Adapter getAdapter() {
+ return mAdapter;
+ }
+
+ @Override
+ public void onAttachedToRecyclerView(final RecyclerView recyclerView) {
+ RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
+ if (layoutManager instanceof GridLayoutManager) {
+ final GridLayoutManager gridLayoutManager = (GridLayoutManager) layoutManager;
+ final GridLayoutManager.SpanSizeLookup spanSizeLookup = gridLayoutManager.getSpanSizeLookup();
+ gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
+ @Override
+ public int getSpanSize(int position) {
+ WrapperAdapter wrapperAdapter = (WrapperAdapter) recyclerView.getAdapter();
+ if (isFullSpanType(wrapperAdapter.getItemViewType(position))) {
+ return gridLayoutManager.getSpanCount();
+ } else if (spanSizeLookup != null) {
+ return spanSizeLookup.getSpanSize(position - 2);
+ }
+ return 1;
+ }
+ });
+ }
+ }
+
+ @Override
+ public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) {
+ super.onViewAttachedToWindow(holder);
+ int position = holder.getAdapterPosition();
+ int type = getItemViewType(position);
+ if (isFullSpanType(type)) {
+ ViewGroup.LayoutParams layoutParams = holder.itemView.getLayoutParams();
+ if (layoutParams instanceof StaggeredGridLayoutManager.LayoutParams) {
+ StaggeredGridLayoutManager.LayoutParams lp = (StaggeredGridLayoutManager.LayoutParams) layoutParams;
+ lp.setFullSpan(true);
+ }
+ }
+ }
+
+ private boolean isFullSpanType(int type) {
+ return type == REFRESH_HEADER || type == HEADER || type == FOOTER || type == LOAD_MORE_FOOTER;
+ }
+
+ @Override
+ public int getItemCount() {
+ return mAdapter.getItemCount() + 4;
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ if (position == 0) {
+ return REFRESH_HEADER;
+ } else if (position == 1) {
+ return HEADER;
+ } else if (1 < position && position < mAdapter.getItemCount() + 2) {
+ return mAdapter.getItemViewType(position - 2);
+ } else if (position == mAdapter.getItemCount() + 2) {
+ return FOOTER;
+ } else if (position == mAdapter.getItemCount() + 3) {
+ return LOAD_MORE_FOOTER;
+ }
+
+ throw new IllegalArgumentException("Wrong type! Position = " + position);
+ }
+
+ @Override
+ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ if (viewType == REFRESH_HEADER) {
+ return new RefreshHeaderContainerViewHolder(mRefreshHeaderContainer);
+ } else if (viewType == HEADER) {
+ return new HeaderContainerViewHolder(mHeaderContainer);
+ } else if (viewType == FOOTER) {
+ return new FooterContainerViewHolder(mFooterContainer);
+ } else if (viewType == LOAD_MORE_FOOTER) {
+ return new LoadMoreFooterContainerViewHolder(mLoadMoreFooterContainer);
+ } else {
+ return mAdapter.onCreateViewHolder(parent, viewType);
+ }
+ }
+
+ @Override
+ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
+ if (1 < position && position < mAdapter.getItemCount() + 2) {
+ mAdapter.onBindViewHolder(holder, position - 2);
+ }
+ }
+
+ static class RefreshHeaderContainerViewHolder extends RecyclerView.ViewHolder {
+
+ public RefreshHeaderContainerViewHolder(View itemView) {
+ super(itemView);
+ }
+ }
+
+ static class HeaderContainerViewHolder extends RecyclerView.ViewHolder {
+
+ public HeaderContainerViewHolder(View itemView) {
+ super(itemView);
+ }
+ }
+
+ static class FooterContainerViewHolder extends RecyclerView.ViewHolder {
+
+ public FooterContainerViewHolder(View itemView) {
+ super(itemView);
+ }
+ }
+
+ static class LoadMoreFooterContainerViewHolder extends RecyclerView.ViewHolder {
+
+ public LoadMoreFooterContainerViewHolder(View itemView) {
+ super(itemView);
+ }
+ }
+}
diff --git a/recyclerview_helper/library/src/main/java/com/lvr/library/support/MultiItemTypeSupport.java b/recyclerview_helper/library/src/main/java/com/lvr/library/support/MultiItemTypeSupport.java
new file mode 100644
index 0000000..be98f1c
--- /dev/null
+++ b/recyclerview_helper/library/src/main/java/com/lvr/library/support/MultiItemTypeSupport.java
@@ -0,0 +1,12 @@
+package com.lvr.library.support;
+
+/**
+ * Created by lvr on 2017/5/24.
+ */
+
+public interface MultiItemTypeSupport
+{
+ int getLayoutId(int itemType);
+
+ int getItemViewType(int position, T t);
+}
diff --git a/recyclerview_helper/library/src/main/res/attrs.xml b/recyclerview_helper/library/src/main/res/attrs.xml
new file mode 100644
index 0000000..df25174
--- /dev/null
+++ b/recyclerview_helper/library/src/main/res/attrs.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/recyclerview_helper/library/src/main/res/values/attrs.xml b/recyclerview_helper/library/src/main/res/values/attrs.xml
new file mode 100644
index 0000000..df25174
--- /dev/null
+++ b/recyclerview_helper/library/src/main/res/values/attrs.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file