实现ListView的下拉刷新功能

xiaoxiao2021-02-28  109

1.实现原理

在ListView的顶部添加一个header布局,在下拉过程中,然后重新onTouchEvent(),根据滑动过程中y轴的变化,改变header布局的状态,包括hender的提示音和箭头方向。

2.实现步骤

1)创建header布局文件 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <LinearLayout android:id="@+id/layout" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" android:layout_centerInParent="true" android:gravity="center"> <TextView android:id="@+id/tv_tip" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="下拉可以刷新"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/tv_lastupdatetime"/> </LinearLayout> <ImageView android:id="@+id/arrow" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toLeftOf="@+id/layout" android:layout_marginRight="20dp" android:src="@drawable/pull_to_refresh_arrow" /> <ProgressBar android:id="@+id/progress" android:layout_width="wrap_content" android:layout_height="wrap_content" style="?android:attr/progressBarStyleSmall" android:layout_toLeftOf="@+id/layout" android:layout_marginRight="20dp" android:visibility="gone"/> </RelativeLayout> </LinearLayout> 2)自定义ListView public class RefreshListView extends ListView implements AbsListView.OnScrollListener{ private static final String TAG = "RefreshListView"; private int headerHeight;//顶部布局文件的高度 //顶部的各种状态 private final static int RELEASE_TO_REFRESH = 0;//松开刷新 private final static int PULL_TO_REFRESH = 1;//下拉刷新 private final static int REFRESHING = 2;//正在刷新 private final static int DONE = 3;//刷新完成 private final static int LOADING = 4;//正在加载 // private final static int RATIO = 3; //实际的padding的距离与界面上偏移距离的比例 //头部布局文件的控件 private LinearLayout headView; private TextView tipsTextview; private TextView lastUpdatedTextView; private ImageView arrowImageView; private ProgressBar progressBar; //箭头旋转动画 private RotateAnimation animation; private RotateAnimation reverseAnimation; //用于保证startY的值在一个完整的touch事件中只被记录一次 private boolean isRecored; private int firstItemIndex; //记录初始的Y坐标 private int startY; //记录当前的状态 private int state; private boolean isRefreshable; private boolean isBack; private onRefreshListener refreshListener; public RefreshListView(Context context) { super(context); initView(context); } public RefreshListView(Context context, AttributeSet attrs) { super(context, attrs); initView(context); } public RefreshListView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initView(context); } private void initView(Context context){ LayoutInflater inflater = LayoutInflater.from(context); headView = (LinearLayout) inflater.inflate(R.layout.header_layout, null); measureView(headView); headerHeight = headView.getMeasuredHeight(); //隐藏顶部布局文件 headView.setPadding(headView.getPaddingLeft(), -headerHeight, headView.getPaddingRight(), headView.getPaddingBottom()); headView.invalidate(); this.addHeaderView(headView); arrowImageView = (ImageView) headView.findViewById(R.id.arrow); arrowImageView.setMinimumWidth(50); arrowImageView.setMinimumHeight(70); progressBar = (ProgressBar) headView.findViewById(R.id.progress); tipsTextview = (TextView) headView.findViewById(R.id.tv_tip); lastUpdatedTextView = (TextView) headView.findViewById(R.id.tv_lastupdatetime); animation = new RotateAnimation(0, -180, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f); animation.setInterpolator(new LinearInterpolator()); animation.setDuration(250); animation.setFillAfter(true); reverseAnimation = new RotateAnimation(-180, 0, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f); animation.setDuration(200); animation.setFillAfter(true); state = DONE; isRefreshable = false; } /** * 通知父布局,View占用的宽高 * @param view */ private void measureView(View view) { ViewGroup.LayoutParams p = view.getLayoutParams(); if (p == null){ p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); } int width = ViewGroup.getChildMeasureSpec(0, 0, p.width); int height; int tempHeight = p.height; if (tempHeight > 0) { height = MeasureSpec.makeMeasureSpec(tempHeight, MeasureSpec.EXACTLY); } else { height = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); } view.measure(width, height); } @Override public void onScrollStateChanged(AbsListView view, int scrollState) { } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { firstItemIndex = firstVisibleItem; } @Override public boolean onTouchEvent(MotionEvent ev) { if (isRefreshable) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: if (firstItemIndex == 0 && !isRecored) { isRecored = true; startY = (int) ev.getY(); Log.i(TAG, "在down时候记录当前位置"); } break; case MotionEvent.ACTION_UP: Log.i(TAG, "down时候记录当前位置"); if (state != REFRESHING && state != LOADING) { if (state == DONE) { } if (state == PULL_TO_REFRESH) { state = DONE; changeHeaderViewByState(); Log.i(TAG, "有下拉刷新状态,到done状态"); } if (state == RELEASE_TO_REFRESH) { state = REFRESHING; changeHeaderViewByState(); onRefresh(); Log.i(TAG, "由松开刷新状态,到done状态"); } } isRecored = false; isBack = false; break; case MotionEvent.ACTION_MOVE: int tempY = (int) ev.getY(); if (!isRecored && firstItemIndex == 0) { Log.i(TAG, "在move时候记录下位置"); isRecored = true; startY = tempY; } if (state != REFRESHING && isRecored && state != LOADING) { //保证在设置padding的过程中,当前的位置一直在head if (state == RELEASE_TO_REFRESH) { setSelection(0); //下拉到当前状态后又往上推了,推到了屏幕足够掩盖head的程度 if ((tempY - startY) / RATIO < headerHeight && (tempY - startY) > 0) { state = PULL_TO_REFRESH; changeHeaderViewByState(); Log.i(TAG, "松开刷新转为下拉刷新"); } else if (tempY - startY <= 0) { state = DONE; changeHeaderViewByState(); Log.i(TAG, "松开刷新转为done"); } } if (state == DONE) { if (tempY - startY > 0) { state = PULL_TO_REFRESH; changeHeaderViewByState(); } } if (state == PULL_TO_REFRESH) { setSelection(0); if ((tempY - startY) / RATIO >= headerHeight) { state = RELEASE_TO_REFRESH; isBack = true; changeHeaderViewByState(); Log.i(TAG, "有下拉刷新转为松开刷新"); } } //更新headView的size if (state == PULL_TO_REFRESH) { headView.setPadding(0, -1 * headerHeight + (tempY - startY) / RATIO, 0, 0); } // 更新headView的paddingTop if (state == RELEASE_TO_REFRESH) { headView.setPadding(0, (tempY - startY) / RATIO - headerHeight, 0, 0); } } break; } } return super.onTouchEvent(ev); } // 当状态改变时候,调用该方法,以更新界面 private void changeHeaderViewByState() { switch (state) { case RELEASE_TO_REFRESH: arrowImageView.setVisibility(View.VISIBLE); progressBar.setVisibility(View.GONE); tipsTextview.setVisibility(View.VISIBLE); lastUpdatedTextView.setVisibility(View.VISIBLE); arrowImageView.clearAnimation(); arrowImageView.startAnimation(animation); tipsTextview.setText("放开以刷新"); Log.v(TAG, "当前状态,松开刷新"); break; case PULL_TO_REFRESH: progressBar.setVisibility(View.GONE); tipsTextview.setVisibility(View.VISIBLE); lastUpdatedTextView.setVisibility(View.VISIBLE); arrowImageView.clearAnimation(); arrowImageView.setVisibility(View.VISIBLE); // 是由RELEASE_To_REFRESH状态转变来的 if (isBack) { isBack = false; arrowImageView.clearAnimation(); arrowImageView.startAnimation(reverseAnimation); tipsTextview.setText("下拉刷新"); } else { tipsTextview.setText("下拉刷新"); } Log.v(TAG, "当前状态,下拉刷新"); break; case REFRESHING: headView.setPadding(0, 0, 0, 0); progressBar.setVisibility(View.VISIBLE); arrowImageView.clearAnimation(); arrowImageView.setVisibility(View.GONE); tipsTextview.setText("正在刷新..."); lastUpdatedTextView.setVisibility(View.VISIBLE); Log.v(TAG, "当前状态,正在刷新..."); break; case DONE: headView.setPadding(0, -1 * headerHeight, 0, 0); progressBar.setVisibility(View.GONE); arrowImageView.clearAnimation(); arrowImageView.setImageResource(R.drawable.pull_to_refresh_arrow); tipsTextview.setText("下拉刷新"); lastUpdatedTextView.setVisibility(View.VISIBLE); Log.v(TAG, "当前状态,done"); break; } } public interface onRefreshListener { public void onRefresh(); } public void setonRefreshListener(onRefreshListener onRefreshListener) { this.refreshListener = onRefreshListener; isRefreshable = true; } private void onRefresh() { if (refreshListener != null) { refreshListener.onRefresh(); } } public void onRefreshComplete() { state = DONE; lastUpdatedTextView.setText("最近更新:" + new Date().toLocaleString()); changeHeaderViewByState(); } } 3)实现接口 @Override public void onRefresh() { new AsyncTask<Void, Void, Void>() { @Override protected Void doInBackground(Void... params) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } setReflashData(); return null; } @Override protected void onPostExecute(Void aVoid) { super.onPostExecute(aVoid); adapter.notifyDataSetChanged(); listview.onRefreshComplete(); } }.execute(); }
转载请注明原文地址: https://www.6miu.com/read-48239.html

最新回复(0)