重写继承ListView后,其实本质就是两点:
(1)弹簧:利用View的scrollTo(int x, int y)方法来搞定弹簧;
(2)动态的加入和删除Header;
(3)Scroller滚动的方向和手指滑动的方向是相反的。
下面是 例子:
(1)MainActivity.class
package com.habby.sliderbar;
import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import com.habby.sliderbar.SpringListView.SpringListener;
public class MainActivity extends Activity implements OnClickListener {
private final String TAG = getClass().getSimpleName();
private final int COMPLETED = 1; // 已完成
private SpringListView mListView = null;
private SpringListener mSpringListener = null;
private List<String> mDatas;
private ArrayAdapter<String> mAdapter;
private View mHeader1 = null;
private View mHeader2 = null;
private Handler mListener = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == COMPLETED) {
if (mListView.getHeaderViewsCount() != 0) {
mListView.removeHeaderView(mHeader2);
}
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
@Override
public void onClick(View view) {
switch (view.getId()) {
default:
break;
}
}
private void initView() {
mListView = (SpringListView) findViewById(R.id.name_lv);
mDatas = new ArrayList<String>();
for (int i = 0; i < 25; ++i) {
mDatas.add("fuck you");
}
mAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, mDatas);
mHeader1 = LayoutInflater.from(this).inflate(R.layout.slider_view, null);
mHeader2 = LayoutInflater.from(this).inflate(R.layout.right_view, null);
/**
* 这应该是一个bug,必须在setAdapter之前addHeaderView,然后再removeHeaderView,这
* 样才能动态的加入和删除header。
*/
mListView.addHeaderView(mHeader1);
mListView.setAdapter(mAdapter);
mListView.removeHeaderView(mHeader1);
mSpringListener = new SpringListener() {
@Override
public void onSpringUpPush() {
Log.e(TAG, "UpPush !");
}
@Override
public void onSpringDownPush() {
Log.e(TAG, "DownPush");
if (mListView.getHeaderViewsCount() == 0) {
mListView.addHeaderView(mHeader1);
}
}
@Override
public void onSpringCompleted() {
Log.e(TAG, "Completed !");
if (mListView.getHeaderViewsCount() != 0) {
mListView.removeHeaderView(mHeader1);
mListView.addHeaderView(mHeader2);
mListener.obtainMessage(COMPLETED).sendToTarget();
}
}
};
mListView.registerSpringListener(mSpringListener);
}
}
(2)SpringListView.class
package com.habby.sliderbar;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ListView;
/**
* 针对一个带上拉/下拉弹簧效果的ListView,比普通的ListView仅仅多了弹簧效果而已;
* 因此,可以重写ListView,添加弹簧效果即可,其他的行为依旧是默认的ListView行为。
* 子线程用于处理 “弹回” 效果。
* @author habby
*/
public class SpringListView extends ListView implements Runnable {
private float mLastDownY = 0f;
private int mDistance = 0; // 手指/弹簧拉去移动的距离
private int mStep = 10;
private boolean mPositive = false; // 滚动方向
private SpringListener mListener;
public SpringListView(Context ctx, AttributeSet attrs) {
super(ctx, attrs);
}
public SpringListView(Context ctx, AttributeSet attrs, int defStyle) {
super(ctx, attrs, defStyle);
}
public SpringListView(Context ctx) {
super(ctx);
}
@Override
public void onFinishInflate() {
}
/**
* 只有满足这个情况才会有下拉弹簧:
* 当按下时,ListView可以显示的第1行是处于顶部第1个或底部最后1个时,下拉或上拉才有弹簧效果。
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if (getFirstVisiblePosition() == 0 || getLastVisiblePosition() == getCount() - 1) {
mLastDownY = event.getY();
return true;
}
mDistance = 0;
break;
case MotionEvent.ACTION_MOVE: // 拉伸
mDistance = (int) (mLastDownY - event.getY());
if ((mDistance < 0 && (getFirstVisiblePosition() == 0)) || (mDistance > 0 && (getLastVisiblePosition() == getCount() - 1))) {
mDistance /= 2;
scrollTo(0, mDistance);
if (mListener != null) {
if (mDistance < 0) {
mListener.onSpringDownPush();
} else if (mDistance > 0) {
mListener.onSpringUpPush();
}
}
return true;
}
mDistance = 0;
break;
case MotionEvent.ACTION_UP: // 松手的时候,弹回来
if ((mDistance < 0 && getFirstVisiblePosition() == 0) || (mDistance > 0 && getLastVisiblePosition() == getCount() - 1)) {
mStep = 1;
mPositive = (mDistance >= 0);
this.post(this); // 启动子线程,用于 "弹回" 效果
return true;
}
mDistance = 0;
break;
default:
break;
}
// 其他情况使用ListView(父类)本身的行为,不覆盖。这里仅仅是覆盖了ListView以上的2中情况。
return super.onTouchEvent(event);
}
@Override
public void run() {
mDistance += mDistance > 0 ? -mStep : mStep;
scrollTo(0, mDistance);
if ((mPositive && mDistance <= 0) || (!mPositive && mDistance >= 0)) {
scrollTo(0, 0);
mDistance = 0;
mLastDownY = 0f;
if (mListener != null) {
mListener.onSpringCompleted();
}
return;
}
mStep += 5;
this.postDelayed(this, 10);
}
public void registerSpringListener(SpringListener listener) {
mListener = listener;
}
/**
* 回调接口
*/
public interface SpringListener {
public void onSpringDownPush(); // 下拉
public void onSpringUpPush(); // 上拉
public void onSpringCompleted(); //"回弹" 完成
}
}