重写继承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();	//"回弹" 完成
    }
}



更多相关文章

  1. Android从零开搞系列:自定义View(15)仿天天美剧拖动卡片的效果(下)
  2. javascript实现拖动层效果代码(许愿墙)
  3. spring data RedisTemplate无效果

随机推荐

  1. RelativeLayout的一些布局属性
  2. android 上 webkit js 扩展之全局本地对
  3. Android 消息机制之Message
  4. Android Layout XML属性
  5. 源码茶舍之android:externalService是什
  6. Android如何设置圆角按钮 类似微信的登陆
  7. Android学习路线
  8. JPCT-AE for Android 3D (一)----------H
  9. Android 进程间通信:AIDL
  10. 前端h5与 Android/iOS 交互传参