package com.lzx.demo.view; import android.content.Context; import android.support.design.widget.AppBarLayout; import android.support.design.widget.CoordinatorLayout; import android.support.v4.content.ContextCompat; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.ViewParent; import android.widget.LinearLayout; import android.widget.ScrollView; import com.github.jdsjlzx.interfaces.IRefreshHeader; import com.github.jdsjlzx.recyclerview.AppBarStateChangeListener; import com.github.jdsjlzx.view.ArrowRefreshHeader; /** * 自定义下拉刷新ScrollView * <p/> */ public class PullScrollView extends ScrollView { private RefreshListener mRefreshListener; private IRefreshHeader mRefreshHeader; private boolean isRefreshEnabled = true; //设置下拉刷新是否可用 private float dragRate = 2; //下拉刷新滑动阻力系数,越大需要手指下拉的距离越大才能刷新 private boolean isRefreshing; //是否正在刷新 private float mLastY = -1; //上次触摸的的Y值 private int topY; private float sumOffSet; private boolean isAdded; private AppBarStateChangeListener.State appbarState = AppBarStateChangeListener.State.EXPANDED; public PullScrollView(Context context) { this(context, null); } public PullScrollView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public PullScrollView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } private void init() { if (isRefreshEnabled) { mRefreshHeader = new ArrowRefreshHeader(getContext()); } } private void setLayout() { if (!isAdded) { isAdded = true; ViewGroup group = (ViewGroup) getParent(); LinearLayout container = new LinearLayout(getContext()); container.setOrientation(LinearLayout.VERTICAL); int index = group.indexOfChild(this); group.removeView(this); group.addView(container, index, getLayoutParams()); container.addView(mRefreshHeader.getHeaderView(), new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); container.addView(this, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); } } public View getRefreshHeaderView() { return mRefreshHeader.getHeaderView(); } /** * 设置下拉刷新上拉加载回调 */ public void setRefreshListener(RefreshListener listener) { mRefreshListener = listener; } /** * 设置自定义的header */ public void setRefreshHeader(IRefreshHeader mRefreshHeader) { this.mRefreshHeader = mRefreshHeader; } /** * 下拉刷新是否可用 */ public void setPullRefreshEnabled(boolean enabled) { isRefreshEnabled = enabled; } /** * 下拉刷新滑动阻力系数,越大需要手指下拉的距离越大才能刷新 */ public void setDragRate(int dragRate) { this.dragRate = dragRate; } /** * 设置下拉刷新的进度条风格 */ public void setRefreshProgressStyle(int style) { if (mRefreshHeader != null && mRefreshHeader instanceof ArrowRefreshHeader) { ((ArrowRefreshHeader) mRefreshHeader).setProgressStyle(style); } } /** * 设置下拉刷新的箭头图标 */ public void setArrowImageView(int resId) { if (mRefreshHeader != null && mRefreshHeader instanceof ArrowRefreshHeader) { ((ArrowRefreshHeader) mRefreshHeader).setArrowImageView(resId); } } /** * 设置颜色 * @param indicatorColor Only call the method setRefreshProgressStyle(int style) to take effect * @param hintColor * @param backgroundColor */ public void setHeaderViewColor(int indicatorColor, int hintColor, int backgroundColor) { if (mRefreshHeader != null && mRefreshHeader instanceof ArrowRefreshHeader) { ArrowRefreshHeader arrowRefreshHeader = ((ArrowRefreshHeader) mRefreshHeader); arrowRefreshHeader.setIndicatorColor(ContextCompat.getColor(getContext(),indicatorColor)); arrowRefreshHeader.setHintTextColor(hintColor); arrowRefreshHeader.setViewBackgroundColor(backgroundColor); } } /** * 手动调用直接刷新,无下拉效果 */ public void refresh() { if (mRefreshListener != null) { isRefreshing = true; mRefreshListener.onRefresh(); } } /** * 手动调用下拉刷新,有下拉效果 */ public void refreshWithPull() { setRefreshing(true); refresh(); } /** * 下拉刷新和到底加载完成 */ public void setRefreshCompleted() { if (isRefreshing) { isRefreshing = false; mRefreshHeader.refreshComplete(); } } /** * 手动调用加载状态,此函数不会调用 {@link RefreshListener#onRefresh()}加载数据 * 如果需要加载数据和状态显示调用 {@link #refreshWithPull()} */ public void setRefreshing(final boolean refreshing) { if (refreshing && isRefreshEnabled) { isRefreshing = true; mRefreshHeader.onRefreshing(); int offSet = mRefreshHeader.getHeaderView() .getMeasuredHeight(); mRefreshHeader.onMove(offSet, offSet); } } @Override public boolean onTouchEvent(MotionEvent ev) { if (mLastY == -1) { mLastY = ev.getRawY(); } switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: mLastY = ev.getRawY(); sumOffSet = 0; break; case MotionEvent.ACTION_MOVE: final float deltaY = (ev.getRawY() - mLastY) / dragRate; mLastY = ev.getRawY(); sumOffSet += deltaY; if (isOnTop() && isRefreshEnabled && appbarState == AppBarStateChangeListener.State.EXPANDED) { mRefreshHeader.onMove(deltaY, sumOffSet); if (mRefreshHeader.getVisibleHeight() > 0 && !isRefreshing) { return false; } } break; default: mLastY = -1; // reset if (isOnTop() && isRefreshEnabled && appbarState == AppBarStateChangeListener.State.EXPANDED) { if (mRefreshHeader.onRelease()) { if (mRefreshListener != null) { isRefreshing = true; mRefreshListener.onRefresh(); } } } break; } return super.onTouchEvent(ev); } @Override protected void onScrollChanged(int l, int t, int oldl, int oldt) { super.onScrollChanged(l, t, oldl, oldt); topY = t; } /** * 如果在HeaderView已经被添加到布局中,说明已经到顶部 */ private boolean isOnTop() { return topY == 0; } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); //解决和AppBarLayout冲突的问题 ViewParent p = getParent(); while (p != null) { if (p instanceof CoordinatorLayout) { break; } p = p.getParent(); } if (p != null) { AppBarLayout appBarLayout = null; CoordinatorLayout coordinatorLayout = (CoordinatorLayout) p; final int childCount = coordinatorLayout.getChildCount(); for (int i = childCount - 1; i >= 0; i--) { final View child = coordinatorLayout.getChildAt(i); if (child instanceof AppBarLayout) { appBarLayout = (AppBarLayout) child; break; } } if (appBarLayout != null) { appBarLayout.addOnOffsetChangedListener(new AppBarStateChangeListener() { @Override public void onStateChanged(AppBarLayout appBarLayout, State state) { appbarState = state; } }); } } setLayout(); } public interface RefreshListener { void onRefresh(); } }