package jsc.kit.adapter.refresh; import android.animation.Animator; import android.animation.ObjectAnimator; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Rect; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.widget.SwipeRefreshLayout; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.StaggeredGridLayoutManager; import android.util.AttributeSet; import android.util.Log; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; import android.widget.ImageView; import jsc.kit.adapter.R; import jsc.kit.adapter.SimpleAnimatorListener; /** * <br>Email:[email protected] * <br>QQ:1006368252 * create time: 2018/12/23 15:51 * * @author jsc */ public class SwipeRefreshRecyclerView extends FrameLayout { public static final String TAG = "SwipeRefresh"; public static final int DEFAULT_START_PAGE_NUMBER = 1; public static final int DEFAULT_PAGE_SIZE = 12; private SwipeRefreshLayout swipeRefreshLayout; private RecyclerView recyclerView; private View loadMoreView; private int startPageNumber = DEFAULT_START_PAGE_NUMBER; private int currentPageNumber = startPageNumber; private int pageSize = DEFAULT_PAGE_SIZE; private boolean isLoading = false; private boolean hasMorePage = false; private boolean refreshEnable = true; private boolean loadMoreEnable = true; private Rect visibleRect = new Rect(); private OnRefreshListener onRefreshListener = null; private int translationDistance = 0; private Animator defaultLoadingAnimator = null; private Animator defaultLoadedAnimator = null; private RecyclerView.OnScrollListener scrollListener = new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); if (newState != RecyclerView.SCROLL_STATE_IDLE) return; RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager(); RecyclerView.Adapter adapter = recyclerView.getAdapter(); if (layoutManager == null || adapter == null) { // swipeRefreshLayout.setEnabled(false); return; } if (isLoading() || !isLoadMoreEnable() || !isHasMorePage() || !isScrollToBottom()) return; //如果第一条和最后一条同时可见 if (swipeRefreshLayout.isEnabled()) { //如果SwipeRefreshLayout中的CircleImageView可见,则走刷新逻辑 if (isCircleImageViewVisible()) { return; } } Log.i(TAG, "onScrollStateChanged: "); if (onRefreshListener != null) { showScrollUpAnim(); } } @Override public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); } }; public SwipeRefreshRecyclerView(Context context) { super(context); initView(context); initAttrs(context, null, 0); } public SwipeRefreshRecyclerView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); initView(context); initAttrs(context, attrs, 0); } public SwipeRefreshRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initView(context); initAttrs(context, attrs, defStyleAttr); } private void initView(Context context) { inflate(context, R.layout.recycler_default_swipe_refresh_recycler_view_layout, this); swipeRefreshLayout = findViewById(R.id.swipe_refresh_layout); recyclerView = findViewById(R.id.recycler_view); swipeRefreshLayout.setColorSchemeColors(0xFF3F51B5, 0xFF303F9F); swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { setLoading(true); currentPageNumber = startPageNumber; onRefreshListener.onRefresh(currentPageNumber, pageSize); } }); recyclerView.addOnScrollListener(scrollListener); } private void initAttrs(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SwipeRefreshRecyclerView, defStyleAttr, 0); int layoutId = a.getResourceId(R.styleable.SwipeRefreshRecyclerView_srrvLoadMoreLayout, R.layout.recycler_default_load_more_layout); a.recycle(); if (loadMoreView != null) { removeView(loadMoreView); loadMoreView = null; } if (layoutId != -1) { LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); params.gravity = Gravity.BOTTOM; loadMoreView = LayoutInflater.from(context).inflate(layoutId, this, false); addView(loadMoreView, params); } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); translationDistance = loadMoreView.getMeasuredHeight(); loadMoreView.setTranslationY(translationDistance); } private boolean isCircleImageViewVisible() { for (int i = 0; i < swipeRefreshLayout.getChildCount(); i++) { View child = swipeRefreshLayout.getChildAt(i); if (child instanceof ImageView) { child.getLocalVisibleRect(visibleRect); if (visibleRect.bottom > 0) return true; } } return false; } public void reset() { setHasMorePage(false); setLoading(false); if (defaultLoadingAnimator != null && defaultLoadingAnimator.isRunning()) defaultLoadingAnimator.cancel(); if (defaultLoadedAnimator != null && defaultLoadedAnimator.isRunning()) defaultLoadedAnimator.cancel(); loadMoreView.setTranslationY(translationDistance); } private void showScrollUpAnim() { if (isLoading()) return; setLoading(true); swipeRefreshLayout.setEnabled(false); if (defaultLoadingAnimator == null) defaultLoadingAnimator = createDefaultLoadingAnimator(); defaultLoadingAnimator.start(); } private void showScrollDownAnim() { if (defaultLoadedAnimator == null) defaultLoadedAnimator = createDefaultLoadedAnimator(); defaultLoadedAnimator.start(); } /** * Whether scrolled to the bottom of list. * @return true, scrolled to the bottom of list, else false. */ private boolean isScrollToBottom() { return recyclerView.computeVerticalScrollRange() <= recyclerView.computeVerticalScrollOffset() + recyclerView.computeVerticalScrollExtent(); } public SwipeRefreshLayout getSwipeRefreshLayout() { return swipeRefreshLayout; } public RecyclerView getRecyclerView() { return recyclerView; } public View getLoadMoreView() { return loadMoreView; } public void setOnRefreshListener(OnRefreshListener onRefreshListener) { this.onRefreshListener = onRefreshListener; } public void loadComplete() { if (currentPageNumber == startPageNumber) refreshComplete(); else loadMoreComplete(); } public void refreshComplete() { isLoading = false; swipeRefreshLayout.setRefreshing(false); } public void loadMoreComplete() { showScrollDownAnim(); } public void refresh() { if (isLoading()) return; refreshDelay(0); } public void refreshDelay(long delay) { if (isLoading()) return; swipeRefreshLayout.setRefreshing(true); if (delay <= 0) { startRefreshing(); return; } postDelayed(new Runnable() { @Override public void run() { startRefreshing(); } }, delay); } private void startRefreshing() { isLoading = true; if (onRefreshListener != null) { currentPageNumber = startPageNumber; onRefreshListener.onRefresh(currentPageNumber, pageSize); } } public boolean isLoading() { return isLoading; } public void setLoading(boolean loading) { isLoading = loading; } public boolean isRefreshEnable() { return refreshEnable; } public void setRefreshEnable(boolean refreshEnable) { this.refreshEnable = refreshEnable; swipeRefreshLayout.setEnabled(refreshEnable); } public boolean isLoadMoreEnable() { return loadMoreEnable; } public void setLoadMoreEnable(boolean loadMoreEnable) { this.loadMoreEnable = loadMoreEnable; } public boolean isHasMorePage() { return hasMorePage; } public void setHasMorePage(boolean hasMorePage) { this.hasMorePage = hasMorePage; } public boolean isFirstPage() { return currentPageNumber == startPageNumber; } public int getStartPageNumber() { return startPageNumber; } public void setStartPageNumber(int startPageNumber) { this.startPageNumber = startPageNumber; } public int getCurrentPageNumber() { return currentPageNumber; } public int getPageSize() { return pageSize; } public void setPageSize(int pageSize) { this.pageSize = pageSize; } private Animator createDefaultLoadingAnimator() { ObjectAnimator animator = ObjectAnimator.ofFloat(loadMoreView, TRANSLATION_Y, loadMoreView.getTranslationY(), 0); animator.setDuration(300); animator.addListener(new SimpleAnimatorListener() { @Override public void onAnimationEnd(Animator animation) { if (onRefreshListener != null) { currentPageNumber++; onRefreshListener.onLoadMore(currentPageNumber, pageSize); } } }); return animator; } private Animator createDefaultLoadedAnimator() { ObjectAnimator animator = ObjectAnimator.ofFloat(loadMoreView, TRANSLATION_Y, loadMoreView.getTranslationY(), translationDistance); animator.setDuration(300); animator.addListener(new SimpleAnimatorListener() { @Override public void onAnimationEnd(Animator animation) { setLoading(false); swipeRefreshLayout.setEnabled(true ); } }); return animator; } @Override protected void onDetachedFromWindow() { getHandler().removeCallbacksAndMessages(null); reset(); super.onDetachedFromWindow(); } public interface OnRefreshListener { /** * Do refreshing. */ void onRefresh(int currentPageNumber, int pageSize); /** * Do loading more. */ void onLoadMore(int currentPageNumber, int pageSize); } }