效果如图:
源码已上传至我的资源 即:自定义ScrollerView源代码.rar
话不多说直接开始写代码:
1.自定义 MyScrollView 类继承 ScrollView
public class MyScrollView extends ScrollView {
2.构造器( 注意!这里不能用this来连写,构造 )
public MyScrollView(Context context) {
super(context);
this.mContext=context;
}
public MyScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
this.mContext=context;
}
public MyScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.mContext=context;
}
3.获取子视图
@Override
protected void onFinishInflate() {
super.onFinishInflate();
//ScrollView只能有一个孩子,所以这里获取的就是ScrollView
if (getChildCount()>0){
childView= getChildAt(0);
}
}
4.重写onTouchEvent()方法
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (childView == null || !isFinishAnimation) {
return super.onTouchEvent(ev);
}
//获取当前y轴方向的坐标(相较于当前视图)
int eventY = (int) ev.getY();
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
lastY = eventY;
break;
case MotionEvent.ACTION_MOVE:
//获取y轴移动的位移
int dy = eventY - lastY;
if (isNeedMove()) {//如果没有记录过left,top,right,bottom,返回true.
if (normal.isEmpty()) {
//记录临界状态的left,top,right,bottom
normal.set(childView.getLeft(), childView.getTop(), childView.getRight(), childView.getBottom());
}
//给视图重新布局
childView.layout(childView.getLeft(), childView.getTop() + dy / 2, childView.getRight(), childView.getBottom());
//记得要重新赋值,即把上一次的结束,作为下一次的开始
lastY = eventY;
}
break;
case MotionEvent.ACTION_UP:
if (isNeedAnimation()) {
TranslateAnimation translateAnimation = new TranslateAnimation(0, 0, 0, normal.bottom - childView.getBottom());
translateAnimation.setDuration(300);
childView.startAnimation(translateAnimation);
//设置动画的监听
translateAnimation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
isFinishAnimation = false;
}
@Override
public void onAnimationEnd(Animation animation) {
isFinishAnimation = true;
//先清除动画
childView.clearAnimation();
childView.layout(normal.left, normal.top, normal.right, normal.bottom);//重新布局
normal.setEmpty();//清空normal中left、top、right、bottom数据
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
}
break;
}
return super.onTouchEvent(ev);
}
5.重写onInterceptTouchEvent()方法
/**
* @param ev
* @return 如果返回值为true,表示拦截子视图的处理。如果返回false,表示不拦截
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean isIntercet=false;
int eventX= (int) ev.getX();
int eventY= (int) ev.getY();
switch (ev.getAction()){
case MotionEvent.ACTION_DOWN:
//记录水平方向和垂直方向移动的距离
downY= lastY=eventY;
downX= lastX=eventX;
break;
case MotionEvent.ACTION_MOVE:
int disX=Math.abs(eventX-downX);
int disY=Math.abs(eventY-downY);
if (disX<disY || disY> dp2px(10)){
isIntercet=true;
}
lastY=eventY;
lastX=eventX;
break;
}
return isIntercet;
}
6.在布局中使用自定义的ScrollView
<!--换成自定义的ScrollView-->
<!--ScrollView只能有一个孩子-->
<com.example.chenjunmei.myscrollview.MyScrollView
android:layout_marginTop="3dp"
android:layout_width="match_parent"
android:layout_height="match_parent">
</com.example.chenjunmei.myscrollview.MyScrollView>
好了完成~