橡皮筋的核心思想应该是摩擦力和弹力,下拉的时候模拟出一个摩擦力的效果,松手的时候的时候有个回弹的效果就好了。
Path是将需要有橡皮筋效果的部分做成了ListView的head。在listview的dispatchTouchEvent里进行了处理。
先看下head的布局文件,就是一个ImageView,
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/headView_Main" android:layout_width="match_parent" android:layout_height="wrap_content" > <ImageView android:id="@+id/path_headimage" android:layout_width="fill_parent" android:layout_height="190dp" android:scaleType="center" android:src="@drawable/bg" /> </RelativeLayout>
需要注意的就是 android:scaleType="center"这个属性。也可以是 android:scaleType="centerCrop"。具体变化可以自己动手试下。
下面看下重要的代码部分,自己重写一个ListView:
public class ListViewPro extends ListView { private Context mContext; private Scroller mScroller; int left, top; float startX, startY, currentX, currentY; int bgViewH, iv1W; int rootW, rootH; View headView; View bgView; boolean scrollerType; static final int len = 0xc8; public ListViewPro(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public ListViewPro(Context context, AttributeSet attrs) { super(context, attrs); this.mContext = context; mScroller = new Scroller(mContext); } public ListViewPro(Context context) { super(context); } @Override public boolean dispatchTouchEvent(MotionEvent event) { int action = event.getAction(); if (!mScroller.isFinished()) { return super.onTouchEvent(event); } headView = MainActivity.itemHead1; bgView = headView.findViewById(R.id.path_headimage); currentX = event.getX(); currentY = event.getY(); headView.getTop(); switch (action) { case MotionEvent.ACTION_DOWN: left = bgView.getLeft(); top = bgView.getBottom(); rootW = getWidth(); rootH = getHeight(); bgViewH = bgView.getHeight(); startX = currentX; startY = currentY; break; case MotionEvent.ACTION_MOVE: if (headView.isShown() && headView.getTop() >= 0) { int t = getScrollY(currentY - startY); if (t >= top && t <= headView.getBottom() + len) { bgView.setLayoutParams(new RelativeLayout.LayoutParams(bgView.getWidth(), t)); } scrollerType = false; } break; case MotionEvent.ACTION_UP: scrollerType = true; mScroller.startScroll(bgView.getLeft(), bgView.getBottom(), 0 - bgView.getLeft(), bgViewH - bgView.getBottom(), 200); invalidate(); break; } return super.dispatchTouchEvent(event); } private int getScrollY(float dy) { int yy = (int) (top + dy/2.5F); return yy; } public void computeScroll() { //super.computeScroll(); if (mScroller.computeScrollOffset()) { int x = mScroller.getCurrX(); int y = mScroller.getCurrY(); bgView.layout(0, 0, x + bgView.getWidth(), y); invalidate(); if (!mScroller.isFinished() && scrollerType && y > 200) { bgView.setLayoutParams(new RelativeLayout.LayoutParams(bgView.getWidth(), y)); } } } }
原理就是根据手势在ListView上的滑动来改变ImageView的高度。代码处理部分在dispatchTouchEvent方法的MotionEvent.ACTION_MOVE这个case下:int t = getScrollY(currentY - startY); if (t >= top && t <= headView.getBottom() + len) { bgView.setLayoutParams(new RelativeLayout.LayoutParams(bgView.getWidth(), t)); }
需要关注的是getScrollY这个方法:private int getScrollY(float dy) { int yy = (int) (top + dy/2.5F); return yy; }dy/2.5就是为了实现这个橡皮筋的效果。手指在ListView的滑动的距离体现到ImageView的高度时做了个摩擦力的虚拟效果。手势弹起的时候就会sroll到初始状态。