一.上拉刷新
步骤:
1.需要添加顶部下拉加载界面。
2.监听onScrollListener来判断当前是否显示在ListView的最顶部。
3.因为顶部下拉加载界面是随收拾滑动状态不断改变的,因此我们需要监听onTouch事件,来改变当前状态以及界面显示。
4.根据当前状态加载数据。
大家先看看主角上拉刷新View的设计
<?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" android:paddingTop="10dp" android:paddingBottom="10dp"> <LinearLayout android:id="@+id/id_layout" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:orientation="vertical"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/id_tip" android:text="下拉可以刷新"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/id_lastupdatetime" android:text="5分钟之前刷新"/> </LinearLayout> <ImageView android:id="@+id/id_arrow" android:layout_toLeftOf="@id/id_layout" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/arrow" /> <ProgressBar android:id="@+id/id_progress" style="?android:attr/progressBarStyle" android:layout_toLeftOf="@id/id_layout" android:layout_width="wrap_content" android:layout_height="wrap_content" android:visibility="visible"/> </RelativeLayout> </LinearLayout>是时候把他初始化了
实现OnScrollListener,定义我要使用的变量
public class LoadListView extends ListView implements AbsListView.OnScrollListener {
private View header; private boolean isRemark;//标记、当前是在ListView最顶端按下的 private int startY;//按下时的Y值 private int state;//当前的状态 private int scrollState;//ListView的当前滚动状态 private final int NONE=0;//正常状态 private final int PULL=1;//提示下拉状态 private final int RELEASE=2;//提示释放状态 private final int REFLEASHING=3;//正在刷新状态 private IRefleshListener iRefleshListener;//
private void initView(Context context) { LayoutInflater inflater = LayoutInflater.from(context); header = inflater.inflate(R.layout.header_layout, null); //通知父布局,占用的宽高 measureView(header); headerHeight = header.getMeasuredHeight(); Log.i("LoadListView", "headerHeight " + headerHeight); //设置header布局的上边距 topPadding(-headerHeight); footer = inflater.inflate(R.layout.footer_layout, null); footer.findViewById(R.id.id_loadlayout).setVisibility(View.GONE); this.setOnScrollListener(this); this.addHeaderView(header); this.addFooterView(footer); }通知父布局,占用的宽高,否则header.getMeasuredHeight()为零
/* 通知父布局,占用的宽高 */ 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); } Log.i("LoadListView", "width:" + width); Log.i("LoadListView", "height:" + height); view.measure(width,height); }设置header布局的高度为负原始高度来隐藏header 别忘了刷新header控件
//设置header布局的上边距 private void topPadding(int topPaddding) { header.setPadding(header.getPaddingLeft(), topPaddding, header.getPaddingRight(), header.getPaddingBottom()); header.invalidate(); }
记录一下listview第一个item的次序来判断是否scroll达到了最顶端
@Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { this.firstVisibleItem=firstVisibleItem; this.lastVisibleItem = firstVisibleItem + visibleItemCount; this.totalItemCount = totalItemCount; }
记录 scrollState
@Override public void onScrollStateChanged(AbsListView view, int scrollState) { this.scrollState = scrollState;
判断onTouchEvent来决定header显示啥子东西
@Override public boolean onTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: { if (firstVisibleItem == 0) isRemark = true;//标记 是否在listview最顶端按下 startY = (int) ev.getY();//按下时的Y值 } break; case MotionEvent.ACTION_MOVE: onMove(ev); break; case MotionEvent.ACTION_UP://判断抬手时的状态 if (state == RELEASE) {//若是释放状态执行刷新 state = REFLEASHING; //加载最新的数据 if (this.iRefleshListener != null) { this.iRefleshListener.onReflesh(); reflashViewByState(); } } else if (state == PULL) {//若是下拉状态 置为正常状态 state = NONE; isRemark = false; reflashViewByState(); } } return super.onTouchEvent(ev); }
iRefleshListener是为了调用那个实现它接口的主Activity里面方法 这个怎么做呢
1.A为主类 B为辅类 在A中实例化B A可以调B B如果想调A 就得这么搞
在B中定义接口
private IRefleshListener iRefleshListener;
public interface IRefleshListener { public void onReflesh(); }
并定义一个方法把A传进来
public void setInterface(IRefleshListener iRefleshListener) { this.iRefleshListener = iRefleshListener; }
public class MainActivity extends AppCompatActivity implements LoadListView.ILoadListener ,LoadListView.IRefleshListener {
mListView.setInterface(this);
@Override public void onReflesh() { //加一个延迟效果 android.os.Handler handler = new android.os.Handler(); handler.postDelayed(new Runnable() { @Override public void run() { //获取最新数据 setRefleshDatas(); //通知界面显示 ShowListView((ArrayList<Bean>)mDatas); //通知listview通知完毕 mListView.refleshComplete(); } },2000); } }
/* 判断移动过程中的操作 */ private void onMove(MotionEvent ev) { if (!isRemark) return; int tempY = (int) ev.getY(); int space = tempY - startY; int topPadding = space - headerHeight; switch (state) { case NONE://如果大于0个像素 说明状态由空置转变为下拉状态 if (space > 0) state = PULL; reflashViewByState();//根据当前状态改变界面显示 break; case PULL: topPadding(topPadding);//一步一步似爪牙 if (space > headerHeight + 30 && scrollState == SCROLL_STATE_TOUCH_SCROLL) { state = RELEASE; reflashViewByState(); } break; case RELEASE: topPadding(topPadding); if (space < headerHeight + 30) { state = PULL; reflashViewByState(); } else if (space <= 0) { state = NONE; isRemark = false; reflashViewByState(); } break; case REFLEASHING: break; } }下面是更新界面
/* 根据当前状态改变界面显示 */ private void reflashViewByState() { TextView tip = (TextView) header.findViewById(R.id.id_tip); ImageView arrow = (ImageView) header.findViewById(R.id.id_arrow); ProgressBar progressBar = (ProgressBar) header.findViewById(R.id.id_progress); RotateAnimation anim = new RotateAnimation(0, 180, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f); RotateAnimation anim1 = new RotateAnimation(180, 0, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f); anim.setDuration(500); anim.setFillAfter(true); anim1.setDuration(500); anim1.setFillAfter(true); switch (state) { case NONE: topPadding(-headerHeight); arrow.clearAnimation(); break; case PULL: arrow.setVisibility(View.VISIBLE); progressBar.setVisibility(View.GONE); tip.setText("下拉可以刷新"); arrow.setAnimation(anim1); break; case RELEASE: arrow.setVisibility(View.VISIBLE); progressBar.setVisibility(View.GONE); tip.setText("松开可以刷新"); arrow.setAnimation(anim); break; case REFLEASHING: topPadding(headerHeight); arrow.setVisibility(View.GONE); progressBar.setVisibility(View.VISIBLE); tip.setText("正在刷新..."); arrow.clearAnimation(); break; } }获取完毕记得给header干掉并记录一下时间
/* 获取完数据 */ public void refleshComplete() { state = NONE; isRemark = false; reflashViewByState(); TextView lastUpdateTime = (TextView) header.findViewById(R.id.id_lastupdatetime); SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日 hh:mm:ss"); Date date = new Date(System.currentTimeMillis()); String time = format.format(date); lastUpdateTime.setText(time); }
哈拉先更到这里啦