listview反弹实现详解
重写listview,通过监听滑动事件,根据滑动时所处的位置,以及滑动的方向,使用view的内置scrollTo或scrollBy函数来移动view到你手势互动的距离(此处为一半),然后当确定消费了给事件后,又回滚到(0,0)点。当然只有在超出了边界时才回滚。而且回滚的过程由TranslateAnimation来控制,这样的好处在代码的解释中。我是基于网络上的listviewpress改了一些(有几处好像是被篡改了,我又按我的理解将它改正过来,运行后没问题)。一下是关键的代码,整个代码见附件中。有不懂的可以问问,大家互相学习。
?
?
?
*重合y轴,就好像整个布局被往左拉动。 * y为正,则向上滑动|y|距离。负则相反。 */scrollBy(0, distance / 2);Log.v("onScroll", "e2.getRawY():"+e2.getRawY());Log.v("onScroll", "distance:"+distance);Log.v("onScroll", "distanceY:"+distanceY);return true;}if (lastView == null&&(outBound || (lastPos == itemCount - 1 && distanceY > 0))) {Log.d("bottom", "bottom");distance = (int) (firstOut - e2.getRawY());//此处应为正直,因为view向上滑动scrollBy(0, distance/2);return true;}return false;}public void onShowPress(MotionEvent e) {// TODO Auto-generated method stub}public boolean onSingleTapUp(MotionEvent e) {// TODO Auto-generated method stubreturn false;}});/** * 最早响应触屏事件,按下和释放响应两次 */public boolean dispatchTouchEvent(MotionEvent ev) {if(getFirstVisiblePosition()==0){int act = ev.getAction();if ((act == MotionEvent.ACTION_UP || act == MotionEvent.ACTION_CANCEL)&& outBound) {outBound = false;}if (!gestureDetector.onTouchEvent(ev)) {outBound = false;} else {outBound = true;}Rect rect = new Rect();getLocalVisibleRect(rect);/** * rect.top是个正的距离值,而TanslateAnimation填的是坐标值(有方向的); */TranslateAnimation am = new TranslateAnimation(0, 0, -rect.top, 0);/** * 若此处时间设为0,将导致一阵的抖动,因为完成回滚的速度不是分步,而是直接到终点 * 因为每次触发onScroll时都会做一次回滚,而当传进又一次move时,上一次的move还没作完 * 就将被新的一次覆盖,所以不用担心产生抖动。所以此处给它设时间就是抓住它需要时间来完成回滚的目标,相当 * 于给它一个时间的缓冲来实现移动,因为当你在移动时,实际是不需要回滚的,只有你释放了手指还才需要回滚。 * 注意,此时调用scrollTo已经将位置返回了0(可以把animation当成是模型,只有使用scrollTo才 * 能真正触发该移动,结果是已经知道了的,即移动到原点,而过程是TranslateAnimation参谋的,即 * scrollTo在移动时会调用onScrollChange来实际移动,而onScrollChange则根据传入的参数来移动 * 而TranslateAnimation则可以控制该参数。可以把scrollTo先去掉,就可以发现new top 和 * after scrollBy是一样的值)。也就是new Top=0。所以每次迭代相减都是现在的e2减去最初的e2在y轴上的值, * 这样通过scrollBy就可以将view移动到新的位置,而此时top也就又被写成了新的滑动的位置(是滑动距离的一半位置)。 * 11-19 23:51:11.101: V/onScroll(18396): after scrollBy top:011-19 23:51:11.101: V/onScroll(18396): new top:011-19 23:51:11.249: V/onScroll(18396): after scrollBy top:011-19 23:51:11.249: V/onScroll(18396): new top:011-19 23:51:11.288: V/onScroll(18396): after scrollBy top:-611-19 23:51:11.288: V/onScroll(18396): new top:011-19 23:51:11.319: V/onScroll(18396): after scrollBy top:-1611-19 23:51:11.319: V/onScroll(18396): new top:011-19 23:51:11.358: V/onScroll(18396): after scrollBy top:-2011-19 23:51:11.358: V/onScroll(18396): new top:011-19 23:51:11.374: V/onScroll(18396): after scrollBy top:-2711-19 23:51:11.374: V/onScroll(18396): new top:0 */am.setDuration(300);startAnimation(am);Log.v("onScroll","after scrollBy top:"+rect.top);scrollTo(0, 0);getLocalVisibleRect(rect); Log.v("onScroll", "new top:"+rect.top);}Log.d("getLastVisiblePosition()", getLastVisiblePosition()+"");Log.d("getCount()", getCount()+"");if(getLastVisiblePosition()==getCount()-1){int act = ev.getAction();if ((act == MotionEvent.ACTION_DOWN || act == MotionEvent.ACTION_CANCEL)&& outBound) {outBound = false;}if (!gestureDetector.onTouchEvent(ev)) {outBound = false;} else {outBound = true;}if(outBound){Rect rect1 = new Rect();getLocalVisibleRect(rect1);TranslateAnimation am1 = new TranslateAnimation(0, 0, rect1.top, 0);am1.setDuration(300);startAnimation(am1);scrollTo(0, 0);}}return super.dispatchTouchEvent(ev);};}1 楼 真心等候 2012-06-09 想做这样的功能久了。感谢