展会信息港展会大全

Android实现ListView头部和尾部可伸展并回弹功能
来源:互联网   发布日期:2015-11-26 13:15:06   浏览:4761次  

导读:一、大致的实现思路 给ListView添加HeadView和FootView,当ListView滑动至列表第一项时使HeadView滑动出现,当ListView滑动至列表最后一项时使Foo...

一、大致的实现思路

给ListView添加HeadView和FootView,当ListView滑动至列表第一项时使HeadView滑动出现,当ListView滑动至列表最后一项时使FootView滑动出现。HeadView和FootView的高度取决于用户手指滑动的距离(ACTION_MOVE初始时记录startPullDownY=event.getY(),startPullUpY=event.getY(),ACTION_MOVE结束时计算手指的总滑动距离moveDownY=event.getY()

- startPullDownY(),moveUpY=startPullUpY()-event.getY()),然后刷新HeadView和FootView的高度至moveDownY*0.5(moveUpY*0.5),取值0.5是为了让用户感觉到视图滑动视差,形成一种平滑滑动的感觉。当用户滑动完毕放开手指时,调用任务调度类ScheduledExecutorService,实现HeadView和FootView的平滑回弹。

二、实现关键代码

添加HeadView和FootView

/**

* 初始化

*/

@SuppressWarnings("deprecation")

private void init(boolean isHeadViewNeed, boolean isTailViewNeed) {

Log.d(TAG, "isHeadViewNeed=" + isHeadViewNeed);

Log.d(TAG, "isTailViewNeed=" + isTailViewNeed);

if(isHeadViewNeed) {

// 监听滚动状态

setOnScrollListener(this);

// 创建PullListView的HeadView

mHeadView = new View(this.getContext());

// 默认白色背景,可以改变颜色, 也可以设置背景图片

mHeadView.setBackgroundColor(Color.parseColor("#4F9D9D"));

// 默认高度为0

mHeadView.setLayoutParams(new AbsListView.LayoutParams(

LayoutParams.FILL_PARENT, 0));

this.addHeaderView(mHeadView);

}

if(isTailViewNeed) {

// 监听滚动状态

setOnScrollListener(this);

// 创建PullListView的HeadView

mTailView = new View(this.getContext());

// 默认白色背景,可以改变颜色, 也可以设置背景图片

mTailView.setBackgroundColor(Color.parseColor("#4F9D9D"));

// 默认高度为0

mTailView.setLayoutParams(new AbsListView.LayoutParams(

LayoutParams.FILL_PARENT, 0));

this.addFooterView(mTailView);

}

}

重写ListView的onTouchEvent事件

/**

* 覆盖onTouchEvent方法,实现下拉回弹效果

*/

@SuppressWarnings("deprecation")

@Override

public boolean onTouchEvent(MotionEvent event) {

switch (event.getAction()) {

case MotionEvent.ACTION_DOWN:

break;

case MotionEvent.ACTION_CANCEL:

case MotionEvent.ACTION_UP:

if (!isRecordPullDown && !isRecordPullUp) {

// it's not in pull down state or pull up state, break

Log.d(TAG, "ACTION_UP it's not in pull down state or pull up state, break");

break;

}

if(isPullDownState()) {

Log.d(TAG, "isRecordPullDown=" + isRecordPullDown);

// 以一定的频率递减HeadView的高度,实现平滑回弹

schedulor = Executors.newScheduledThreadPool(1);

schedulor.scheduleAtFixedRate(new Runnable() {

@Override

public void run() {

mHandler.sendEmptyMessage(PULL_DOWN_BACK_ACTION);

}

}, 0, PULL_BACK_TASK_PERIOD, TimeUnit.NANOSECONDS);

setPullDownState(!isRecordPullDown);

} else if(isPullUpState()) {

Log.d(TAG, "isRecordPullUp=" + isRecordPullUp);

// 以一定的频率递减HeadView的高度,实现平滑回弹

schedulor = Executors.newScheduledThreadPool(1);

schedulor.scheduleAtFixedRate(new Runnable() {

@Override

public void run() {

mHandler.sendEmptyMessage(PULL_UP_BACK_ACTION);

}

}, 0, PULL_BACK_TASK_PERIOD, TimeUnit.NANOSECONDS);

setPullUpState(!isRecordPullUp);

}

break;

case MotionEvent.ACTION_MOVE:

Log.d(TAG, "firstItemIndex=" + firstItemIndex);

if (!isRecordPullDown && firstItemIndex == 0) {

Log.d(TAG, "firstItemIndex=" + firstItemIndex + " set isRecordPullDown=true");

startPullDownY = (int) event.getY();

setPullType(PULL_DOWN_BACK_ACTION);

}else if (!isRecordPullUp && lastItemIndex == getCount()) {

Log.d(TAG, "lastItemIndex == getCount()" + " set isRecordPullUp=true");

startPullUpY = (int) event.getY();

setPullType(PULL_UP_BACK_ACTION);

}

if (!isRecordPullDown && !isRecordPullUp) {

// it's not in pull down state or pull up state, break

Log.d(TAG, "ACTION_MOVE it's not in pull down state or pull up state, break");

break;

}

if(isRecordPullDown) {

int tempY = (int) event.getY();

int moveY = tempY - startPullDownY;

if (moveY

使用Handler完成HeadView和FootView的回弹效果

/**

* 实现回弹效果的handler,用于递减HeadView的高度并请求重绘

*/

@SuppressLint("HandlerLeak")

private Handler mHandler = new Handler() {

@Override

public void handleMessage(Message msg) {

super.handleMessage(msg);

switch(msg.what) {

case PULL_DOWN_BACK_ACTION:

AbsListView.LayoutParams headerParams = (LayoutParams) mHeadView

.getLayoutParams();

// 递减高度

headerParams.height -= PULL_BACK_REDUCE_STEP;

mHeadView.setLayoutParams(headerParams);

// 重绘

mHeadView.invalidate();

// 停止回弹时递减headView高度的任务

if (headerParams.height

重写ListView的onScroll方法和onScrollStateChanged方法

@Override

public void onScroll(AbsListView view, int firstVisiableItem,

int visibleItemCount, int totalItemCount) {

this.firstItemIndex = firstVisiableItem;

this.lastItemIndex = firstVisiableItem + visibleItemCount;

}

@Override

public void onScrollStateChanged(AbsListView view, int scrollState) {

currentScrollState = scrollState;

Log.d(TAG, "scrollState: " + getScrollStateString(currentScrollState));

}

private String getScrollStateString(int flag) {

String str = "";

switch(flag) {

case OnScrollListener.SCROLL_STATE_IDLE:

str = "SCROLL_STATE_IDLE";

break;

case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:

str = "SCROLL_STATE_TOUCH_SCROLL";

break;

case OnScrollListener.SCROLL_STATE_FLING:

str = "SCROLL_STATE_FLING";

break;

default:

str = "wrong state";

}

return str;

}三、实现效果图

赞助本站

人工智能实验室

相关热词: android开发 教程

AiLab云推荐
展开

热门栏目HotCates

Copyright © 2010-2024 AiLab Team. 人工智能实验室 版权所有    关于我们 | 联系我们 | 广告服务 | 公司动态 | 免责声明 | 隐私条款 | 工作机会 | 展会港