先看效果
分别是我的效果和今日头条的效果:
以上效果包括:
1.如果下拉的高度超过search view的高度的3/4,但是小于head view高度,则松开手时search view自动出现
2.如果下拉的高度小于search view的高度的1/4,则松开手时search view自动回弹消失
3.如果下拉的高度超过head view的总高度,则松手进行刷新
4.刷新完成自动隐藏search view
实现原理讲解
参考了 github开源项目:[https://github.com/vivian8725118/SearchListView ] 但是这个开源调用listview.setOnItemClickListener的时候,下拉出现search view,下拉刷新都响应了onItemClick,这显然是不对的,我在onTouchEvent的Action_Up中进行了修改,以保证能正确响应点击事件。
提示: 这个效果是基于PullToRefreshListView实现的,如果对下拉刷新listview实现不明白的,可以先看这篇博客[http://blog.csdn.net/u010335298/article/details/51098755]
原理讲解
如图,将搜索部分的view放进ListView的头view中,在触摸事件中处理search view 的显示和隐藏。
1.我给listview定义了五种状态
public static final int STATE_NONE = 0;
public static final int STATE_PULL_TO_SHOW_SEARCH_VIEW = 1; // 下拉去展示search_view
public static final int STATE_PULL_TO_REFRESH = 2; //下拉去刷新
public static final int STATE_RELEASE_TO_REFRESH = 3; // 释放进行刷新
public static final int STATE_REFRESHING = 4; // 正在刷新
稍微讲解以下这几种状态:
STATE_PULL_TO_SHOW_SEARCH_VIEW 指的是search view出现了一部分但是没有完全出现的时候
STATE_PULL_TO_REFRESH 指的是search view完全出现,但是head view没有完全出现的时候
STATE_RELEASE_TO_REFRESH 指的是head view完全出现的时候
2.添加search view
private void initHeaderView() {
headerView = View.inflate(getContext(), R.layout.search_header_listview, null);
searchContainer = (RelativeLayout) headerView.findViewById(R.id.search_container);
headerTv = (TextView) headerView.findViewById(R.id.tvHead);
headerView.measure(0, 0); // 系统会帮我们测量出headerView的高度
headerHeight = refreshHeight = headerView.getMeasuredHeight();
Log.d("zyr", "--------------------headerHeight :" + headerHeight);
headerView.setPadding(0, -headerHeight, 0, 0);
invalidate();
Log.d("zyr", "----------------------headerPaddingTop :" + headerView.getPaddingTop());
super.addHeaderView(headerView, null, false);
}
private void addSearchView() {
searchView = LayoutInflater.from(getContext()).inflate(R.layout.search_view, null);
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
searchContainer.addView(searchView , layoutParams);
searchContainer.measure(0, 0);
searchContainerHeight = searchContainer.getMeasuredHeight();
Log.d("zyr", "--------------------searchContainerHeight :" + searchContainerHeight);
headerHeight = searchContainerHeight + headerHeight ;
headerView.setPadding(0, - headerHeight, 0, 0);
invalidate();
Log.d("zyr", "--------------------headerHeight :" + headerHeight);
Log.d("zyr", "----------------------headerPaddingTop :" + headerView.getPaddingTop());
}
3.触摸事件的处理:我详细的写了注释
/*************************** Touch***************************************/
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN :
downY = lastMoveY = (int) ev.getY();
downX = (int) ev.getX();
break;
case MotionEvent.ACTION_MOVE :
moveY = (int) ev.getY();
moveDiff = (moveY - lastMoveY)/2 ;
lastMoveY = moveY ;
diff = moveY - downY;
//计算移动后的paddingTop
int paddingTop = headerView.getPaddingTop() + moveDiff ;
// 如果: 第一个可见
if(getFirstVisiblePosition() == 0 && Math.abs(diff) > 50){
switch (state){
case STATE_NONE :
//当状态是none的时候,向下拉才做处理
if(diff > 0){
state = STATE_PULL_TO_SHOW_SEARCH_VIEW;
headerView.setPadding(0, paddingTop, 0, 0);
Log.d("zyr", "--------------paddingTop:" + paddingTop);
return true;
}
break;
case STATE_PULL_TO_SHOW_SEARCH_VIEW:
case STATE_PULL_TO_REFRESH:
case STATE_RELEASE_TO_REFRESH:
if (paddingTop >= 0 ) { // 完全显示了.
Log.i("zyr", "ACTION_MOVE 松开刷新");
state = STATE_RELEASE_TO_REFRESH;
refreshHeaderView();
} else if (