Path的橡皮筋效果其实挺好实现。这里记录下学习心得。
橡皮筋的核心思想应该是摩擦力和弹力,下拉的时候模拟出一个摩擦力的效果,松手的时候的时候有个回弹的效果就好了。
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到初始状态。