在Android中ScrollView是没有上下反弹效果,IOS中的控件默认是有上下反弹效果。实现上下反弹效果对于用户来说可能体验感觉会更好一些。ScrollView实现上下反弹效果原理很简单,下面先来说一下实现原理,然后在贴代码。
1、首先自定义个CustomerScrollView类,继承ScrollView
2、重写onFinishInflate()方法,该方法会在视图生成后调用,重写该方法的目的是获取ScrollView的子视图
3、监听ScrollView的onTouch事件,在该事件中根据不同的事件去处理不同的事情。
import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.TranslateAnimation;
import android.widget.ScrollView;
/**
*
* 可以上下反弹的ScrollView
*/
public class CustomerScrollView extends ScrollView {
private View inner;
private Rect rect = new Rect();
private float y=0;
private int size=4;//
public CustomerScrollView(Context context) {
super(context, null);
init();
}
public CustomerScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
/**
* 初始化设置
* 去掉ScrollView的边缘效果
*/
private void init()
{
setOverScrollMode(OVER_SCROLL_NEVER);//去掉边缘效果
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
//获取子布局
if (this.getChildAt(0) != null) {
inner = this.getChildAt(0);
}
}
//监听ScrollView的onTouchEvent事件
@Override
public boolean onTouchEvent(MotionEvent ev) {
//如果inner为null,即scrollView没有子视图,直接返回
if (inner == null) {
return super.onTouchEvent(ev);
}
//自定义事件处理方法
customerOnTouchEvent(ev);
return super.onTouchEvent(ev);
}
/**
* 自定义触摸事件
*
* @author King
* created at 2016/1/9 11:55
*/
private void customerOnTouchEvent(MotionEvent event) {
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
//手指按下是记录y的坐标
y=event.getY();
break;
case MotionEvent.ACTION_UP:
//手指抬起的时候计算是否需要回到正常状态
if(isNeedAnimation())
{
animationToNomal();
}
break;
case MotionEvent.ACTION_MOVE:
//手指一动的时候重新布局View
float nowY=event.getY();
int deltaY=(int)((y-nowY)/size);
y=nowY;
if(isNeedMove())
{
if(rect.isEmpty())
{
rect.set(inner.getLeft(),inner.getTop(),inner.getRight(),inner.getBottom());
return;
}
int yy=inner.getTop()-deltaY;//滑动的偏移量
inner.layout(inner.getLeft(),yy,inner.getRight(),inner.getBottom()-deltaY);
}
break;
}
}
private boolean isNeedAnimation()
{
return !rect.isEmpty();
}
/**
* 手指抬起后将页面回到原始状态
*
*
*/
private void animationToNomal()
{
TranslateAnimation translateAnimation=new TranslateAnimation(0,0,inner.getTop(),rect.top);
translateAnimation.setDuration(200);
inner.startAnimation(translateAnimation);
inner.layout(rect.left, rect.top, rect.right, rect.bottom);
rect.setEmpty();
}
/**
* 是否需要移动
*/
public boolean isNeedMove()
{
int offset=inner.getMeasuredHeight()-getHeight();
int scrollY=getScrollY();//getScrollY表示Y轴滚动的距离
int t=getScrollY()+getHeight();//getHeight:获取scrollView的高度
debug("offset="+offset+",scrollY="+scrollY+",inner.getMeasuredHeight()="+inner.getMeasuredHeight()+",getScrollY()+getHeight()="+String.valueOf(t));
debug("getHeight="+getHeight()+",getScrollY()="+getScrollY());
//inner.getMeasuredHeight<=t:判断滚动条是否滚到底部
if(scrollY==0||inner.getMeasuredHeight()<=t)
{
return true;
}
return false;
}
private void debug(String msg)
{
Log.d("CustomerScrollerView","-----------------"+msg);
}
}
在布局页面的布局:
<com.test.app.widget.CustomerScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="ddddddd" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="ddddddd" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="ddddddd" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="ddddddd" />
</LinearLayout>
</com.test.app.widget.CustomerScrollView>
在LinearLayout中可以随意的放置组件了。