先讲下原理:
ScrollView的子View 主要分为3部分:head头部,滚动内容,fooder底部
我们实现惯性滑动,以及回弹,都是靠超过head或者fooder 就重新滚动到 ,内容的顶部或者底部。
之前看了Pulltorefresh 他是通过不断改变 head或者 fooder的 pading 值来实现 上拉或者 下拉的效果。感觉有点不流畅,而且层次嵌套得比较多。当然他的好处是扩展性好。
因工作需求,需要层次嵌套少,对性能要求非常高。因此重新自定义了ViewGroup实现。
直接上代码:
package com.example.administrator.customscrollview;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.OverScroller;
/**
* 自定义 pulltorefresh Layout
* TODO: ferris 2015年9月11日 18:52:40
*/
public class PullTorefreshScrollView extends ViewGroup {
private FoodeLayout fooder_layout;// top and buttom
private View top_layout;
private int desireWidth, desireHeight;
private VelocityTracker velocityTracker;
private int mPointerId;
private float x, y;
private OverScroller mScroller;
private int maxFlingVelocity, minFlingVelocity;
private int mTouchSlop;
protected Boolean isMove = false;
protected float downX = 0, downY = 0;
private int top_hight = 0;
private int scrollYButtom = 0;
private int nScrollYButtom = 0;
private int pullDownMin = 0;
private Boolean isEnablePullDown = true;
private Boolean isFirst=true;
public void setEnablePullDown(Boolean isEnablePullDown) {
this.isEnablePullDown = isEnablePullDown;
}
public PullTorefreshScrollView(Context context) {
super(context);
init(null, 0);
}
public PullTorefreshScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs, 0);
}
public PullTorefreshScrollView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(attrs, defStyle);
}
private void init(AttributeSet attrs, int defStyle) {
// Load attributes
// final TypedArray a = getContext().obtainStyledAttributes(
// attrs, R.styleable.PullTorefreshScrollView, defStyle, 0);
//
//
// a.recycle();
mScroller = new OverScroller(getContext());
maxFlingVelocity = ViewConfiguration.get(getContext()).getScaledMaximumFlingVelocity();
minFlingVelocity = ViewConfiguration.get(getContext()).getScaledMinimumFlingVelocity();
mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
fooder_layout = (FoodeLayout) findViewById(R.id.fooder_layout);
top_layout = findViewById(R.id.top_layout);
if (isEnablePullDown) {
fooder_layout.showFooderPull();
} else {
fooder_layout.hideFooder();
}
}
public int getScrollYTop() {
return top_hight;
}
public int getScrollYButtom() {
return scrollYButtom;
}
public int getNScrollYTop() {
return 0;
}
public int getNScrollYButtom() {
return nScrollYButtom;
}
public int measureWidth(int widthMeasureSpec) {
int result = 0;
int measureMode = MeasureSpec.getMode(widthMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
switch (measureMode) {
case MeasureSpec.AT_MOST:
case MeasureSpec.EXACTLY:
result = width;
break;
default:
break;
}
return result;
}
public int measureHeight(int heightMeasureSpec) {
int result = 0;
int measureMode = MeasureSpec.getMode(heightMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
switch (measureMode) {
case MeasureSpec.AT_MOST:
case MeasureSpec.EXACTLY:
result = height;
break;
default:
break;
}
return