android仿新浪微博刷新列表

大家看到新浪微博中的列表往下拉的时候, 头部出现正在刷新,然后获取到数据了以后列表会刷新的效果了吧,是不是都觉得很棒啊。 笔者今天参考进行实现。 当然也借鉴了前人的劳动成果。 下面对具体实现进行剖析。 
首先要明确一点的是,ListView提供了HeaderView 和FooterView用于增加顶部和底部视图。 头部的刷新调和底部的更多条目都是使用这两个来实现的。 
下面我们来看看怎么实现的: 
1.  对ListView进行集成,主要是监听滑动事件,触发底端和顶端事件: 
package com.drawthink.nxjobhunting.ui.components; 

import android.content.Context; 
import android.util.AttributeSet; 
import android.view.MotionEvent; 
import android.view.View; 
import android.widget.ListView; 


/** 
* <p>一个可以监听ListView是否滚动到最顶部或最底部的自定义控件</p> 
* 只能监听由触摸产生的,如果是ListView本身Flying导致的,则不能监听</br> 
* 如果加以改进,可以实现监听scroll滚动的具体位置等 
* @author Seya Qu</br> Email:seyason@gmail.com 
*/ 

public class ScrollOverListView extends ListView { 

private int mLastY; 
private int mTopPosition; 
private int mBottomPosition; 

public ScrollOverListView(Context context, AttributeSet attrs, int defStyle) { 
super(context, attrs, defStyle); 
init(); 


public ScrollOverListView(Context context, AttributeSet attrs) { 
super(context, attrs); 
init(); 


public ScrollOverListView(Context context) { 
super(context); 
init(); 


private void init(){ 
mTopPosition = 0; 
mBottomPosition = 0; 


@Override 
public boolean onTouchEvent(MotionEvent ev) { 
final int action = ev.getAction(); 
final int y = (int) ev.getRawY(); 

switch(action){ 
case MotionEvent.ACTION_DOWN:{ 
mLastY = y; 
final boolean isHandled = mOnScrollOverListener.onMotionDown(ev); 
if (isHandled) { 
mLastY = y; 
return isHandled; 

break; 


case MotionEvent.ACTION_MOVE:{ 
final int childCount = getChildCount(); 
if(childCount == 0) return super.onTouchEvent(ev); 

final int itemCount = getAdapter().getCount() - mBottomPosition; 

final int deltaY = y - mLastY; 
//DLog.d("lastY=%d y=%d", mLastY, y); 

final int firstTop = getChildAt(0).getTop(); 
final int listPadding = getListPaddingTop(); 

final int lastBottom = getChildAt(childCount - 1).getBottom(); 
final int end = getHeight() - getPaddingBottom(); 

final int firstVisiblePosition = getFirstVisiblePosition(); 

final boolean isHandleMotionMove = mOnScrollOverListener.onMotionMove(ev, deltaY); 

if(isHandleMotionMove){ 
mLastY = y; 
return true; 


//DLog.d("firstVisiblePosition=%d firstTop=%d listPaddingTop=%d deltaY=%d", firstVisiblePosition, firstTop, listPadding, deltaY); 
if (firstVisiblePosition <= mTopPosition && firstTop >= listPadding && deltaY > 0) { 
            final boolean isHandleOnListViewTopAndPullDown; 
            isHandleOnListViewTopAndPullDown = mOnScrollOverListener.onListViewTopAndPullDown(deltaY); 
            if(isHandleOnListViewTopAndPullDown){ 
            mLastY = y; 
            return true; 
            } 
        } 

// DLog.d("lastBottom=%d end=%d deltaY=%d", lastBottom, end, deltaY); 
        if (firstVisiblePosition + childCount >= itemCount && lastBottom <= end && deltaY < 0) { 
        final boolean isHandleOnListViewBottomAndPullDown; 
        isHandleOnListViewBottomAndPullDown = mOnScrollOverListener.onListViewBottomAndPullUp(deltaY); 
        if(isHandleOnListViewBottomAndPullDown){ 
        mLastY = y; 
        return true; 
        } 
        } 
break; 


case MotionEvent.ACTION_UP:{ 
final boolean isHandlerMotionUp = mOnScrollOverListener.onMotionUp(ev); 
if (isHandlerMotionUp) { 
mLastY = y; 
return true; 

break; 



mLastY = y; 
return super.onTouchEvent(ev); 



/**空的*/ 
private OnScrollOverListener mOnScrollOverListener = new OnScrollOverListener(){ 

@Override 
public boolean onListViewTopAndPullDown(int delta) { 
return false; 


@Override 
public boolean onListViewBottomAndPullUp(int delta) { 
return false; 


@Override 
public boolean onMotionDown(MotionEvent ev) { 
return false; 


@Override 
public boolean onMotionMove(MotionEvent ev, int delta) { 
return false; 


@Override 
public boolean onMotionUp(MotionEvent ev) { 
return false; 


}; 







// =============================== public method =============================== 

/** 
* 可以自定义其中一个条目为头部,头部触发的事件将以这个为准,默认为第一个 

* @param index 正数第几个,必须在条目数范围之内 
*/ 
public void setTopPosition(int index){ 
if(getAdapter() == null) 
throw new NullPointerException("You must set adapter before setTopPosition!"); 
if(index < 0) 
throw new IllegalArgumentException("Top position must > 0"); 

mTopPosition = index; 


/** 
* 可以自定义其中一个条目为尾部,尾部触发的事件将以这个为准,默认为最后一个 

* @param index 倒数第几个,必须在条目数范围之内 
*/ 
public void setBottomPosition(int index){ 
if(getAdapter() == null) 
throw new NullPointerException("You must set adapter before setBottonPosition!"); 
if(index < 0) 
throw new IllegalArgumentException("Bottom position must > 0"); 

mBottomPosition = index; 


/** 
* 设置这个Listener可以监听是否到达顶端,或者是否到达低端等事件</br> 

* @see OnScrollOverListener 
*/ 
public void setOnScrollOverListener(OnScrollOverListener onScrollOverListener){ 
mOnScrollOverListener = onScrollOverListener; 


/** 
* 滚动监听接口</br> 
* @see ScrollOverListView#setOnScrollOverListener(OnScrollOverListener) 

* @author Seya Qu</br> Email:seyason@gmail.com 
*/ 
public interface OnScrollOverListener { 

/** 
* 到达最顶部触发 

* @param delta 手指点击移动产生的偏移量 
* @return 
*/ 
boolean onListViewTopAndPullDown(int delta); 

/** 
* 到达最底部触发 

* @param delta 手指点击移动产生的偏移量 
* @return 
*/ 
boolean onListViewBottomAndPullUp(int delta); 

/** 
* 手指触摸按下触发,相当于{@link MotionEvent#ACTION_DOWN} 

* @return 返回true表示自己处理 
* @see View#onTouchEvent(MotionEvent) 
*/ 
boolean onMotionDown(MotionEvent ev); 

/** 
* 手指触摸移动触发,相当于{@link MotionEvent#ACTION_MOVE} 

* @return 返回true表示自己处理 
* @see View#onTouchEvent(MotionEvent) 
*/ 
boolean onMotionMove(MotionEvent ev, int delta); 

/** 
* 手指触摸后提起触发,相当于{@link MotionEvent#ACTION_UP} 

* @return 返回true表示自己处理 
* @see View#onTouchEvent(MotionEvent) 
*/ 
boolean onMotionUp(MotionEvent ev); 







2. 定义PullDownView, 继承LinearLayout, 主要是为了调用和监听ListView, 通过接口OnPullDownListener的onRefresh来通知外部进行顶部数据的刷新, onMore触发请求底部更多数据, 具体如何去获取数据, 需要在外面的Activity中实现。 
package com.drawthink.nxjobhunting.ui.components; 

import java.text.SimpleDateFormat; 
import java.util.Date; 
import java.util.Timer; 
import java.util.TimerTask; 

import android.content.Context; 
import android.os.Handler; 
import android.os.Message; 
import android.util.AttributeSet; 
import android.view.LayoutInflater; 
import android.view.MotionEvent; 
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.ListView; 
import android.widget.TextView; 

import com.drawthink.nxjobhunting.R; 
import com.drawthink.nxjobhunting.ui.components.ScrollOverListView.OnScrollOverListener; 
import com.drawthink.nxjobhunting.utils.GlobalVar; 
import com.drawthink.nxjobhunting.utils.LogX; 

/** 
* 下拉刷新控件</br> 
* 真正实现下拉刷新的是这个控件, 
* ScrollOverListView只是提供触摸的事件等 
* @author Seya Qu</br> Email:seyason@gmail.com 
*/ 
public class PullDownView extends LinearLayout implements OnScrollOverListener{ 

private static final int START_PULL_DEVIATION = 50; // 移动误差 
private static final int AUTO_INCREMENTAL = 10; // 自增量,用于回弹 

private static final int WHAT_DID_LOAD_DATA = 1; // Handler what 数据加载完毕 
private static final int WHAT_ON_REFRESH = 2; // Handler what 刷新中 
private static final int WHAT_DID_REFRESH = 3; // Handler what 已经刷新完 
private static final int WHAT_SET_HEADER_HEIGHT = 4;// Handler what 设置高度 
private static final int WHAT_DID_MORE = 5; // Handler what 已经获取完更多 

private static final int DEFAULT_HEADER_VIEW_HEIGHT = 105; // 头部文件原本的高度 

private static SimpleDateFormat dateFormat = new SimpleDateFormat("MM-dd HH:mm"); 

private View mHeaderView; 
private LayoutParams mHeaderViewParams;
private TextView mHeaderViewDateView; 
private TextView mHeaderTextView; 
private ImageView mHeaderArrowView; 
private View mHeaderLoadingView; 
private View mFooterView; 
private TextView mFooterTextView; 
private View mFooterLoadingView; 
private ScrollOverListView mListView; 

private OnPullDownListener mOnPullDownListener; 
private RotateAnimation mRotateOTo180Animation; 
private RotateAnimation mRotate180To0Animation; 

private int mHeaderIncremental; // 增量 
private float mMotionDownLastY; // 按下时候的Y轴坐标 

private boolean mIsDown; // 是否按下 
private boolean mIsRefreshing; // 是否下拉刷新中 
private boolean mIsFetchMoreing; // 是否获取更多中 
private boolean mIsPullUpDone; // 是否回推完成 
private boolean mEnableAutoFetchMore; // 是否允许自动获取更多 

// 头部文件的状态 
private static final int HEADER_VIEW_STATE_IDLE = 0; // 空闲 
private static final int HEADER_VIEW_STATE_NOT_OVER_HEIGHT = 1; // 没有超过默认高度 
private static final int HEADER_VIEW_STATE_OVER_HEIGHT = 2; // 超过默认高度 
private int mHeaderViewState = HEADER_VIEW_STATE_IDLE; 


public PullDownView(Context context, AttributeSet attrs) { 
super(context, attrs); 
initHeaderViewAndFooterViewAndListView(context); 


public PullDownView(Context context) { 
super(context); 
initHeaderViewAndFooterViewAndListView(context); 


/* 
* ================================== 
* Public method 
* 外部使用,具体就是用这几个就可以了 

* ================================== 
*/ 

/** 
* 刷新事件接口 
* @author 何龙威 Email:kjsoloho@gmail.com 
*/ 
public interface OnPullDownListener { 
void onRefresh(); 
void onMore(); 


/** 
* 通知加载完了数据,要放在Adapter.notifyDataSetChanged后面 
* 当你加载完数据的时候,调用这个notifyDidLoad() 
* 才会隐藏头部,并初始化数据等 
*/ 
public void notifyDidLoad() { 
mUIHandler.sendEmptyMessage(WHAT_DID_LOAD_DATA); 


/** 
* 通知已经刷新完了,要放在Adapter.notifyDataSetChanged后面 
* 当你执行完刷新任务之后,调用这个notifyDidRefresh() 
* 才会隐藏掉头部文件等操作 
*/ 
public void notifyDidRefresh() { 
mUIHandler.sendEmptyMessage(WHAT_DID_REFRESH); 


/** 
* 通知已经获取完更多了,要放在Adapter.notifyDataSetChanged后面 
* 当你执行完更多任务之后,调用这个notyfyDidMore() 
* 才会隐藏加载圈等操作 
*/ 
public void notifyDidMore() { 
mUIHandler.sendEmptyMessage(WHAT_DID_MORE); 


/** 
* 设置监听器 
* @param listener 
*/ 
public void setOnPullDownListener(OnPullDownListener listener){ 
mOnPullDownListener = listener; 


/** 
* 获取内嵌的listview 
* @return ScrollOverListView 
*/ 
public ListView getListView(){ 
return mListView; 


/** 
* 是否开启自动获取更多 
* 自动获取更多,将会隐藏footer,并在到达底部的时候自动刷新 
* @param index 倒数第几个触发 
*/ 
public void enableAutoFetchMore(boolean enable, int index){ 
if(enable){ 
mListView.setBottomPosition(index); 
mFooterLoadingView.setVisibility(View.VISIBLE); 
}else{ 
mFooterTextView.setText("更多"); 
mFooterLoadingView.setVisibility(View.GONE); 

mEnableAutoFetchMore = enable; 


/* 
* ================================== 
* Private method 
* 具体实现下拉刷新等操作 

* ================================== 
*/ 

/** 
* 初始化界面 
*/ 
private void initHeaderViewAndFooterViewAndListView(Context context){ 
setOrientation(LinearLayout.VERTICAL); 
//setDrawingCacheEnabled(false); 
/* 
* 自定义头部文件 
* 放在这里是因为考虑到很多界面都需要使用 
* 如果要修改,和它相关的设置都要更改 
*/ 
mHeaderView = LayoutInflater.from(context).inflate(R.layout.pulldown_header, null); 
mHeaderViewParams = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT); 
addView(mHeaderView, 0, mHeaderViewParams); 

mHeaderTextView = (TextView) mHeaderView.findViewById(R.id.pulldown_header_text); 
mHeaderArrowView = (ImageView) mHeaderView.findViewById(R.id.pulldown_header_arrow); 
mHeaderLoadingView = mHeaderView.findViewById(R.id.pulldown_header_loading); 

// 注意,图片旋转之后,再执行旋转,坐标会重新开始计算 
mRotateOTo180Animation = new RotateAnimation(0, 180, 
Animation.RELATIVE_TO_SELF, 0.5f, 
Animation.RELATIVE_TO_SELF, 0.5f); 
mRotateOTo180Animation.setDuration(250); 
mRotateOTo180Animation.setFillAfter(true); 

mRotate180To0Animation = new RotateAnimation(180, 0, 
Animation.RELATIVE_TO_SELF, 0.5f, 
Animation.RELATIVE_TO_SELF, 0.5f); 
mRotate180To0Animation.setDuration(250); 
mRotate180To0Animation.setFillAfter(true); 

/** 
* 自定义脚部文件 
*/ 
mFooterView = LayoutInflater.from(context).inflate(R.layout.pulldown_footer, null); 
mFooterTextView = (TextView) mFooterView.findViewById(R.id.pulldown_footer_text); 
mFooterLoadingView = mFooterView.findViewById(R.id.pulldown_footer_loading); 
mFooterView.setOnClickListener(new OnClickListener() { 
@Override 
public void onClick(View v) { 
if(!mIsFetchMoreing){ 
mIsFetchMoreing = true; 
mFooterTextView.setText("加载更多中..."); 
mFooterLoadingView.setVisibility(View.VISIBLE); 
mOnPullDownListener.onMore(); 


}); 

/* 
* ScrollOverListView 同样是考虑到都是使用,所以放在这里 
* 同时因为,需要它的监听事件 
*/ 
mListView = new ScrollOverListView(context); 
mListView.setVerticalScrollBarEnabled(false); 
mListView.setOnScrollOverListener(this); 
mListView.setCacheColorHint(0); 

mListView.setDivider(GlobalVar.appContext.getResources().getDrawable(R.drawable.dot)); 

addView(mListView, LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT); 

// 空的listener 
mOnPullDownListener = new OnPullDownListener() { 
@Override 
public void onRefresh() {} 
@Override 
public void onMore() {} 
}; 


/** 
* 在下拉和回推的时候检查头部文件的状态</br> 
* 如果超过了默认高度,就显示松开可以刷新, 
* 否则显示下拉可以刷新 
*/ 
private void checkHeaderViewState(){ 
if(mHeaderViewParams.height >= DEFAULT_HEADER_VIEW_HEIGHT){ 
if(mHeaderViewState == HEADER_VIEW_STATE_OVER_HEIGHT) return; 
mHeaderViewState = HEADER_VIEW_STATE_OVER_HEIGHT; 
mHeaderTextView.setText("松开可以刷新"); 
mHeaderArrowView.startAnimation(mRotateOTo180Animation); 
}else{ 
if(mHeaderViewState == HEADER_VIEW_STATE_NOT_OVER_HEIGHT 
|| mHeaderViewState == HEADER_VIEW_STATE_IDLE) return; 
mHeaderViewState = HEADER_VIEW_STATE_NOT_OVER_HEIGHT; 
mHeaderTextView.setText("下拉可以刷新"); 
mHeaderArrowView.startAnimation(mRotate180To0Animation); 



private void setHeaderHeight(final int height){ 
mHeaderIncremental = height; 
mHeaderViewParams.height = height; 
mHeaderView.setLayoutParams(mHeaderViewParams); 


/** 
* 自动隐藏动画 
* @author 何龙威 Email:kjsoloho@gmail.com 
*/ 
class HideHeaderViewTask extends TimerTask{ 
@Override 
public void run() { 
if(mIsDown) { 
cancel(); 
return; 

mHeaderIncremental -= AUTO_INCREMENTAL; 
if(mHeaderIncremental > 0){ 
mUIHandler.sendEmptyMessage(WHAT_SET_HEADER_HEIGHT); 
}else{ 
mHeaderIncremental = 0; 
mUIHandler.sendEmptyMessage(WHAT_SET_HEADER_HEIGHT); 
cancel(); 




/** 
* 自动显示动画 
* @author 何龙威 Email:kjsoloho@gmail.com 
*/ 
class ShowHeaderViewTask extends TimerTask{ 

@Override 
public void run() { 
if(mIsDown) { 
cancel(); 
return; 

mHeaderIncremental -= AUTO_INCREMENTAL; 
if(mHeaderIncremental > DEFAULT_HEADER_VIEW_HEIGHT){ 
mUIHandler.sendEmptyMessage(WHAT_SET_HEADER_HEIGHT); 
}else{ 
mHeaderIncremental = DEFAULT_HEADER_VIEW_HEIGHT; 
mUIHandler.sendEmptyMessage(WHAT_SET_HEADER_HEIGHT); 
if(!mIsRefreshing){ 
mIsRefreshing = true; 
mUIHandler.sendEmptyMessage(WHAT_ON_REFRESH); 

cancel(); 





private Handler mUIHandler = new Handler(){ 

@Override 
public void handleMessage(Message msg) { 
switch (msg.what) { 
case WHAT_DID_LOAD_DATA:{ 
mHeaderViewParams.height = 0; 
mHeaderLoadingView.setVisibility(View.GONE); 
mHeaderTextView.setText("下拉可以刷新"); 
mHeaderViewDateView = (TextView) mHeaderView.findViewById(R.id.pulldown_header_date); 
mHeaderViewDateView.setVisibility(View.VISIBLE); 
mHeaderViewDateView.setText("更新于:" + dateFormat.format(new Date(System.currentTimeMillis()))); 
mHeaderArrowView.setVisibility(View.VISIBLE); 
showFooterView(); 
return; 


case WHAT_ON_REFRESH:{ 
// 要清除掉动画,否则无法隐藏 
mHeaderArrowView.clearAnimation(); 
mHeaderArrowView.setVisibility(View.INVISIBLE); 
mHeaderLoadingView.setVisibility(View.VISIBLE); 
mOnPullDownListener.onRefresh();
return; 


case WHAT_DID_REFRESH :{ 
mIsRefreshing = false; 
mHeaderViewState = HEADER_VIEW_STATE_IDLE; 
mHeaderArrowView.setVisibility(View.VISIBLE); 
mHeaderLoadingView.setVisibility(View.GONE); 
mHeaderViewDateView.setText("更新于:" + dateFormat.format(new Date(System.currentTimeMillis()))); 
setHeaderHeight(0); 
showFooterView(); 
return; 


case WHAT_SET_HEADER_HEIGHT :{ 
setHeaderHeight(mHeaderIncremental); 
return; 


case WHAT_DID_MORE :{ 
mIsFetchMoreing = false; 
mFooterTextView.setText("更多"); 
mFooterLoadingView.setVisibility(View.GONE); 




}; 

/** 
* 显示脚步脚部文件 
*/ 
private void showFooterView(){ 
if(mListView.getFooterViewsCount() == 0 && isFillScreenItem()){ 
mListView.addFooterView(mFooterView); 
mListView.setAdapter(mListView.getAdapter()); 



/** 
* 条目是否填满整个屏幕 
*/ 
private boolean isFillScreenItem(){ 
final int firstVisiblePosition = mListView.getFirstVisiblePosition(); 
final int lastVisiblePostion = mListView.getLastVisiblePosition() - mListView.getFooterViewsCount(); 
final int visibleItemCount = lastVisiblePostion - firstVisiblePosition + 1; 
final int totalItemCount = mListView.getCount() - mListView.getFooterViewsCount(); 

if(visibleItemCount < totalItemCount) return true; 
return false; 


/* 
* ================================== 
* 实现 OnScrollOverListener接口 


* ================================== 
*/ 

@Override 
public boolean onListViewTopAndPullDown(int delta) { 
if(mIsRefreshing || mListView.getCount() - mListView.getFooterViewsCount() == 0) return false; 

int absDelta = Math.abs(delta); 
final int i = (int) Math.ceil((double)absDelta / 2); 

mHeaderIncremental += i; 
if(mHeaderIncremental >= 0){ // && mIncremental <= mMaxHeight 
setHeaderHeight(mHeaderIncremental); 
checkHeaderViewState(); 

return true; 


@Override 
public boolean onListViewBottomAndPullUp(int delta) { 
if(!mEnableAutoFetchMore || mIsFetchMoreing) return false; 
// 数量充满屏幕才触发 
if(isFillScreenItem()){ 
mIsFetchMoreing = true; 
mFooterTextView.setText("加载更多中..."); 
mFooterLoadingView.setVisibility(View.VISIBLE); 
mOnPullDownListener.onMore(); 
return true; 

return false; 


@Override 
public boolean onMotionDown(MotionEvent ev) { 
mIsDown = true; 
mIsPullUpDone = false; 
mMotionDownLastY = ev.getRawY(); 
return false; 


@Override 
public boolean onMotionMove(MotionEvent ev, int delta) { 
//当头部文件回推消失的时候,不允许滚动 
if(mIsPullUpDone) return true; 

// 如果开始按下到滑动距离不超过误差值,则不滑动 
final int absMotionY = (int) Math.abs(ev.getRawY() - mMotionDownLastY); 
if(absMotionY < START_PULL_DEVIATION) return true; 

final int absDelta = Math.abs(delta); 
final int i = (int) Math.ceil((double)absDelta / 2); 

// onTopDown在顶部,并上回推和onTopUp相对 
if(mHeaderViewParams.height > 0 && delta < 0){ 
mHeaderIncremental -= i; 
if(mHeaderIncremental > 0){ 
setHeaderHeight(mHeaderIncremental); 
checkHeaderViewState(); 
}else{ 
mHeaderViewState = HEADER_VIEW_STATE_IDLE; 
mHeaderIncremental = 0; 
setHeaderHeight(mHeaderIncremental); 
mIsPullUpDone = true; 

return true; 

return false; 


@Override 
public boolean onMotionUp(MotionEvent ev) { 
mIsDown = false; 
// 避免和点击事件冲突 
if(mHeaderViewParams.height > 0){ 
// 判断头文件拉动的距离与设定的高度,小了就隐藏,多了就固定高度 
int x = mHeaderIncremental - DEFAULT_HEADER_VIEW_HEIGHT; 
Timer timer = new Timer(true); 
if(x < 0){ 
timer.scheduleAtFixedRate(new HideHeaderViewTask(), 0, 10); 
}else{ 
timer.scheduleAtFixedRate(new ShowHeaderViewTask(), 0, 10); 

return true; 

return false; 




3. xml布局文件Layout中的定义 
pulldown_footer.xml 
<?xml version="1.0" encoding="utf-8"?> 
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:paddingBottom="10dp" 
    android:paddingTop="10dp" > 

    <TextView 
        android:id="@+id/pulldown_footer_text" 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:layout_centerInParent="true" 
        android:text="更多" 
        android:textSize="15dp" /> 

    <ProgressBar 
        android:id="@+id/pulldown_footer_loading" 
        style="@android:style/Widget.ProgressBar.Small" 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:layout_centerVertical="true" 
        android:layout_marginLeft="20dp" 
        android:visibility="gone" /> 

</RelativeLayout> 

pulldown_header.xml 
<?xml version="1.0" encoding="utf-8"?> 
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:paddingBottom="10dp" 
    android:paddingTop="10dp" > 

    <ImageView 
        android:id="@+id/pulldown_header_arrow" 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:layout_alignParentLeft="true" 
        android:layout_marginLeft="20dp" 
        android:scaleType="centerCrop" 
        android:src="@drawable/z_arrow_down" 
        android:visibility="invisible" /> 

    <LinearLayout 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:layout_alignBottom="@+id/pulldown_header_arrow" 
        android:layout_alignTop="@+id/pulldown_header_arrow" 
        android:layout_centerHorizontal="true" 
        android:gravity="center_vertical" 
        android:orientation="vertical" > 

        <TextView 
            android:id="@+id/pulldown_header_text" 
            android:layout_width="wrap_content" 
            android:layout_height="wrap_content" 
            android:layout_gravity="center_horizontal" 
            android:text="加载中..." /> 

        <TextView 
            android:id="@+id/pulldown_header_date" 
            android:layout_width="wrap_content" 
            android:layout_height="wrap_content" 
            android:layout_gravity="center_horizontal" 
            android:text="更新于:" 
            android:visibility="gone" /> 
    </LinearLayout> 

    <ProgressBar 
        android:id="@+id/pulldown_header_loading" 
        style="@android:style/Widget.ProgressBar.Small" 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:layout_centerVertical="true" 
        android:layout_marginLeft="20dp" /> 

</RelativeLayout> 

调用自定义的PullDownView部分布局文件 
um_information_activity.xml 
<?xml version="1.0" encoding="utf-8"?> 
<RelativeLayout android:background="#FFFFFF" android:layout_width="fill_parent" android:layout_height="fill_parent" 
  xmlns:android="http://schemas.android.com/apk/res/android"> 
... 
<com.drawthink.nxjobhunting.ui.components.PullDownView 
    android:id="@+id/latest_list" 
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent" 
    android:paddingLeft="10dp" 
    android:paddingRight="10dp" 
    android:background="@android:color/white" 
    android:layout_below="@id/category_layout" 
    > 

</com.drawthink.nxjobhunting.ui.components.PullDownView> 
</RelativeLayout> 

4. Activity文件 
JobsInformationActivity 
package com.drawthink.nxjobhunting.ui; 

import java.util.ArrayList; 
import java.util.List; 

import android.content.Intent; 
import android.os.Bundle; 
import android.os.Message; 
import android.text.TextUtils; 
import android.view.View; 
import android.widget.AdapterView; 
import android.widget.AdapterView.OnItemClickListener; 
import android.widget.Button; 
import android.widget.EditText; 
import android.widget.ExpandableListView; 
import android.widget.ExpandableListView.OnChildClickListener; 
import android.widget.LinearLayout; 
import android.widget.ListView; 
import android.widget.RelativeLayout; 

import com.drawthink.nxjobhunting.R; 
import com.drawthink.nxjobhunting.handler.HandlerManager; 
import com.drawthink.nxjobhunting.http.response.CateListRespProcessor; 
import com.drawthink.nxjobhunting.http.response.LatestJobsRespProcessor; 
import com.drawthink.nxjobhunting.logic.CategoryManager; 
import com.drawthink.nxjobhunting.logic.JobsManager; 
import com.drawthink.nxjobhunting.ui.adapter.CategoryExpListAdapter; 
import com.drawthink.nxjobhunting.ui.adapter.JobsListAdapter; 
import com.drawthink.nxjobhunting.ui.components.PullDownView; 
import com.drawthink.nxjobhunting.ui.components.PullDownView.OnPullDownListener; 
import com.drawthink.nxjobhunting.utils.Constants; 
import com.drawthink.nxjobhunting.utils.GlobalKeys; 
import com.drawthink.nxjobhunting.vo.CategoryItem; 
import com.drawthink.nxjobhunting.vo.JobInfo; 

public class JobsInformationActivity extends BaseActivity implements OnPullDownListener, OnItemClickListener{
public static enum TabIndex{ 
LATEST, 
FULL_TIME, 
PART_TIME 


private CategoryManager mManager; 
private JobsManager jobManager; 
// private ToolBar mToolBar; 
private Button latest; 
private Button fullTime; 
private Button partTime; 
private CategoryExpListAdapter mAdapter; 
private ExpandableListView exListV; 
private Button searchBtn; 
private EditText searchInput; 
private LinearLayout catelogL; 
private RelativeLayout loadingL; 

//最新职位列表 
private PullDownView mPullDownView; 
private ListView mListView; 
private JobsListAdapter jobListAdapter; 
private List<JobInfo> listData; 

private TabIndex tabIndex = TabIndex.LATEST; 

private String lastRecTime = ""; 

//keep category list in memory 
public static List<CategoryItem> fullTimeGList = null; 


public static List<CategoryItem> partTimeGList = null; 


private OnChildClickListener childListener = new OnChildClickListener() { 

@Override 
public boolean onChildClick(ExpandableListView parent, View v, 
int groupPosition, int childPosition, long id) { 
Intent intent = new Intent(JobsInformationActivity.this, JobsListActivity.class); 
intent.putExtra(GlobalKeys.CATEGORY_ID, id); 
startActivity(intent); 
return false; 


}; 
public void onCreate(Bundle bundle) { 
super.onCreate(bundle); 

setView(R.layout.um_information_activity); 
setTitle(getString(R.string.job_info_main)); 
setTitleBar(R.drawable.home_back, "", 0, ""); 

// mToolBar = (ToolBar) findViewById(R.id.tool_bar); 
// mToolBar.setSelection(3); 
latest = (Button) findViewById(R.id.latest); 
fullTime = (Button) findViewById(R.id.fulltime); 
partTime = (Button) findViewById(R.id.parttime); 

fullTime.setOnClickListener(this); 
partTime.setOnClickListener(this); 
latest.setOnClickListener(this); 

latest.requestFocus(); 

mPullDownView =  (PullDownView) findViewById(R.id.latest_list); 
mPullDownView.setOnPullDownListener(this); 
mListView = mPullDownView.getListView(); 

jobListAdapter = new JobsListAdapter(this); 
mListView.setAdapter(jobListAdapter); 
mListView.setOnItemClickListener(this); 
        
        mPullDownView.enableAutoFetchMore(false, 1); 
        
catelogL = (LinearLayout) findViewById(R.id.category_layout); 

exListV = (ExpandableListView) findViewById(R.id.categoryList); 
exListV.setGroupIndicator(null); 

loadingL = (RelativeLayout) findViewById(R.id.loading); 

mAdapter = new CategoryExpListAdapter(this); 
exListV.setAdapter(mAdapter); 
exListV.setOnChildClickListener(childListener); 

searchBtn = (Button) findViewById(R.id.search); 
searchInput = (EditText) findViewById(R.id.search_input); 

searchBtn.setOnClickListener(this); 

mManager = new CategoryManager(); 
jobManager = new JobsManager(); 

HandlerManager.handlerMap.put(HandlerManager.KEY_CATEGORY, mHandler); 

// mManager.getCategoryList(1); 

// if(mProgressDialog == null) { 
// mProgressDialog = ProgressDialog.show(this, "", "正在加载,请稍后..."); 
// } 
jobManager.getLatestJobs(lastRecTime); 



@Override 
public void handleClick(int buttonId) { 
switch (buttonId) { 

case R.id.latest: 
if (tabIndex == TabIndex.LATEST) { 
return; 

//设置背景色 
latest.setBackgroundResource(R.drawable.zuixin2); 
fullTime.setBackgroundResource(R.drawable.quanzhi2); 
partTime.setBackgroundResource(R.drawable.jianzhi2); 
catelogL.setBackgroundResource(R.drawable.zhiwei_bj1); 

if (mPullDownView.getVisibility() == View.GONE) { 
exListV.setVisibility(View.GONE); 
mPullDownView.setVisibility(View.VISIBLE); 

tabIndex = TabIndex.LATEST; 
if (loadingL.getVisibility() == View.VISIBLE) { 
loadingL.setVisibility(View.GONE); 

// mManager.getCategoryList(1); 
// if(mProgressDialog == null) { 
// mProgressDialog = ProgressDialog.show(this, "", "正在加载,请稍后..."); 
// } 
break; 
case R.id.fulltime: 
if (tabIndex == TabIndex.FULL_TIME) { 
return; 

//设置背景色 
latest.setBackgroundResource(R.drawable.zuixin1); 
fullTime.setBackgroundResource(R.drawable.quanzhi1); 
partTime.setBackgroundResource(R.drawable.jianzhi2); 
catelogL.setBackgroundResource(R.drawable.zhiwei_bj2); 

if (fullTimeGList == null) { 
loadingL.setVisibility(View.VISIBLE); 
exListV.setVisibility(View.GONE); 
mManager.getCategoryList(1); 
} else { 
if (loadingL.getVisibility() == View.VISIBLE) { 
loadingL.setVisibility(View.GONE); 

exListV.setVisibility(View.VISIBLE); 
mAdapter.setData(fullTimeGList); 

if (tabIndex == TabIndex.LATEST) { 
exListV.setVisibility(View.VISIBLE); 
mPullDownView.setVisibility(View.GONE); 


tabIndex = TabIndex.FULL_TIME; 


// if(mProgressDialog == null) { 
// mProgressDialog = ProgressDialog.show(this, "", "正在加载,请稍后..."); 
// } 
break; 
case R.id.parttime: 
if (tabIndex == TabIndex.PART_TIME) { 
return; 

latest.setBackgroundResource(R.drawable.zuixin1); 
fullTime.setBackgroundResource(R.drawable.quanzhi2); 
partTime.setBackgroundResource(R.drawable.jianzhi1); 
catelogL.setBackgroundResource(R.drawable.zhiwei_bj3); 

if (partTimeGList == null) { 
loadingL.setVisibility(View.VISIBLE); 
exListV.setVisibility(View.GONE); 
mManager.getCategoryList(2); 
} else { 
if (loadingL.getVisibility() == View.VISIBLE) { 
loadingL.setVisibility(View.GONE); 

exListV.setVisibility(View.VISIBLE); 
mAdapter.setData(partTimeGList); 


if (tabIndex == TabIndex.LATEST) { 
exListV.setVisibility(View.VISIBLE); 
mPullDownView.setVisibility(View.GONE); 


tabIndex = TabIndex.PART_TIME; 
// if(mProgressDialog == null) { 
// mProgressDialog = ProgressDialog.show(this, "", "正在加载,请稍后..."); 
// } 
break; 
case R.id.search: 
final String keyword = searchInput.getText().toString(); 
if (!TextUtils.isEmpty(keyword)) { 
Intent intent = new Intent(Constants.ACTION_SEARCH); 
intent.putExtra(GlobalKeys.KEYWORD, keyword); 
startActivity(intent); 


break; 



public void onMessage(Message msg) { 
switch (msg.what) { 
case LatestJobsRespProcessor.MSG_REFRESH_JOBS: 
List<JobInfo> list = (List<JobInfo>)msg.obj; 
boolean isFirstLoad = "".equals(lastRecTime); 
if (list.size() > 0) { 
lastRecTime = list.get(0).date; 
jobListAdapter.addDataToFront(list); 

if (isFirstLoad) { 
mPullDownView.notifyDidLoad(); 
} else { 
mPullDownView.notifyDidRefresh(); 


break; 
case CateListRespProcessor.MSG_REFRESH: 
List<CategoryItem> itemList = (List<CategoryItem>)msg.obj; 
mAdapter.setData(itemList); 

if (tabIndex == TabIndex.FULL_TIME) { 
fullTimeGList = itemList; 
} else if (tabIndex == TabIndex.PART_TIME) { 
partTimeGList = itemList; 


if (mProgressDialog != null) { 
mProgressDialog.cancel(); 
mProgressDialog = null; 


if (mPullDownView.getVisibility() == View.VISIBLE) { 
mPullDownView.setVisibility(View.GONE); 


if (loadingL.getVisibility() == View.VISIBLE) { 
loadingL.setVisibility(View.GONE); 


exListV.setVisibility(View.VISIBLE); 

break; 



@Override 
protected void onLeftAction() { 
finish(); 



@Override 
protected void onRightAction() { 




@Override 
public void onMore() { 
mPullDownView.notifyDidMore(); 



@Override 
public void onItemClick(AdapterView<?> adapter, View view, int position, long id) { 
Intent intent = new Intent(this, JobDetailActivity.class); 
intent.putExtra("id", (int)id); 
JobInfo info = (JobInfo) adapter.getItemAtPosition(position); 
intent.putExtra("title", info.title); 
intent.putExtra("number", info.num); 
startActivity(intent); 



@Override 
public void onRefresh() { 
jobManager.getLatestJobs(lastRecTime); 
mListView.setSelection(-1); 




其中onRefresh异步调用网络数据, 在onMessage中返回, 更新列表数据。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值