今天已经是这个星期连续加班的第四天了,趁着现在后台在处理逻辑问题,将前几天写的一个小例子整理下来。
效果图
效果分析
1 向下滑动,头部的图片随着手指滑动不断变大 2 向上滑动,不断的向上移动图片,直到图片不可见 3 当顶部图片不可见时,向上滑动,滑动ListView
实现思路
1 由于这个View分上下两部分,垂直排列,可以通过继承LinearLayout实现::自定义一个DragImageView,该View继承LinearLayout
public DragImageView(Context context, AttributeSet attrs) {
super(context, attrs);
// 默认该View垂直排列
setOrientation(LinearLayout.VERTICAL);
// 用于配合处理该View的惯性滑动
mScroller = new OverScroller(context);
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
mMaximumVelocity = ViewConfiguration.get(context)
.getScaledMaximumFlingVelocity();
mMinimumVelocity = ViewConfiguration.get(context)
.getScaledMinimumFlingVelocity();
}
2 onMeasure中设置内容视图的高度
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
LayoutParams params = (LayoutParams) getChildAt(1).getLayoutParams();
// 头部可以全部隐藏,所以内容视图的高度即为该控件的高度
params.height = getMeasuredHeight();
}
3 设置ImageView的ScaleType属性
@Override
protected void onFinishInflate() {
super.onFinishInflate();
imageView = (ImageView) getChildAt(0);
// 随着手指滑动,图片不断放大(宽高都大于或者等于ImageView的大小),并居中显示:
// 根据上边的分析,CENTER_CROP:可以使用均衡的缩放图像(保持图像原始比例),使图片的两个坐标(宽、高)都大于等于 相应的视图坐标(负的内边距),图像则位于视图的中央
imageView.setScaleType(ScaleType.CENTER_CROP);
listView = (ListView) getChildAt(1);
}
4 事件拦截
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
downX = (int) ev.getX();
downY = (int) ev.getY();
}
if (ev.getAction() == MotionEvent.ACTION_MOVE) {
int currentX = (int) ev.getX();
int currentY = (int) ev.getY();
// 确保是垂直滑动
if (Math.abs(currentY - downY) Math.abs(currentX - downX)) {
View childView = listView.getChildAt(listView
.getFirstVisiblePosition());
// 有两种情况需要拦截:
// 1 图片没有完全隐藏
// 2 图片完全隐藏,但是向下滑动,并且ListView滑动到顶部
if (getScrollY() != imageHeight
|| (getScrollY() == imageHeight && currentY - downY 0
&& childView != null && childView.getTop() == 0)) {
initVelocityTrackerIfNotExists();
mVelocityTracker.addMovement(ev);
return true;
}
}
}
if (ev.getAction() == MotionEvent.ACTION_UP) {
recycleVelocityTracker();
}
return super.onInterceptTouchEvent(ev);
}
5 onTouchEvent的ACTION_MOVE处理
if (ev.getAction() == MotionEvent.ACTION_MOVE) {
int currentX = (int) ev.getX();
int currentY = (int) ev.getY();
int deltyX = currentX - downX;
int deltyY = currentY - downY;
if (Math.abs(deltyY) Math.abs(deltyX)) {
if (deltyY 0) {
if (getScrollY() 0) {
if (getScrollY() - deltyY < 0) {
scrollBy(0, -getScrollY());
return true;
}
// 当图片没有完全显示,并且向下滑动时,继续整个view使图片可见
scrollBy(0, -deltyY);
} else {
// 当图片完全显示,并且向下滑动时,则不断的放大图片(通过改变ImageView)的高度
LayoutParams layoutParams = (LayoutParams) getChildAt(0)
.getLayoutParams();
layoutParams.height = layoutParams.height + deltyY / 2;
getChildAt(0).setLayoutParams(layoutParams);
}
} else {
// 当图片还处于放大状态,并且向上滑动时,继续不断的缩小图片的高度,使图片缩小
if (getChildAt(1).getTop() imageHeight) {
LayoutParams layoutParams = (LayoutParams) getChildAt(0)
.getLayoutParams();
layoutParams.height = layoutParams.height + deltyY / 2;
getChildAt(0).setLayoutParams(layoutParams);
} else {
// 当图片处于正常状态,并且向上滑动时,移动整个View,缩小图片的可见范围
if (getScrollY() - deltyY imageHeight) {
scrollBy(0, imageHeight - getScrollY());
return true;
}
scrollBy(0, -deltyY);
}
}
downY = currentY;
downX = currentX;
return true;
}
}
5 onTouchEvent的ACTION_UP处理
if (ev.getAction() == MotionEvent.ACTION_UP) {
// 当图片处于放大状态时松手,使图片缓慢的缩回到原来的状态
if (getChildAt(1).getTop() imageHeight) {
isAnimating = true;
ValueAnimator valueAnimator = ValueAnimator.ofInt(getChildAt(1)
.getTop(), imageHeight);
valueAnimator.setDuration(300);
valueAnimator.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int value = (Integer) animation.getAnimatedValue();
LayoutParams layoutParams = (LayoutParams) getChildAt(0)
.getLayoutParams();
layoutParams.height = value;
getChildAt(0).setLayoutParams(layoutParams);
}
});
valueAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
isAnimating = false;
}
});
valueAnimator.start();
}
// 当现在图片处于正常状态,并且图片没有完全隐藏,并且松手时滑动的速度大于可惯性滑动的最小值,让View产生惯性滑动效果
if (getChildAt(1).getTop() == imageHeight
&& getScrollY() != imageHeight) {
mVelocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
int velocityY = (int) mVelocityTracker.getYVelocity();
if (Math.abs(velocityY) mMinimumVelocity) {
fling(-velocityY);
}
recycleVelocityTracker();
}
总结
这里主要有两个学习的点
1 图片缩放的处理,事件的拦截
2 View的惯性滑动:主要是结合OverScroller的使用
以上就是本文的全部内容,希望对大家的学习有所帮助。