有一个比较好用的这个自定义view,方便以后直接使用,我记得是在GitHub上down下来的,我找不到地址了,所以直接粘贴,原作者发现告诉我地址,我注明
package com.example.orion.htmltext1.View; import android.view.View; /** * 当前类注释: * 作者:jinwenfeng on 2016/12/6 13:48 * 邮箱:[email protected] * QQ: 823546371 * 公司:南京穆尊信息科技有限公司 * © 2016 jinwenfeng * © 版权所有,未经允许不得传播 */ public interface FooterView { /** * 开始下拉 */ void begin(); /** * 回调的精度,单位为px * * @param progress 当前高度 * @param all 总高度 为默认高度的2倍 */ void progress(float progress, float all); void finishing(float progress, float all); /** * 下拉完毕 */ void loading(); /** * 看不见的状态 */ void normal(); /** * 返回当前视图 * */ 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; /** * 当前类注释: * 作者:jinwenfeng on 2016/12/6 13:49 * 邮箱:[email protected] * QQ: 823546371 * 公司:南京穆尊信息科技有限公司 * © 2016 jinwenfeng * © 版权所有,未经允许不得传播 */ 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("松开刷新"); }else{ tv.setText("下拉加载"); } } @Override public void finishing(float progress, float all) { } @Override public void loading() { arrow.setVisibility(GONE); progressBar.setVisibility(VISIBLE); tv.setText("刷新中..."); } @Override public void normal() { arrow.setVisibility(VISIBLE); progressBar.setVisibility(GONE); tv.setText("下拉刷新"); } @Override public View getView() { return this; } }
package com.example.orion.htmltext1.View; import android.view.View; /** * 当前类注释: * 作者:jinwenfeng on 2016/12/6 13:48 * 邮箱:[email protected] * QQ: 823546371 * 公司:南京穆尊信息科技有限公司 * © 2016 jinwenfeng * © 版权所有,未经允许不得传播 */ public interface HeadView { /** * 开始下拉 */ void begin(); /** * 回调的精度,单位为px * * @param progress 当前高度 * @param all 总高度 */ void progress(float progress, float all); void finishing(float progress, float all); /** * 下拉完毕 */ void loading(); /** * 看不见的状态 */ void normal(); /** * 返回当前视图 * */ 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; /** * 当前类注释: * 作者:jinwenfeng on 2016/12/8 10:47 * 邮箱:[email protected] * QQ: 823546371 * 公司:南京穆尊信息科技有限公司 * © 2016 jinwenfeng * © 版权所有,未经允许不得传播 */ 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("松开加载更多"); }else{ tv.setText("上拉加载"); } } @Override public void finishing(float progress, float all) { } @Override public void loading() { arrow.setVisibility(GONE); progressBar.setVisibility(VISIBLE); tv.setText("加载中..."); } @Override public void normal() { arrow.setVisibility(VISIBLE); progressBar.setVisibility(GONE); tv.setText("上拉加载"); } @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; /** * 当前类注释: * 作者:jinwenfeng on 2016/12/6 11:52 * 邮箱:[email protected] * QQ: 823546371 * 公司:南京穆尊信息科技有限公司 * © 2016 jinwenfeng * © 版权所有,未经允许不得传播 */ 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; //滑动的最小距离 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); } /** * 创建动画 */ 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) { //代表结束加载 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) { //代表结束加载 mFooterView.finishing(value, head_height_2); } else { mFooterView.progress(value, foot_height); } } if (value == purpose) { if (callBack != null) callBack.onSuccess(); } requestLayout(); } }); anim.start(); } /** * 结束下拉刷新 */ 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; } } /** * 设置展示view (error,empty,loading) * */ public void showView(@ViewStatus.VIEW_STATUS int status) { switchView(status); } /** * 获取view (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(); } }); } /** * 结束刷新 */ public void finishRefresh() { setFinish(State.REFRESH); } /** * 结束加载更多 */ public void finishLoadMore() { setFinish(State.LOADMORE); } /** * 设置是否启用加载更多 */ public void setCanLoadMore(boolean canLoadMore) { this.canLoadMore = canLoadMore; } /** * 设置是否启用下拉刷新 */ public void setCanRefresh(boolean canRefresh) { this.canRefresh = canRefresh; } /** * 设置是下拉刷新头部 * * @param mHeaderView 需实现 HeadView 接口 */ public void setHeaderView(HeadView mHeaderView) { this.mHeaderView = mHeaderView; addHeadView(); } /** * 设置是下拉刷新尾部 * * @param mFooterView 需实现 FooterView 接口 */ public void setFooterView(FooterView mFooterView) { this.mFooterView = mFooterView; addFooterView(); } /** * 设置刷新控件的高度 * * @param dp 单位为dp */ public void setHeadHeight(int dp) { head_height = DisplayUtil.dp2Px(getContext(), dp); } /** * 设置加载更多控件的高度 * * @param dp 单位为dp */ public void setFootHeight(int dp) { foot_height = DisplayUtil.dp2Px(getContext(), dp); } /** * 同时设置加载更多控件和刷新控件的高度 * * @param dp 单位为dp */ public void setAllHeight(int dp) { head_height = DisplayUtil.dp2Px(getContext(), dp); foot_height = DisplayUtil.dp2Px(getContext(), dp); } /** * 同时设置加载更多控件和刷新控件的高度 * * @param refresh 刷新控件的高度 单位为dp * @param loadMore 加载控件的高度 单位为dp */ public void setAllHeight(int refresh, int loadMore) { head_height = DisplayUtil.dp2Px(getContext(), refresh); foot_height = DisplayUtil.dp2Px(getContext(), loadMore); } /** * 设置刷新控件的下拉的最大高度 且必须大于本身控件的高度 最佳为2倍 * * @param dp 单位为dp */ public void setMaxHeadHeight(int dp) { if (head_height >= DisplayUtil.dp2Px(getContext(), dp)) { return; } head_height_2 = DisplayUtil.dp2Px(getContext(), dp); } /** * 设置加载更多控件的上拉的最大高度 且必须大于本身控件的高度 最佳为2倍 * * @param dp 单位为dp */ public void setMaxFootHeight(int dp) { if (foot_height >= DisplayUtil.dp2Px(getContext(), dp)) { return; } foot_height_2 = DisplayUtil.dp2Px(getContext(), dp); } /** * 同时设置加载更多控件和刷新控件的最大高度 且必须大于本身控件的高度 最佳为2倍 * * @param dp 单位为dp */ 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); } /** * 同时设置加载更多控件和刷新控件的最大高度 且必须大于本身控件的高度 最佳为2倍 * * @param refresh 刷新控件下拉的最大高度 单位为dp * @param loadMore 加载控件上拉的最大高度 单位为dp */ 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); } }