There is a relatively easy -to -use custom view, which is convenient to use it directly. I remember that it was down on GitHub. I couldn’t find the address, so I passed it directly.
package com.example.orion.htmltext1.View; import android.view.View; /** * Current classes annotation: * Author:jinwenfeng on 2016/12/6 13:48 * mailbox:[email protected] * QQ: 823546371 * Company: Nanjing Muzun Information Technology Co., Ltd. * 2016 jinwenfeng * Copyright, not allowed to spread without permission */ public interface FooterView { /** * Start drop -down */ void begin(); /** * Capital accuracy,unit ispx * * @param progress Current height * @param all Total height is the default height2times */ void progress(float progress, float all); void finishing(float progress, float all); /** * Pulling down */ void loading(); /** * Invisible state */ void normal(); /** * Return to the current view * */ View getView(); }
package com.example.orion.htmltext1.View; import android.content.Context; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.TextView; import com.example.orion.htmltext1.R; /** * At present comments: * Author:jinwenfeng on 2016/12/6 13:49 * mailbox:[email protected] * QQ: 823546371 * Company: Nanjing Muzun Information Technology Co., Ltd. * 2016 jinwenfeng * All rights reserved, not allowed to spread without permission */ public class HeadRefreshView extends FrameLayout implements HeadView { private TextView tv; private ImageView arrow; private ProgressBar progressBar; public HeadRefreshView(Context context) { this(context,null); } public HeadRefreshView(Context context, AttributeSet attrs) { this(context, attrs,0); } public HeadRefreshView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context); } private void init(Context context) { View view = LayoutInflater.from(context).inflate(R.layout.layout_header,null); addView(view); tv = (TextView) view.findViewById(R.id.header_tv); arrow = (ImageView) view.findViewById(R.id.header_arrow); progressBar = (ProgressBar) view.findViewById(R.id.header_progress); } @Override public void begin() { } @Override public void progress(float progress, float all) { float s = progress / all; if (s >= 0.9f){ arrow.setRotation(180); }else{ arrow.setRotation(0); } if (progress >= all-10){ tv.setText("Reconciliation"); }else{ tv.setText("drop -down load"); } } @Override public void finishing(float progress, float all) { } @Override public void loading() { arrow.setVisibility(GONE); progressBar.setVisibility(VISIBLE); tv.setText("refreshing..."); } @Override public void normal() { arrow.setVisibility(VISIBLE); progressBar.setVisibility(GONE); tv.setText("drop -down and refresh"); } @Override public View getView() { return this; } }
package com.example.orion.htmltext1.View; import android.view.View; /** * Current class notes: * Author:jinwenfeng on 2016/12/6 13:48 * mailbox:[email protected] * QQ: 823546371 * Company: Nanjing Muzun Information Technology Co., Ltd. * 2016 jinwenfeng * All rights reserved, not allowed to spread without permission */ public interface HeadView { /** * Start drop -down */ void begin(); /** * precision of callback,unit ispx * * @param progress Current height * @param all Total height */ void progress(float progress, float all); void finishing(float progress, float all); /** * Pulling down */ void loading(); /** * Invisible state */ void normal(); /** * Return to the current view * */ View getView(); }
package com.example.orion.htmltext1.View; import android.content.Context; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.TextView; import com.example.orion.htmltext1.R; /** * Current class notes: * Author:jinwenfeng on 2016/12/8 10:47 * mailbox:[email protected] * QQ: 823546371 * Company: Nanjing Muzun Information Technology Co., Ltd. * 2016 jinwenfeng * All rights reserved, not allowed to spread without permission */ public class LoadMoreView extends FrameLayout implements FooterView { private TextView tv; private ImageView arrow; private ProgressBar progressBar; public LoadMoreView(Context context) { this(context,null); } public LoadMoreView(Context context, AttributeSet attrs) { this(context, attrs,0); } public LoadMoreView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context); } private void init(Context context) { View view = LayoutInflater.from(context).inflate(R.layout.layout_header,null); addView(view); tv = (TextView) view.findViewById(R.id.header_tv); arrow = (ImageView) view.findViewById(R.id.header_arrow); progressBar = (ProgressBar) view.findViewById(R.id.header_progress); } @Override public void begin() { } @Override public void progress(float progress, float all) { float s = progress / all; if (s >= 0.9f){ arrow.setRotation(0); }else{ arrow.setRotation(180); } if (progress >= all-10){ tv.setText("Loose and load more"); }else{ tv.setText("Draw up load"); } } @Override public void finishing(float progress, float all) { } @Override public void loading() { arrow.setVisibility(GONE); progressBar.setVisibility(VISIBLE); tv.setText("loading..."); } @Override public void normal() { arrow.setVisibility(VISIBLE); progressBar.setVisibility(GONE); tv.setText("Draw up load"); } @Override public View getView() { return this; } }
package com.example.orion.htmltext1.View; import android.animation.ValueAnimator; import android.content.Context; import android.content.res.TypedArray; import android.support.v4.view.ViewCompat; import android.util.AttributeSet; import android.view.Gravity; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; import android.view.ViewGroup; import android.widget.FrameLayout; import com.example.orion.htmltext1.R; import com.example.orion.htmltext1.Util.DisplayUtil; import com.example.orion.htmltext1.interfaces.BaseRefreshListener; import com.example.orion.htmltext1.interfaces.State; import com.example.orion.htmltext1.interfaces.ViewStatus; /** * Current class notes: * Author:jinwenfeng on 2016/12/6 11:52 * mailbox:[email protected] * QQ: 823546371 * Company: Nanjing Muzun Information Technology Co., Ltd. * 2016 jinwenfeng * All rights reserved, not allowed to spread without permission */ public class PullToRefreshLayout extends FrameLayout { private HeadView mHeaderView; private FooterView mFooterView; private View mChildView; private static final long ANIM_TIME = 300; private static int HEAD_HEIGHT = 60; private static int FOOT_HEIGHT = 60; private static int head_height; private static int head_height_2; private static int foot_height; private static int foot_height_2; private float mTouchY; private float mCurrentY; private boolean canLoadMore = true; private boolean canRefresh = true; private boolean isRefresh; private boolean isLoadMore; //The minimum distance of sliding private int mTouchSlope; private BaseRefreshListener refreshListener; private View loadingView, errorView, emptyView; private int loading = R.layout.layout_loading, empty = R.layout.layout_empty, error = R.layout.layout_error; public void setRefreshListener(BaseRefreshListener refreshListener) { this.refreshListener = refreshListener; } public PullToRefreshLayout(Context context) { this(context, null); } public PullToRefreshLayout(Context context, AttributeSet attrs) { this(context, attrs, 0); } public PullToRefreshLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PullToRefreshLayout, defStyleAttr, 0); error = a.getResourceId(R.styleable.PullToRefreshLayout_view_error, error); loading = a.getResourceId(R.styleable.PullToRefreshLayout_view_loading, loading); empty = a.getResourceId(R.styleable.PullToRefreshLayout_view_empty, empty); init(); } private void cal() { head_height = DisplayUtil.dp2Px(getContext(), HEAD_HEIGHT); foot_height = DisplayUtil.dp2Px(getContext(), FOOT_HEIGHT); head_height_2 = DisplayUtil.dp2Px(getContext(), HEAD_HEIGHT * 2); foot_height_2 = DisplayUtil.dp2Px(getContext(), FOOT_HEIGHT * 2); mTouchSlope = ViewConfiguration.get(getContext()).getScaledTouchSlop(); } private void init() { cal(); int count = getChildCount(); if (count != 1) { new IllegalArgumentException("child only can be one"); } } @Override protected void onFinishInflate() { super.onFinishInflate(); mChildView = getChildAt(0); addHeadView(); addFooterView(); } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); } private void addHeadView() { if (mHeaderView == null) { mHeaderView = new HeadRefreshView(getContext()); }else{ removeView(mHeaderView.getView()); } LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 0); mHeaderView.getView().setLayoutParams(layoutParams); if (mHeaderView.getView().getParent() != null) ((ViewGroup) mHeaderView.getView().getParent()).removeAllViews(); addView(mHeaderView.getView(), 0); } private void addFooterView() { if (mFooterView == null) { mFooterView = new LoadMoreView(getContext()); }else{ removeView(mFooterView.getView()); } LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 0); layoutParams.gravity = Gravity.BOTTOM; mFooterView.getView().setLayoutParams(layoutParams); if (mFooterView.getView().getParent() != null) ((ViewGroup) mFooterView.getView().getParent()).removeAllViews(); addView(mFooterView.getView()); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { if (!canLoadMore && !canRefresh) return super.onInterceptTouchEvent(ev); //if (isRefresh || isLoadMore) return true; switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: mTouchY = ev.getY(); mCurrentY = mTouchY; break; case MotionEvent.ACTION_MOVE: float currentY = ev.getY(); float dy = currentY - mCurrentY; if (canRefresh) { boolean canChildScrollUp = canChildScrollUp(); if (dy > mTouchSlope && !canChildScrollUp) { mHeaderView.begin(); return true; } } if (canLoadMore) { boolean canChildScrollDown = canChildScrollDown(); if (dy < -mTouchSlope && !canChildScrollDown) { mFooterView.begin(); return true; } } } return super.onInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { if (isRefresh || isLoadMore) return true; switch (event.getAction()) { case MotionEvent.ACTION_MOVE: mCurrentY = event.getY(); float dura = (mCurrentY - mTouchY) / 3.0f; if (dura > 0 && canRefresh) { dura = Math.min(head_height_2, dura); dura = Math.max(0, dura); mHeaderView.getView().getLayoutParams().height = (int) dura; ViewCompat.setTranslationY(mChildView, dura); requestLayout(); mHeaderView.progress(dura, head_height); } else { if (canLoadMore) { dura = Math.min(foot_height_2, Math.abs(dura)); dura = Math.max(0, Math.abs(dura)); mFooterView.getView().getLayoutParams().height = (int) dura; ViewCompat.setTranslationY(mChildView, -dura); requestLayout(); mFooterView.progress(dura, foot_height); } } return true; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: float currentY = event.getY(); final int dy1 = (int) (currentY - mTouchY) / 3; if (dy1 > 0 && canRefresh) { if (dy1 >= head_height) { createAnimatorTranslationY(State.REFRESH, dy1 > head_height_2 ? head_height_2 : dy1, head_height, new CallBack() { @Override public void onSuccess() { isRefresh = true; if (refreshListener != null) { refreshListener.refresh(); } mHeaderView.loading(); } }); } else if (dy1 > 0 && dy1 < head_height) { setFinish(dy1, State.REFRESH); mHeaderView.normal(); } } else { if (canLoadMore) { if (Math.abs(dy1) >= foot_height) { createAnimatorTranslationY(State.LOADMORE, Math.abs(dy1) > foot_height_2 ? foot_height_2 : Math.abs(dy1), foot_height, new CallBack() { @Override public void onSuccess() { isLoadMore = true; if (refreshListener != null) { refreshListener.loadMore(); } mFooterView.loading(); } }); } else { setFinish(Math.abs(dy1), State.LOADMORE); mFooterView.normal(); } } } break; } return super.onTouchEvent(event); } private boolean canChildScrollDown() { if (mChildView == null) { return false; } return ViewCompat.canScrollVertically(mChildView, 1); } private boolean canChildScrollUp() { if (mChildView == null) { return false; } return ViewCompat.canScrollVertically(mChildView, -1); } /** * Create animation */ public void createAnimatorTranslationY(@State.REFRESH_STATE final int state, final int start, final int purpose, final CallBack callBack) { final ValueAnimator anim; anim = ValueAnimator.ofInt(start, purpose); anim.setDuration(ANIM_TIME); anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { int value = (int) valueAnimator.getAnimatedValue(); if (state == State.REFRESH) { mHeaderView.getView().getLayoutParams().height = value; ViewCompat.setTranslationY(mChildView, value); if (purpose == 0) { //represents end loading mHeaderView.finishing(value, head_height_2); } else { mHeaderView.progress(value, head_height); } } else { mFooterView.getView().getLayoutParams().height = value; ViewCompat.setTranslationY(mChildView, -value); if (purpose == 0) { //Representative end load mFooterView.finishing(value, head_height_2); } else { mFooterView.progress(value, foot_height); } } if (value == purpose) { if (callBack != null) callBack.onSuccess(); } requestLayout(); } }); anim.start(); } /** * End downward drawing refresh */ private void setFinish(int height, @State.REFRESH_STATE final int state) { createAnimatorTranslationY(state, height, 0, new CallBack() { @Override public void onSuccess() { if (state == State.REFRESH) { isRefresh = false; mHeaderView.normal(); } else { isLoadMore = false; mFooterView.normal(); } } }); } private void setFinish(@State.REFRESH_STATE int state) { if (state == State.REFRESH) { if (mHeaderView != null && mHeaderView.getView().getLayoutParams().height > 0 && isRefresh) { setFinish(head_height, state); } } else { if (mFooterView != null && mFooterView.getView().getLayoutParams().height > 0 && isLoadMore) { setFinish(foot_height, state); } } } public interface CallBack { void onSuccess(); } private void showLoadingView() { if (loadingView == null) { loadingView = LayoutInflater.from(getContext()).inflate(loading, null); LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); addView(loadingView, layoutParams); } else { loadingView.setVisibility(VISIBLE); } } private void showEmptyView() { if (emptyView == null) { emptyView = LayoutInflater.from(getContext()).inflate(empty, null); LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); addView(emptyView, layoutParams); } else { emptyView.setVisibility(VISIBLE); } } private void showErrorView() { if (errorView == null) { errorView = LayoutInflater.from(getContext()).inflate(error, null); LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); addView(errorView, layoutParams); } else { errorView.setVisibility(VISIBLE); } } private void hideView(View view) { if (view != null) view.setVisibility(GONE); } private void switchView(int status) { switch (status) { case ViewStatus.CONTENT_STATUS: hideView(loadingView); hideView(emptyView); hideView(errorView); mChildView.setVisibility(VISIBLE); break; case ViewStatus.LOADING_STATUS: hideView(mChildView); hideView(emptyView); hideView(errorView); showLoadingView(); break; case ViewStatus.EMPTY_STATUS: hideView(mChildView); hideView(loadingView); hideView(errorView); showEmptyView(); break; case ViewStatus.ERROR_STATUS: hideView(mChildView); hideView(loadingView); hideView(emptyView); showErrorView(); break; default: hideView(loadingView); hideView(emptyView); hideView(errorView); mChildView.setVisibility(VISIBLE); break; } } /** * Settings displayview (error,empty,loading) * */ public void showView(@ViewStatus.VIEW_STATUS int status) { switchView(status); } /** * Getview (error,empty,loading) * */ public View getView(@ViewStatus.VIEW_STATUS int status) { switch (status) { case ViewStatus.EMPTY_STATUS: return emptyView; case ViewStatus.LOADING_STATUS: return loadingView; case ViewStatus.ERROR_STATUS: return errorView; case ViewStatus.CONTENT_STATUS: return mChildView; } return null; } public void autoRefresh(){ createAnimatorTranslationY(State.REFRESH, 0, head_height, new CallBack() { @Override public void onSuccess() { isRefresh = true; if (refreshListener != null) { refreshListener.refresh(); } mHeaderView.loading(); } }); } /** * End refresh */ public void finishRefresh() { setFinish(State.REFRESH); } /** * End load more */ public void finishLoadMore() { setFinish(State.LOADMORE); } /** * Settings Whether to enable and load more */ public void setCanLoadMore(boolean canLoadMore) { this.canLoadMore = canLoadMore; } /** * Set whether to enable drop -down and refresh */ public void setCanRefresh(boolean canRefresh) { this.canRefresh = canRefresh; } /** * Settings are drop -down and refresh the head * * @param mHeaderView need to be realizedHeadView interface */ public void setHeaderView(HeadView mHeaderView) { this.mHeaderView = mHeaderView; addHeadView(); } /** * Settings are pulling down and refreshing tail * * @param mFooterView need to be achievedFooterView interface */ public void setFooterView(FooterView mFooterView) { this.mFooterView = mFooterView; addFooterView(); } /** * Set the height of the refresh control * * @param dp unit isdp */ public void setHeadHeight(int dp) { head_height = DisplayUtil.dp2Px(getContext(), dp); } /** * Set the height of more controls * * @param dp unit isdp */ public void setFootHeight(int dp) { foot_height = DisplayUtil.dp2Px(getContext(), dp); } /** * At the same time, set more controls and refresh control heights at the same time * * @param dp unit isdp */ public void setAllHeight(int dp) { head_height = DisplayUtil.dp2Px(getContext(), dp); foot_height = DisplayUtil.dp2Px(getContext(), dp); } /** * At the same time, set more controls and refresh control heights at the same time * * @param refresh The height unit of the control of the control isdp * @param loadMore The height unit of loading control isdp */ public void setAllHeight(int refresh, int loadMore) { head_height = DisplayUtil.dp2Px(getContext(), refresh); foot_height = DisplayUtil.dp2Px(getContext(), loadMore); } /** * Set the maximum height of the drop -down control and the best height of its own control is2times * * @param dp unit isdp */ public void setMaxHeadHeight(int dp) { if (head_height >= DisplayUtil.dp2Px(getContext(), dp)) { return; } head_height_2 = DisplayUtil.dp2Px(getContext(), dp); } /** * Set the maximum height of loading more controls and the best height of its own control.2times * * @param dp unit isdp */ public void setMaxFootHeight(int dp) { if (foot_height >= DisplayUtil.dp2Px(getContext(), dp)) { return; } foot_height_2 = DisplayUtil.dp2Px(getContext(), dp); } /** * At the same time, set more control and refresh control to the maximum height, and must be greater than the height of its own control.2times * * @param dp unit isdp */ public void setAllMaxHeight(int dp) { if (head_height >= DisplayUtil.dp2Px(getContext(), dp)) { return; } if (foot_height >= DisplayUtil.dp2Px(getContext(), dp)) { return; } head_height_2 = DisplayUtil.dp2Px(getContext(), dp); foot_height_2 = DisplayUtil.dp2Px(getContext(), dp); } /** * At the same time, set more control and refresh control to the maximum height, and must be greater than the height of its own control.2times The maximum unit of the * * @param refresh refresh control drops isdp * @param loadMore The largest height unit pulled on the control control isdp */ public void setAllMaxHeight(int refresh, int loadMore) { if (head_height >= DisplayUtil.dp2Px(getContext(), refresh)) { return; } if (foot_height >= DisplayUtil.dp2Px(getContext(), loadMore)) { return; } head_height_2 = DisplayUtil.dp2Px(getContext(), refresh); foot_height_2 = DisplayUtil.dp2Px(getContext(), loadMore); } }