首页 > 代码库 > 下拉刷新功能的实现。
下拉刷新功能的实现。
下拉刷新的在android程序中很常见,自己也耐着性子完成了对它的具体实现。
首先你得知道刷新控件也是一个ListView,你用自己的方式实现了一个自定义ListView,
这个ListView具有下拉刷新功能。创建自己的ListView:
public class RefreshListView extends ListView implements OnScrollListener{ 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); } }包括了几个不同的构造方法。下拉时能显示“下拉刷新”是因为ListView能够设置一个头部View,initView(context)
初始化headerView。
private void initView(Context context){ //LayoutInflater作用是加载布局 LayoutInflater inflater = LayoutInflater.from(context); header = inflater.inflate(R.layout.header_layout, null); measureView(header); headerHeight = header.getMeasuredHeight(); Log.i("headerHeight", ""+headerHeight); topPadding(-headerHeight); this.addHeaderView(header); this.setOnScrollListener(this); Time t = new Time(); t.setToNow(); updateTime = t.hour*60+t.minute; Log.i(TAG, "init--->"+updateTime); }把headerView放入布局中,总得告诉父布局你所占用的宽和高啊!调用measuerView()方法进行初始化。
private void measureView(View view){ //LayoutParams are used by views to tell their parents //how they want to be laid out. //LayoutParams被view用来告诉它们的父布局它们应该被怎样安排 ViewGroup.LayoutParams p = view.getLayoutParams(); if(p==null){ //两个参数:width,height p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); } //getChildMeasureSpec:获取子View的widthMeasureSpec、heightMeasureSpec值, //之所以widthMeasureSpec和heightMeasureSpec的获取方法不一样是因为listview中不限定高度 // 但是限定了宽度 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); }toPadding ()方法用于设定headerView的头边距,用于进行隐藏和显示以及拖动,初始化为隐藏。
private void topPadding(int topPadding){ //设置顶部提示的边距 //除了顶部用参数值topPadding外,其他三个用header默认的值 header.setPadding(header.getPaddingLeft(), topPadding, header.getPaddingRight(), header.getPaddingBottom()); //使header无效,将来调用onDraw()重绘View <span style="white-space:pre"> </span>header.invalidate(); }实现OnScrollListener接口主要是为了监听手指是否在屏幕上面,还有就是当前界面上的的第一个
ListItem是否是的第一个item。(当在ListView顶部的时候才能下拉刷新)
@Override public void onScrollStateChanged(AbsListView view, int scrollState) { // TODO Auto-generated method stub this.scrollState = scrollState; } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { // TODO Auto-generated method stub this.firstVisibleItem = firstVisibleItem; }重载onTouchEvent 监听用户手势状态包括按下,滑动,以及放开状态。
@Override public boolean onTouchEvent(MotionEvent ev) { // TODO Auto-generated method stub switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: if(firstVisibleItem == 0){ isFlag = true;//ListView最顶端按下,标志值设为真 startY = (int)ev.getY(); } break; case MotionEvent.ACTION_MOVE: Time t = new Time(); t.setToNow(); System.out.println(t.hour + "时" + t.minute + "分" + t.second + "秒"); onMove(ev); break; case MotionEvent.ACTION_UP: if(state == RELEASE){ state = REFRESH; //加载数据 refreshViewByState(); iRefreshlistener.onRefresh(); }else if(state == PULL){ state = NONE; isFlag = false; refreshViewByState(); } break; } return super.onTouchEvent(ev); }
private void onMove(MotionEvent ev){ //如果不是最顶端按下,则直接返回 if(!isFlag){ return; } int currentY = (int)ev.getY();//当前的Y值 int space = currentY - startY;//用户向下拉的距离 int topPadding = space - headerHeight;//顶部提示View距顶部的距离值 switch (state) { //正常状态 case NONE: if(space>0){ state = PULL;//下拉的距离大于0,则将状态改为PULL(提示下拉更新) refreshViewByState();//根据状态的不同更新View } break; case PULL: topPadding(topPadding); if(space>headerHeight+30//下拉的距离大于header的高度加30且用户滚动屏幕,手指仍在屏幕上 &&scrollState == SCROLL_STATE_TOUCH_SCROLL ){ state = RELEASE;//将状态改为RELEASE(提示松开更新) refreshViewByState(); } break; case RELEASE: if(topPadding > headerHeight + 50){ topPadding = headerHeight + 50; } topPadding(topPadding); if(space<headerHeight+30){//用户下拉的距离不够 state = PULL; //将状态改为PULL refreshViewByState(); }else if(space<=0){ //用户下拉的距离为非正值 state = NONE; //将状态改为NONE isFlag = false; //标志改为false refreshViewByState(); } break; }根据用户的滑动距离改变state的值,并调用refreshViewByState()方法根据state更新控件的显示方式。
private void refreshViewByState(){ //提示 TextView tips = (TextView)header.findViewById(R.id.tips); //箭头 ImageView arrow = (ImageView)header.findViewById(R.id.arrow); //进度条 ProgressBar progress = (ProgressBar)header.findViewById(R.id.progress); //箭头的动画效果1,由0度转向180度,即箭头由朝下转为朝上 RotateAnimation animation1 = new RotateAnimation(0, 180, RotateAnimation.RELATIVE_TO_SELF,0.5f, RotateAnimation.RELATIVE_TO_SELF,0.5f); animation1.setDuration(500); animation1.setFillAfter(true); //箭头的动画效果2,由180度转向0度,即箭头由朝上转为朝下 RotateAnimation animation2 = new RotateAnimation(180, 0, RotateAnimation.RELATIVE_TO_SELF,0.5f, RotateAnimation.RELATIVE_TO_SELF,0.5f); animation2.setDuration(500); animation2.setFillAfter(true); switch (state) { case NONE: //正常状态 arrow.clearAnimation(); //清除箭头动画效果 topPadding(-headerHeight); //设置header距离顶部的距离 break; case PULL: //下拉状态 arrow.setVisibility(View.VISIBLE); //箭头设为可见 progress.setVisibility(View.GONE); //进度条设为不可见 tips.setText("下拉可以刷新"); //提示文字设为"下拉可以刷新" arrow.clearAnimation(); //清除之前的动画效果,并将其设置为动画效果2 arrow.setAnimation(animation2); break; case RELEASE: //释放状态 arrow.setVisibility(View.VISIBLE); //箭头设为可见 progress.setVisibility(View.GONE); //进度条设为不可见 tips.setText("松开可以刷新"); //提示文字设为"松开可以刷新" arrow.clearAnimation(); //清除之前的动画效果,并将其设置为动画效果2 arrow.setAnimation(animation1); break; case REFRESH: //更新状态 topPadding(50); //距离顶部的距离设置为50 arrow.setVisibility(View.GONE); //箭头设为不可见 progress.setVisibility(View.VISIBLE); //进度条设为可见 tips.setText("正在刷新..."); //提示文字设为""正在刷新..." arrow.clearAnimation(); //清除动画效果 break; }这就是下拉刷新实现的流程了。
下拉刷新功能的实现。
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。