+ * My GitHub : https://github.com/af913337456/ + *
+ * My Blog : http://www.cnblogs.com/linguanh/ + *
+ * on 2017/11/8.
+ */
+
+public interface CustomFooterViewCallBack {
+
+ void onLoadingMore(View yourFooterView);
+ void onLoadMoreComplete(View yourFooterView);
+ void onSetNoMore(View yourFooterView,boolean noMore);
+
+}
diff --git a/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/ItemTouchHelperAdapter.java b/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/ItemTouchHelperAdapter.java
new file mode 100644
index 0000000..d7e6602
--- /dev/null
+++ b/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/ItemTouchHelperAdapter.java
@@ -0,0 +1,38 @@
+package com.jcodecraeer.xrecyclerview;
+
+
+/**
+ * Created by jianghejie on 16/6/20.
+ */
+
+public interface ItemTouchHelperAdapter {
+
+ /**
+ * Called when an item has been dragged far enough to trigger a move. This is called every time
+ * an item is shifted, and not at the end of a "drop" event.
+ *
+ * Implementations should call {@link RecyclerView.Adapter#notifyItemMoved(int, int)} after
+ * adjusting the underlying data to reflect this move.
+ *
+ * @param fromPosition The start position of the moved item.
+ * @param toPosition Then resolved position of the moved item.
+ *
+ * @see RecyclerView#getAdapterPositionFor(RecyclerView.ViewHolder)
+ * @see RecyclerView.ViewHolder#getAdapterPosition()
+ */
+ void onItemMove(int fromPosition, int toPosition);
+
+
+ /**
+ * Called when an item has been dismissed by a swipe.
+ *
+ * Implementations should call {@link RecyclerView.Adapter#notifyItemRemoved(int)} after
+ * adjusting the underlying data to reflect this removal.
+ *
+ * @param position The position of the item dismissed.
+ *
+ * @see RecyclerView#getAdapterPositionFor(RecyclerView.ViewHolder)
+ * @see RecyclerView.ViewHolder#getAdapterPosition()
+ */
+ void onItemDismiss(int position);
+}
diff --git a/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/JellyView.java b/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/JellyView.java
new file mode 100644
index 0000000..3d20e6f
--- /dev/null
+++ b/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/JellyView.java
@@ -0,0 +1,108 @@
+package com.jcodecraeer.xrecyclerview;
+
+/**
+ * Created by jianghejie on 15/11/22.
+ */
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.os.Build;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+
+
+public class JellyView extends View implements BaseRefreshHeader{
+ Path path;
+
+ Paint paint;
+
+ private int minimumHeight = 0;
+
+ private int jellyHeight =0;
+
+ public JellyView(Context context) {
+ super(context);
+ init();
+ }
+
+ public JellyView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ }
+
+ public JellyView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init();
+ }
+
+ @SuppressWarnings("unused")
+ @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+ public JellyView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ init();
+ }
+
+ private void init() {
+ if (isInEditMode()) {
+ return;
+ }
+ path = new Path();
+ paint = new Paint();
+ paint.setColor(getContext().getResources().getColor(android.R.color.holo_blue_bright));
+ paint.setAntiAlias(true);
+ }
+
+ public void setJellyColor(int jellyColor) {
+ paint.setColor(jellyColor);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ path.reset();
+ path.lineTo(0, minimumHeight);
+ path.quadTo(getMeasuredWidth() / 2, minimumHeight + jellyHeight, getMeasuredWidth(), minimumHeight);
+ path.lineTo(getMeasuredWidth(), 0);
+ canvas.drawPath(path, paint);
+ }
+
+ @Override
+ public void setMinimumHeight(int minimumHeight) {
+ this.minimumHeight = minimumHeight;
+ }
+
+ public void setJellyHeight(int ribbonHeight) {
+ this.jellyHeight = ribbonHeight;
+ }
+
+ @Override
+ public int getMinimumHeight() {
+ return minimumHeight;
+ }
+
+ public int getJellyHeight() {
+ return jellyHeight;
+ }
+
+
+ @Override
+ public void refreshComplete(){
+
+ }
+
+ @Override
+ public void onMove(float delta) {
+ jellyHeight = jellyHeight + (int)delta;
+ Log.i("jellyHeight", "delta = " + delta);
+ this.invalidate();
+ }
+
+ @Override
+ public boolean releaseAction() {
+ return false;
+ }
+}
diff --git a/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/LoadingMoreFooter.java b/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/LoadingMoreFooter.java
new file mode 100644
index 0000000..8a2755c
--- /dev/null
+++ b/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/LoadingMoreFooter.java
@@ -0,0 +1,127 @@
+package com.jcodecraeer.xrecyclerview;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.LinearLayout;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+
+import com.jcodecraeer.xrecyclerview.progressindicator.AVLoadingIndicatorView;
+
+import androidx.recyclerview.widget.RecyclerView;
+
+public class LoadingMoreFooter extends LinearLayout {
+
+ private SimpleViewSwitcher progressCon;
+ public final static int STATE_LOADING = 0;
+ public final static int STATE_COMPLETE = 1;
+ public final static int STATE_NOMORE = 2;
+
+ private TextView mText;
+ private String loadingHint;
+ private String noMoreHint;
+ private String loadingDoneHint;
+
+ private AVLoadingIndicatorView progressView;
+
+ public LoadingMoreFooter(Context context) {
+ super(context);
+ initView();
+ }
+
+ /**
+ * @param context
+ * @param attrs
+ */
+ public LoadingMoreFooter(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ initView();
+ }
+
+ public void destroy(){
+ progressCon = null;
+ if(progressView != null){
+ progressView.destroy();
+ progressView = null;
+ }
+ }
+
+ public void setLoadingHint(String hint) {
+ loadingHint = hint;
+ }
+
+ public void setNoMoreHint(String hint) {
+ noMoreHint = hint;
+ }
+
+ public void setLoadingDoneHint(String hint) {
+ loadingDoneHint = hint;
+ }
+
+ public void initView(){
+ setGravity(Gravity.CENTER);
+ setLayoutParams(new RecyclerView.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
+ progressCon = new SimpleViewSwitcher(getContext());
+ progressCon.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
+
+ progressView = new AVLoadingIndicatorView(this.getContext());
+ progressView.setIndicatorColor(0xffB5B5B5);
+ progressView.setIndicatorId(ProgressStyle.BallSpinFadeLoader);
+ progressCon.setView(progressView);
+
+ addView(progressCon);
+ mText = new TextView(getContext());
+ mText.setText(getContext().getString(R.string.listview_loading));
+
+ if(loadingHint == null || loadingHint.equals("")){
+ loadingHint = (String)getContext().getText(R.string.listview_loading);
+ }
+ if(noMoreHint == null || noMoreHint.equals("")){
+ noMoreHint = (String)getContext().getText(R.string.nomore_loading);
+ }
+ if(loadingDoneHint == null || loadingDoneHint.equals("")){
+ loadingDoneHint = (String)getContext().getText(R.string.loading_done);
+ }
+
+ LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+ layoutParams.setMargins( (int)getResources().getDimension(R.dimen.textandiconmargin),0,0,0 );
+
+ mText.setLayoutParams(layoutParams);
+ addView(mText);
+ }
+
+ public void setProgressStyle(int style) {
+ if(style == ProgressStyle.SysProgress){
+ progressCon.setView(new ProgressBar(getContext(), null, android.R.attr.progressBarStyle));
+ }else{
+ progressView = new AVLoadingIndicatorView(this.getContext());
+ progressView.setIndicatorColor(0xffB5B5B5);
+ progressView.setIndicatorId(style);
+ progressCon.setView(progressView);
+ }
+ }
+
+ public void setState(int state) {
+ switch(state) {
+ case STATE_LOADING:
+ progressCon.setVisibility(View.VISIBLE);
+ mText.setText(loadingHint);
+ this.setVisibility(View.VISIBLE);
+ break;
+ case STATE_COMPLETE:
+ mText.setText(loadingDoneHint);
+ this.setVisibility(View.GONE);
+ break;
+ case STATE_NOMORE:
+ mText.setText(noMoreHint);
+ progressCon.setVisibility(View.GONE);
+ this.setVisibility(View.VISIBLE);
+ break;
+ }
+ }
+}
diff --git a/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/ProgressStyle.java b/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/ProgressStyle.java
new file mode 100644
index 0000000..7b6dd0d
--- /dev/null
+++ b/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/ProgressStyle.java
@@ -0,0 +1,36 @@
+package com.jcodecraeer.xrecyclerview;
+
+/**
+ * Created by jianghejie on 15/11/23.
+ */
+public class ProgressStyle {
+ public static final int SysProgress=-1;
+ public static final int BallPulse=0;
+ public static final int BallGridPulse=1;
+ public static final int BallClipRotate=2;
+ public static final int BallClipRotatePulse=3;
+ public static final int SquareSpin=4;
+ public static final int BallClipRotateMultiple=5;
+ public static final int BallPulseRise=6;
+ public static final int BallRotate=7;
+ public static final int CubeTransition=8;
+ public static final int BallZigZag=9;
+ public static final int BallZigZagDeflect=10;
+ public static final int BallTrianglePath=11;
+ public static final int BallScale=12;
+ public static final int LineScale=13;
+ public static final int LineScaleParty=14;
+ public static final int BallScaleMultiple=15;
+ public static final int BallPulseSync=16;
+ public static final int BallBeat=17;
+ public static final int LineScalePulseOut=18;
+ public static final int LineScalePulseOutRapid=19;
+ public static final int BallScaleRipple=20;
+ public static final int BallScaleRippleMultiple=21;
+ public static final int BallSpinFadeLoader=22;
+ public static final int LineSpinFadeLoader=23;
+ public static final int TriangleSkewSpin=24;
+ public static final int Pacman=25;
+ public static final int BallGridBeat=26;
+ public static final int SemiCircleSpin=27;
+}
diff --git a/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/SimpleItemTouchHelperCallback.java b/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/SimpleItemTouchHelperCallback.java
new file mode 100644
index 0000000..100f26c
--- /dev/null
+++ b/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/SimpleItemTouchHelperCallback.java
@@ -0,0 +1,88 @@
+package com.jcodecraeer.xrecyclerview;
+
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.view.View;
+
+import androidx.recyclerview.widget.ItemTouchHelper;
+import androidx.recyclerview.widget.RecyclerView;
+
+/**
+ * Created by jianghejie on 16/6/20.
+ */
+
+public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback {
+
+ public static final float ALPHA_FULL = 1.0f;
+
+ private final ItemTouchHelperAdapter mAdapter;
+ private XRecyclerView mXrecyclerView;
+
+ public SimpleItemTouchHelperCallback(ItemTouchHelperAdapter adapter, XRecyclerView recyclerView) {
+ mAdapter = adapter;
+ this.mXrecyclerView = recyclerView;
+ }
+
+ @Override
+ public boolean isLongPressDragEnabled() {
+ return true;
+ }
+
+ @Override
+ public boolean isItemViewSwipeEnabled() {
+ return true;
+ }
+
+ @Override
+ public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
+ // Enable drag and swipe in both directions
+ final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
+ final int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
+ return makeMovementFlags(dragFlags, swipeFlags);
+ }
+
+ @Override
+ public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder source, RecyclerView.ViewHolder target) {
+ if (source.getItemViewType() != target.getItemViewType()) {
+ return false;
+ }
+ // Notify the adapter of the move
+ mAdapter.onItemMove(source.getAdapterPosition(), target.getAdapterPosition());
+ return true;
+ }
+
+ @Override
+ public void onSwiped(RecyclerView.ViewHolder viewHolder, int i) {
+ // Notify the adapter of the dismissal
+ mAdapter.onItemDismiss(viewHolder.getAdapterPosition());
+ }
+
+ @Override
+ public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
+ super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
+
+ // Fade out the view as it is swiped out of the parent's bounds
+ if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
+ View itemView = viewHolder.itemView;
+ final float alpha = ALPHA_FULL - Math.abs(dX) / (float) itemView.getWidth();
+ itemView.setAlpha(alpha);
+ }
+ }
+
+ @Override
+ public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
+ if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
+ // Let the view holder know that this item is being moved or dragged
+ viewHolder.itemView.setBackgroundColor(Color.LTGRAY);
+ }
+
+ super.onSelectedChanged(viewHolder, actionState);
+ }
+
+ @Override
+ public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
+ super.clearView(recyclerView, viewHolder);
+ viewHolder.itemView.setAlpha(ALPHA_FULL);
+ viewHolder.itemView.setBackgroundColor(0);
+ }
+}
diff --git a/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/SimpleViewSwitcher.java b/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/SimpleViewSwitcher.java
new file mode 100644
index 0000000..24410cc
--- /dev/null
+++ b/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/SimpleViewSwitcher.java
@@ -0,0 +1,60 @@
+package com.jcodecraeer.xrecyclerview;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * Created by jianghejie on 15/11/22.
+ */
+public class SimpleViewSwitcher extends ViewGroup {
+
+ public SimpleViewSwitcher(Context context) {
+ super(context);
+ }
+
+ public SimpleViewSwitcher(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public SimpleViewSwitcher(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ int childCount = this.getChildCount();
+ int maxHeight = 0;
+ int maxWidth = 0;
+ for (int i = 0; i < childCount; i++) {
+ View child = this.getChildAt(i);
+ this.measureChild(child, widthMeasureSpec, heightMeasureSpec);
+ int cw = child.getMeasuredWidth();
+ // int ch = child.getMeasuredHeight();
+ maxWidth = child.getMeasuredWidth();
+ maxHeight = child.getMeasuredHeight();
+ }
+ setMeasuredDimension(maxWidth, maxHeight);
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ final int count = getChildCount();
+ for (int i = 0; i < count; i++) {
+ final View child = getChildAt(i);
+ if (child.getVisibility() != View.GONE) {
+ child.layout(0, 0, r - l, b - t);
+
+ }
+ }
+ }
+
+ public void setView(View view) {
+ if (this.getChildCount() != 0){
+ this.removeViewAt(0);
+ }
+ this.addView(view,0);
+ }
+
+}
\ No newline at end of file
diff --git a/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/StickyScrollLinearLayout.java b/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/StickyScrollLinearLayout.java
new file mode 100644
index 0000000..edcfebd
--- /dev/null
+++ b/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/StickyScrollLinearLayout.java
@@ -0,0 +1,292 @@
+package com.jcodecraeer.xrecyclerview;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.VelocityTracker;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.LinearLayout;
+import android.widget.OverScroller;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.core.view.NestedScrollingParent;
+import androidx.core.view.ViewCompat;
+import androidx.recyclerview.widget.GridLayoutManager;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.recyclerview.widget.StaggeredGridLayoutManager;
+
+/**
+ * 作者:林冠宏
+ *
+ * My GitHub : https://github.com/af913337456/ + *
+ * My Blog : http://www.cnblogs.com/linguanh/ + *
+ * on 2017/12/31.
+ *
+ * DES:
+ * A LinearLayout which can combine with XRecyclerView in a sticky scroll status.
+ *
+ * Demo: see it in gitHub.
+ *
+ * Read_me:
+ * Only support XRecyclerView for now,if you wanna to support other viewGroups which
+ * has imp NestedScrollingChild interface,you can change my code,then it will be ok.
+ * When you use it to XR,you best close pull refresh model,because it may
+ * cause some new problems that i never met.
+ * ----LinGuanHong
+ */
+
+public class StickyScrollLinearLayout
+ extends LinearLayout
+ implements NestedScrollingParent
+{
+
+ private static final String TAG = "StickyScrollLayout";
+
+ private View mTopView;
+ private View mTabView;
+ private View mContentView;
+
+ private OverScroller mScroller;
+ private VelocityTracker mVelocityTracker;
+ private int mTopViewHeight;
+ private RecyclerView.LayoutManager layoutManager = null;
+ private int targetFirstVisiblePosition = 1;
+
+ public interface StickyScrollInitInterface{
+ View setTopView();
+ View setTabView();
+ View setContentView();
+ }
+
+ public StickyScrollLinearLayout(Context context) {
+ super(context);
+ init(context);
+ }
+
+ public StickyScrollLinearLayout(Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ init(context);
+ }
+
+ private void init(Context context){
+ setOrientation(LinearLayout.VERTICAL);
+ mScroller = new OverScroller(context);
+ }
+
+ @SuppressWarnings("all")
+ public void setInitInterface(@NonNull StickyScrollInitInterface initInterface){
+ if(initInterface == null)
+ throw new NullPointerException("initInterface can not be null!");
+ this.mTopView = initInterface.setTopView();
+ if(this.mTopView != null)
+ getTopViewHeight();
+
+ this.mTabView = initInterface.setTabView();
+
+ this.mContentView = initInterface.setContentView();
+ if(this.mContentView == null)
+ return;
+ setTotalHeight();
+ requestLayout();
+ }
+
+ public View getContentView(){
+ return this.mContentView;
+ }
+
+ // 设置,当 XR 里面显示的 item 第一个的位置是多少时,触发拦截
+ // to set a position of XR's dataList to control when we should call over scroll
+ public void setTargetFirstVisiblePosition(int targetFirstVisiblePosition) {
+ this.targetFirstVisiblePosition = targetFirstVisiblePosition;
+ }
+
+ @Override
+ public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
+ Log.e(TAG, "onStartNestedScroll "+child.toString()+" "+target.toString());
+ return true;
+ }
+
+ @Override
+ public void onNestedScrollAccepted(View child, View target, int nestedScrollAxes) {
+ Log.e(TAG, "onNestedScrollAccepted");
+ }
+
+ @Override
+ public void onStopNestedScroll(View target) {
+ Log.e(TAG, "onStopNestedScroll "+target.toString());
+ }
+
+ @Override
+ public void onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
+ Log.e(TAG, "onNestedScroll "+dyConsumed+"----"+dyUnconsumed);
+ }
+
+ @Override
+ public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
+
+ if(!(target instanceof XRecyclerView))
+ // todo 2017-12-31,make it more general
+ throw new UnsupportedOperationException("insert your content must is XRecyclerView!");
+
+ layoutManager = ((RecyclerView)target).getLayoutManager();
+
+ int firstVisiblePosition;
+ if (layoutManager instanceof GridLayoutManager) {
+ firstVisiblePosition = ((GridLayoutManager) layoutManager).findFirstCompletelyVisibleItemPosition();
+ } else if (layoutManager instanceof StaggeredGridLayoutManager) {
+ int[] into = new int[((StaggeredGridLayoutManager) layoutManager).getSpanCount()];
+ ((StaggeredGridLayoutManager) layoutManager).findFirstCompletelyVisibleItemPositions(into);
+ firstVisiblePosition = into[0];
+ } else {
+ firstVisiblePosition = ((LinearLayoutManager) layoutManager).findFirstCompletelyVisibleItemPosition();
+ }
+ if(firstVisiblePosition < 0)
+ return;
+
+ int scrollY = getScrollY();
+ boolean temp = dy > 0 && (scrollY < mTopViewHeight);
+ Log.e(TAG,
+ "mTopViewHeight == "+mTopViewHeight
+ +"\ndy == "+dy
+ +"\nscrollY == "+scrollY
+ +"\nhiddenTop && showTop "+temp);
+ if(!temp){
+ // judge
+ temp = dy < 0
+ && (scrollY >= 0)
+ &&
+ (
+ !ViewCompat.canScrollVertically(target, -1)
+ ||
+ firstVisiblePosition==targetFirstVisiblePosition
+ );
+ Log.e(TAG,
+ "mTopViewHeight == "+mTopViewHeight
+ +"\ndy == "+dy
+ +"\nscrollY == "+scrollY
+ +"\nfirstVisiblePosition "+firstVisiblePosition);
+ }
+ if (temp) {
+ scrollBy(0, dy);
+ consumed[1] = dy;
+ }
+ }
+
+ @Override
+ public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
+ Log.e(TAG, "onNestedFling");
+ return false;
+ }
+
+ @Override
+ public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
+ Log.e(TAG, "onNestedPreFling");
+ //down - //up+
+ if (getScrollY() >= mTopViewHeight) return false;
+ fling((int) velocityY);
+ return true;
+ }
+
+ @Override
+ public int getNestedScrollAxes() {
+ Log.e(TAG, "getNestedScrollAxes");
+ return 0;
+ }
+
+ @Deprecated
+ private void initVelocityTrackerIfNotExists() {
+ if (mVelocityTracker == null)
+ mVelocityTracker = VelocityTracker.obtain();
+ }
+
+ // call this when destroy
+ public void destroy() {
+ if (mVelocityTracker != null) {
+ mVelocityTracker.recycle();
+ mVelocityTracker = null;
+ }
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ // 你可以在 xml 文件内配置
+ // you can init those views in your xml file
+
+// mTopView = findViewById(R.id.topContainer);
+// mTabView = findViewById(R.id.tabLayout);
+// mContentView = findViewById(R.id.vp);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ if(mTabView == null || mTopView == null || mContentView == null)
+ return;
+// getChildAt(0).
+// measure(
+// widthMeasureSpec,
+// MeasureSpec.makeMeasureSpec(
+// 0,
+// MeasureSpec.UNSPECIFIED
+// )
+// );
+ setTotalHeight();
+ }
+
+ private void setTotalHeight(){
+ ViewGroup.LayoutParams params = mContentView.getLayoutParams();
+ params.height = getMeasuredHeight() - mTabView.getMeasuredHeight();
+ setMeasuredDimension(
+ getMeasuredWidth(),
+ mTopView.getMeasuredHeight()
+ + mTabView.getMeasuredHeight()
+ + mContentView.getMeasuredHeight()
+ );
+ }
+
+ private void getTopViewHeight(){
+ if(mTopView == null)
+ return;
+ mTopViewHeight = mTopView.getMeasuredHeight();
+ }
+
+ @Override
+ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+ super.onSizeChanged(w, h, oldw, oldh);
+ getTopViewHeight();
+ }
+
+
+ public void fling(int velocityY) {
+ mScroller.fling(0, getScrollY(), 0, velocityY, 0, 0, 0, mTopViewHeight);
+ invalidate();
+ }
+
+ @Override
+ public void scrollTo(int x, int y) {
+ if (y < 0)
+ y = 0;
+
+ if (y > mTopViewHeight)
+ // 边界限制,防止把 tabView 也挡住了
+ // Prevent it from hiding the tabView,so we limit it
+ y = mTopViewHeight;
+
+ if (y != getScrollY())
+ super.scrollTo(x, y);
+ }
+
+ @Override
+ public void computeScroll() {
+ if (mScroller.computeScrollOffset()) {
+ scrollTo(0, mScroller.getCurrY());
+ invalidate();
+ }
+ }
+}
diff --git a/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/XRecyclerView.java b/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/XRecyclerView.java
new file mode 100644
index 0000000..769b573
--- /dev/null
+++ b/xrecyclerview/src/main/java/com/jcodecraeer/xrecyclerview/XRecyclerView.java
@@ -0,0 +1,888 @@
+package com.jcodecraeer.xrecyclerview;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+
+import com.google.android.material.appbar.AppBarLayout;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import androidx.annotation.NonNull;
+import androidx.coordinatorlayout.widget.CoordinatorLayout;
+import androidx.recyclerview.widget.GridLayoutManager;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.recyclerview.widget.StaggeredGridLayoutManager;
+
+import static com.jcodecraeer.xrecyclerview.BaseRefreshHeader.STATE_DONE;
+
+public class XRecyclerView extends RecyclerView {
+ private boolean isLoadingData = false;
+ private boolean isNoMore = false;
+ private int mRefreshProgressStyle = ProgressStyle.SysProgress;
+ private int mLoadingMoreProgressStyle = ProgressStyle.SysProgress;
+ private ArrayList