zoukankan      html  css  js  c++  java
  • 下拉刷新XListView的简单分析

    依照这篇博文里的思路分析和理解的

    先要理解Scroller,看过的博文:

    http://ipjmc.iteye.com/blog/1615828

    http://blog.csdn.net/wangjinyu501/article/details/32339379

    还要理解View的touch时间传递:

    http://www.codekk.com/open-source-project-analysis/detail/Android/Trinea/%E5%85%AC%E5%85%B1%E6%8A%80%E6%9C%AF%E7%82%B9%E4%B9%8BView%20%E4%BA%8B%E4%BB%B6%E4%BC%A0%E9%80%92


    在实现中遇到的问题:

    1、下拉时,下拉区域不会尾随下拉而变化,仅仅显示当中一部分。

    图:

    解决:採用设置下拉区域的paddind,实现尾随滚动效果。终于图:


    2、当下拉超过极限高度后向上滑动时。listview会尾随滑动。

    解决方法是通过在onTouchEvent推断这一情况推断这一情况,具体在代码里。


    代码:

    下拉区域布局文件

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical" >
    
        <RelativeLayout
            android:id="@+id/xlistview_header_content"
            android:layout_width="fill_parent"
            android:layout_height="60dp"
            android:layout_marginBottom="2dp"
            android:gravity="center_horizontal" >
    
            <TextView
                android:id="@+id/xlistview_header_hint_textview"
                android:layout_width="100dp"
                android:layout_height="wrap_content"
                android:layout_centerInParent="true"
                android:gravity="center"
                android:text="正在载入"
                android:textColor="@android:color/black"
                android:textSize="14sp" />
    
            <ImageView
                android:id="@+id/xlistview_header_image"
                android:layout_width="30dp"
                android:layout_height="wrap_content"
                android:layout_centerVertical="true"
                android:layout_toLeftOf="@id/xlistview_header_hint_textview"
                android:src="@drawable/indicator_arrow" />
    
            <ProgressBar
                android:id="@+id/xlistview_header_progressbar"
                android:layout_width="30dp"
                android:layout_height="30dp"
                android:layout_centerVertical="true"
                android:layout_toLeftOf="@id/xlistview_header_hint_textview"
                android:visibility="invisible" />
        </RelativeLayout>
    
    </LinearLayout>

    下拉区域

    package com.example.test;
    
    import android.annotation.SuppressLint;
    import android.content.Context;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.animation.Animation;
    import android.view.animation.RotateAnimation;
    import android.widget.ImageView;
    import android.widget.LinearLayout;
    import android.widget.ProgressBar;
    import android.widget.TextView;
    
    public class XListViewHeader extends LinearLayout {
    
    	private static final String HINT_NORMAL = "下拉刷新";
    	private static final String HINT_READY = "松开刷新数据";
    	private static final String HINT_LOADING = "正在载入...";
    
    	// 正常状态,下拉未超过head高度
    	public final static int STATE_NORMAL = 0;
    	// 准备刷新状态,也就是箭头方向发生改变之后的状态,可是没有刷新
    	public final static int STATE_READY = 1;
    	// 刷新状态。箭头变成了progressBar,正在刷新
    	public final static int STATE_REFRESHING = 2;
    	// 布局容器,也就是根布局
    	private LinearLayout mContentLayout;
    	// 箭头图片
    	private ImageView mImageView;
    	// 刷新状态显示
    	private ProgressBar mProgressBar;
    	// 说明文本
    	private TextView mHintTextView;
    	// 记录当前的状态
    	private int mState = -1;
    	// 用于改变箭头的方向的动画
    	private Animation mRotateUpAnim;
    	private Animation mRotateDownAnim;
    	// 动画持续时间
    	private final int ROTATE_ANIM_DURATION = 180;
    
    	private int headHeight;
    	private Context context;
    
    	public XListViewHeader(Context context) {
    		super(context);
    		this.context = context;
    		init();
    	}
    
    	private void init() {
    		LinearLayout.LayoutParams lp = new LayoutParams(
    				LayoutParams.MATCH_PARENT, 0);// 初始化高度为0
    		mContentLayout = (LinearLayout) LayoutInflater.from(context).inflate(
    				R.layout.xlistview_header, null);
    		mContentLayout.setLayoutParams(lp);
    		addView(mContentLayout);
    
    		mImageView = (ImageView) mContentLayout
    				.findViewById(R.id.xlistview_header_image);// 箭头图片
    		mHintTextView = (TextView) mContentLayout
    				.findViewById(R.id.xlistview_header_hint_textview);// 提示文本
    		mProgressBar = (ProgressBar) mContentLayout
    				.findViewById(R.id.xlistview_header_progressbar);// 进度条
    		mRotateUpAnim = new RotateAnimation(0, 180, Animation.RELATIVE_TO_SELF,
    				0.5f, Animation.RELATIVE_TO_SELF, 0.5f);// 箭头向上旋转的动画
    		mRotateUpAnim.setDuration(ROTATE_ANIM_DURATION);// 动画持续时间
    		mRotateUpAnim.setFillAfter(true);// 动画终止时停留在最后,也就是保留动画以后的状态
    		mRotateDownAnim = new RotateAnimation(-180, 0,
    				Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
    				0.5f);
    		mRotateDownAnim.setFillAfter(true);
    		setState(STATE_NORMAL);// 初始化设置为正常模式
    	}
    
    	public void setState(int state) {
    		if (state == mState) {
    			return;
    		}
    		if (state == STATE_REFRESHING) {// 设置为正在刷新状态时,清楚全部动画,箭头隐藏, 进度条显示
    			mImageView.clearAnimation();
    			mImageView.setVisibility(View.GONE);
    			mProgressBar.setVisibility(View.VISIBLE);
    		} else {
    			mImageView.setVisibility(View.VISIBLE);
    			mProgressBar.setVisibility(View.GONE);
    		}
    		switch (state) {
    		case STATE_NORMAL:
    			if (mState == STATE_READY) {// 由准备状态变为正常状态。开启向下动画
    				mImageView.startAnimation(mRotateDownAnim);
    			} else {
    				mImageView.clearAnimation();
    			}
    			mHintTextView.setText(HINT_NORMAL);
    			break;
    		case STATE_READY:
    			if (mState == STATE_NORMAL) {
    				mImageView.startAnimation(mRotateUpAnim);
    			}
    			mHintTextView.setText(HINT_READY);
    			break;
    		case STATE_REFRESHING:
    			mHintTextView.setText(HINT_LOADING);
    			break;
    		}
    		mState = state;
    	}
    
    	@SuppressLint("NewApi")
    	public void setVisitHeight(int height) {
    		if (height < 0) {
    			height = 0;
    		}
    		LinearLayout.LayoutParams lp = (LayoutParams) mContentLayout
    				.getLayoutParams();
    		lp.height = height;
    		mContentLayout.setLayoutParams(lp);
    		mContentLayout.setPadding(mContentLayout.getPaddingLeft(), height
    				- headHeight, mContentLayout.getPaddingRight(),
    				mContentLayout.getPaddingBottom());// 设置padding是为了下拉时,head尾随着下拉。更好看
    	}
    
    	public int getVisitHeight() {
    		return mContentLayout.getHeight();
    	}
    
    	public void show() {
    		mContentLayout.setVisibility(View.VISIBLE);
    	}
    
    	public void hide() {
    		mContentLayout.setVisibility(View.INVISIBLE);
    	}
    
    	public int getHeadHeight() {
    		return headHeight;
    	}
    
    	public void setHeadHeight(int headHeight) {
    		this.headHeight = headHeight;
    	}
    
    }
    

    listview

    package com.example.test;
    
    import android.content.Context;
    import android.view.MotionEvent;
    import android.view.ViewTreeObserver.OnGlobalLayoutListener;
    import android.view.animation.DecelerateInterpolator;
    import android.widget.ListView;
    import android.widget.RelativeLayout;
    import android.widget.Scroller;
    
    public class XListView extends ListView {
    	private Context context;
    	// 滑动时长
    	private final static int SCROLL_DURATION = 400;
    	// 滑动比例
    	private final static float OFFSET_RADIO = 2f;
    	// 记录按下点的y坐标
    	private float lastY;
    	// 用来回滚
    	private Scroller scroller;
    	private IXListViewListener mListViewListener;
    	private XListViewHeader headerView;
    	private RelativeLayout headerViewContent;
    	// header的高度
    	private int headerHeight;
    	// 是否可以刷新
    	private boolean enableRefresh = true;
    	// 是否正在刷新
    	private boolean isRefreashing = false;
    	// 记录当前手势是向上还是向下
    	private int TOUCH_UP = 0, TOUCH_DOWN = 1;
    	private int mTouch;
    
    	public XListView(Context context) {
    		super(context);
    		this.context = context;
    		init();
    	}
    
    	private void init() {
    		scroller = new Scroller(context, new DecelerateInterpolator());
    		headerView = new XListViewHeader(context);
    		headerViewContent = (RelativeLayout) headerView
    				.findViewById(R.id.xlistview_header_content);
    		// 获得head的高度
    		headerView.getViewTreeObserver().addOnGlobalLayoutListener(
    				new OnGlobalLayoutListener() {
    					@SuppressWarnings("deprecation")
    					@Override
    					public void onGlobalLayout() {
    						headerHeight = headerViewContent.getHeight();
    						headerView.setHeadHeight(headerHeight);
    						getViewTreeObserver()
    								.removeGlobalOnLayoutListener(this);
    					}
    				});
    		addHeaderView(headerView);
    	}
    
    	@Override
    	public boolean onTouchEvent(MotionEvent ev) {
    		switch (ev.getAction()) {
    		case MotionEvent.ACTION_DOWN:
    			lastY = ev.getRawY();
    			break;
    		case MotionEvent.ACTION_MOVE:
    			float t = ev.getRawY() - lastY;
    			lastY = ev.getRawY();
    			if (t > 0) {
    				mTouch = TOUCH_DOWN;
    			} else {
    				mTouch = TOUCH_UP;
    			}
    			// 当前是第一个item,且手势是向下,就显示下拉条,更新高度
    			if (getFirstVisiblePosition() == 0
    					&& (headerView.getVisitHeight() > 0 || t > 0)) {
    				updateHeaderViewHeight(t / OFFSET_RADIO);
    			}
    			if (!isRefreashing && mTouch == TOUCH_UP
    					&& headerView.getVisitHeight() > 0) {
    				return true;// 当下拉高度达到header高度时候,松开就可以刷新。若此刻向上滑,listview会尾随滑动,return
    							// true 代表消费这个事件,listview禁止滚动
    			}
    			break;
    		case MotionEvent.ACTION_UP:
    			if (getFirstVisiblePosition() == 0) {
    				if (enableRefresh && headerView.getVisitHeight() > headerHeight) {
    					isRefreashing = true;
    					headerView.setState(headerView.STATE_REFRESHING);
    					if (mListViewListener != null) {
    						mListViewListener.onRefresh();//刷新事件
    					}
    				}
    			}
    			resetHeaderHeight();
    			break;
    		}
    		return super.onTouchEvent(ev);
    	}
    
    	public void updateHeaderViewHeight(float f) {
    		headerView.setVisitHeight((int) f + headerView.getVisitHeight());
    		// 未处于刷新状态,更新箭头
    		if (enableRefresh && !isRefreashing) {
    			if (headerView.getVisitHeight() > headerHeight) {
    				headerView.setState(XListViewHeader.STATE_READY);
    			}else{
    				headerView.setState(XListViewHeader.STATE_NORMAL);				
    			}
    		}
    	}
    
    	// 下拉条动态消失
    	public void resetHeaderHeight() {
    		int height = headerView.getVisitHeight();
    		int endheight = 0;
    		if (isRefreashing) {
    			endheight = headerHeight;
    		}
    		// y轴方向由 height 到 endheight 。第三个參数是增量,假设不是刷新则高度变为0,假设是,高度变为head原始高度
    		scroller.startScroll(0, height, 0, endheight - height, SCROLL_DURATION);
    		invalidate();
    	}
    
    	public void computeScroll() {
    		if (scroller.computeScrollOffset()) {
    			// 利用scroller 。设置高度。重复重绘
    			headerView.setVisitHeight(scroller.getCurrY());
    			postInvalidate();
    		}
    		super.computeScroll();
    	}
    
    	public void stopRefresh() {
    		if (isRefreashing == true) {
    			isRefreashing = false;
    			resetHeaderHeight();
    		}
    	}
    
    	public void setIxListener(IXListViewListener listener) {
    		this.mListViewListener = listener;
    	}
    
    	interface IXListViewListener {
    		public void onRefresh();// 刷新事件的回调函数
    	}
    }
    

    mainactivity

    package com.example.test;
    
    import android.app.Activity;
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.Message;
    import android.widget.ArrayAdapter;
    
    import com.example.test.XListView.IXListViewListener;
    
    public class MainActivity extends Activity {
    	private XListView xListView;
    	private Handler handler = new Handler() {
    		public void handleMessage(Message msg) {
    			xListView.stopRefresh();
    		}
    	};
    
    	protected void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    		xListView = new XListView(this);
    		ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
    				android.R.layout.simple_expandable_list_item_1);
    		xListView.setAdapter(adapter);
    		for (int i = 0; i < 10; i++) {
    			adapter.add("text" + i);
    		}
    		setContentView(xListView);
    		xListView.setIxListener(new IXListViewListener() {
    			public void onRefresh() {
    				new Thread() {
    					public void run() {
    						try {
    							Thread.sleep(2000);
    						} catch (InterruptedException e) {
    							e.printStackTrace();
    						}
    						handler.sendEmptyMessage(0);
    					}
    				}.start();
    			}
    		});
    	}
    }


    下载

    csdn博文编辑不能撤销么。写的东西都没了

  • 相关阅读:
    【剑指Offer】49把字符串转换成整数
    【剑指Offer】48不用加减乘除做加法
    【剑指Offer】47求1+2+3+...+n
    判断两个线段是否相交
    EM算法--原理
    理解KMP算法
    阿里校招笔试的一道逻辑题
    线性拟合之最小二乘方法和最小距离方法
    Oracle Net Manager 服务命名配置以及用PL/SQL 登陆数据库
    正则表达式总结
  • 原文地址:https://www.cnblogs.com/wzzkaifa/p/7366809.html
Copyright © 2011-2022 走看看