`
hunankeda110
  • 浏览: 741763 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论
收藏列表
标题 标签 来源
管理
狮子让一只豹子管理10只狼,并给他们分发食物。豹子领到肉之后,把肉平均分成了11份,自己要了一份,其他给了10只狼。这10只狼都感觉自己分的少,合起伙来跟豹子唱对台戏。虽然一只狼打不过豹子,但10只狼豹子却没法应付了。 豹子灰溜溜的找狮子辞职。狮子说,看我的。 
    狮子把肉分成了11份,大小不一,自己先挑了最大的一份,然后傲然对其他狼说:你们自己讨论这些肉怎么分。为了争夺到大点的肉,狼群沸腾了,恶狠狠的互相攻击,全然不顾自己连平均的那点肉都没拿到。豹子钦佩的问狮子,这是什么办法? 狮子微微一笑,听说过人类的绩效工资吗?...... 


    第二天,狮子依然把肉分成11块,自己却挑走了2块,然后傲然对其他狼说:你们自己讨论这些肉怎么分。10只狼看了看9块肉,飞快的抢夺起来,一口肉,一口曾经的同伴,直到最后留下一只弱小的狼倒在地上奄奄一息。豹子钦佩的问狮子,这是什么办法? 狮子微微一笑,听说过末位淘汰法吗?...... 


    第三天,狮子把肉分成2块,自己却挑走了1块,然后傲然对其他狼说:你们自己讨论这些肉怎么分。群狼争夺起来,最后一只最强壮的狼打败所有狼,大摇大摆的开始享用它的 战利品。
    狼吃饱以后才允许其它狼再来吃,这些狼都成了它的小弟,恭敬的服从它的管理,按照顺序来享用它的残羹。从此狮子只需管理一只狼,只需分配给它食物,其它的再不操心 豹子钦佩的问狮子,这是什么办法?狮子微微一笑,听说过竞争上岗吗?...... 
 
    第四天,狮子把肉分成5份,自己拿了3份,然后把1份分成9小份,对狼们说:每个都领一小份,我考察你们,最后决定最优秀的可以额外获得那份最大的。然后狼群们迅速拿了各自的那块,各自考虑了一番,有些狼拿出来了自己那份的一部分来给狮子,有只狼把全 部都上交给了狮子,却换回来的优秀员工奖励——那块大肉。狮子得到了全部80%的肉。豹子佩服得五体投地,问狮子这是什么计策? 狮子微微一笑,听说过官场规则吗?..... 


    最后一天,狮子把肉全占了,然后让狼去吃草。因为之前的竞争,狼群已经无力再战了,于是只好逆来顺受。豹子钦佩的问狮子,这是什么。办法? 狮子微微一笑,听说过和谐社会吗?
 
android上下拉刷新
最 近做的类似于微博的项目中,有个Android功能要使用到listview的向下拉刷新来刷新最新消息,向上拉刷新(滑动分页)来加载更多。
新浪微博就是使用这种方式的典型。
当用户从网络上读取微博的时候,如果一下子全部加载用户未读的微博这将耗费比较长的时间,造成不好的用户体验,同时一屏的内容也不足以显示如此多的内容。这时候,我们就需要用到另一个功能,那就是listview的分页了,其实这个分页可以做成客户端的分页,也可以做成服务器端的分页(点击加载时,从服务器对应的加载第N页就好了!!!)。通过分页分次加载数据,用户看多少就去加载多少。
 通常这也分为两种方式,一种是设置一个按钮,用户点击即加载。另一种是当用户滑动到底部时自动加载。今天我就和大家分享一下滑动到底端时自动加载这个功能的实现。
效果图如下所示:


 下拉刷新最主要的流程是:
(1). 下拉,显示提示头部界面(HeaderView),这个过程提示用户”下拉刷新”
(2). 下拉到一定程度,超出了刷新最基本的下拉界限,我们认为达到了刷新的条件,提示用户可以”松手刷新”了,效果上允许用户继续下拉
(3). 用户松手,可能用户下拉远远不止提示头部界面,所以这一步,先反弹回仅显示提示头部界面,然后提示用户”正在加载”。
(4). 加载完成后,隐藏提示头部界面。

那么让我们看看怎么才能实现呢???
第一步:既然是要显示listview ,那么就应该有个listview 的容器pulldown.xml

<?xml version="1.0" encoding="utf-8"?>

<com.solo.pulldown.PullDownView xmlns:android="http://schemas.android.com/apk/res/android"

android:id="@+id/pull_down_view"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:background="@android:color/white">

 

</com.solo.pulldown.PullDownView> 


第二步:自定义一个listview中显示的item对象pulldown_item.xml

<?xml version="1.0" encoding="utf-8"?>

<TextView xmlns:android="http://schemas.android.com/apk/res/android"

android:id="@android:id/text1"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:textAppearance="?android:attr/textAppearanceLarge"

android:gravity="center_vertical"

android:paddingLeft="6dip"

android:minHeight="?android:attr/listPreferredItemHeight"

android:textColor="@android:color/black"

/> 


第三步:定义一个header的xml布局文件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.Inverse"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_centerVertical="true"

android:layout_marginLeft="20dp" />

 

</RelativeLayout> 


第四步:如果需要向上拉更新更多的话,那就定义一个底部的footer的布局文件,在此为方便起见,只定义一个progressbar跟textview,更加复杂的显示,就交给你们了~~~~~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.Inverse"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_centerVertical="true"

android:layout_marginLeft="20dp"

android:visibility="gone" />

 

</RelativeLayout> 


第五步:那么主要的文件这才登场:::::::重写listview这个文件主要任务是提供触摸的事件的处理方法。

/**

 * <p>一个可以监听ListView是否滚动到最顶部或最底部的自定义控件</p>

 * 只能监听由触摸产生的,如果是ListView本身Flying导致的,则不能监听</br>

 * 如果加以改进,可以实现监听scroll滚动的具体位置等

 */

 

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)

*

*/

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);

 

}

 

} 


第六步:下拉刷新控件,真正实现下拉刷新的是这个控件,而上面的那个ScrollOverListView只是提供触摸的事件等



/**

 * 下拉刷新控件</br>

 * 真正实现下拉刷新的是这个控件,

 * ScrollOverListView只是提供触摸的事件等

 */

public class PullDownView extends LinearLayout implements OnScrollOverListener{

private static final String TAG = "PullDownView";

 

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

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

*

* ==================================

*/

 

/**

* 刷新事件接口

*/

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;

mFooterLoadingView.setVisibility(View.VISIBLE);

mOnPullDownListener.onMore();

}

}

});

 

/*

* ScrollOverListView 同样是考虑到都是使用,所以放在这里

* 同时因为,需要它的监听事件

*/

mListView = new ScrollOverListView(context);

mListView.setOnScrollOverListener(this);

mListView.setCacheColorHint(0);

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);

}

 

/**

* 自动隐藏动画

*/

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();

}

}

}

 

/**

* 自动显示动画

*/

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;

}

 

} 


第七步:这个java文件就是封装数据,然后调用上两个文件就好了。废话不多说,上代码:::::


public class PullDownActivity extends Activity implements OnPullDownListener, OnItemClickListener{

 

private static final int WHAT_DID_LOAD_DATA = 0;

private static final int WHAT_DID_REFRESH = 1;

private static final int WHAT_DID_MORE = 2;

 

private ListView mListView;

private ArrayAdapter<String> mAdapter;

 

private PullDownView mPullDownView;

private List<String> mStrings = new ArrayList<String>();

 

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.pulldown);

 

/*

* 1.使用PullDownView

* 2.设置OnPullDownListener

* 3.从mPullDownView里面获取ListView

*/

mPullDownView = (PullDownView) findViewById(R.id.pull_down_view);

mPullDownView.setOnPullDownListener(this);

mListView = mPullDownView.getListView();

 

mListView.setOnItemClickListener(this);

mAdapter = new ArrayAdapter<String>(this, R.layout.pulldown_item, mStrings);

mListView.setAdapter(mAdapter);

 

mPullDownView.enableAutoFetchMore(true, 1);

 

loadData();

}

 

private void loadData(){

new Thread(new Runnable() {

 

@Override

public void run() {

try {

Thread.sleep(2000);

} catch (InterruptedException e) {

e.printStackTrace();

}

List<String> strings = new ArrayList<String>();

for (String body : mStringArray) {

strings.add(body);

}

Message msg = mUIHandler.obtainMessage(WHAT_DID_LOAD_DATA);

msg.obj = strings;

msg.sendToTarget();

}

}).start();

}

 

@Override

public void onRefresh() {

new Thread(new Runnable() {

 

@Override

public void run() {

try {

Thread.sleep(2000);

} catch (InterruptedException e) {

e.printStackTrace();

}

Message msg = mUIHandler.obtainMessage(WHAT_DID_REFRESH);

msg.obj = "After refresh " + System.currentTimeMillis();

msg.sendToTarget();

}

}).start();

}

 

@Override

public void onMore() {

new Thread(new Runnable() {

 

@Override

public void run() {

try {

Thread.sleep(2000);

} catch (InterruptedException e) {

e.printStackTrace();

}

Message msg = mUIHandler.obtainMessage(WHAT_DID_MORE);

msg.obj = "After more " + System.currentTimeMillis();

msg.sendToTarget();

}

}).start();

}

 

private Handler mUIHandler = new Handler(){

 

@Override

public void handleMessage(Message msg) {

switch (msg.what) {

case WHAT_DID_LOAD_DATA:{

if(msg.obj != null){

List<String> strings = (List<String>) msg.obj;

if(!strings.isEmpty()){

mStrings.addAll(strings);

mAdapter.notifyDataSetChanged();

}

}

// 诉它数据加载完毕;

mPullDownView.notifyDidLoad();

break;

}

case WHAT_DID_REFRESH :{

String body = (String) msg.obj;

mStrings.add(0, body);

mAdapter.notifyDataSetChanged();

// 告诉它更新完毕

mPullDownView.notifyDidRefresh();

break;

}

 

case WHAT_DID_MORE:{

String body = (String) msg.obj;

mStrings.add(body);

mAdapter.notifyDataSetChanged();

// 告诉它获取更多完毕

mPullDownView.notifyDidMore();

break;

}

}

 

}

 

};

 

@Override

public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

Toast.makeText(this, "啊,你点中我了 " + position, Toast.LENGTH_SHORT).show();

}

 

// 模拟数据

private String[] mStringArray = {

"Abbaye de Belloc", "Abbaye du Mont des Cats", "Abertam", "Abondance", "Ackawi",

"Acorn", "Adelost", "Affidelice au Chablis", "Afuega'l Pitu", "Airag", "Airedale",

"Aisy Cendre", "Allgauer Emmentaler", "Alverca", "Ambert", "American Cheese"

};

 

} 


整个程序就这么完成了,总之,可以使用前两个封装好的文件,然后,调用就好了~~~~没什么太难的地方。


 
Global site tag (gtag.js) - Google Analytics