我的自定义ScrollView

第一次写博客,主要是公司不能传文件,就想着把关键代码写在博客里,方便以后查看.

今天,根据查找的网上资料,scrollview源码,写了一个类似的VIEW

它主要是通过measureChildWithMargins来布局child,然后通过computeScroll、fling在ontouch时实现滑动,包括拖拽滑动,以及拖拽放开后根据移动速度来滑动.


public class MyScrollView extends FrameLayout {
private static final int INVALI_POINTER_ID = -1;
private Scroller mScroller;
private int mTouchSlop;
private int mMinimumFlingVelocity;
private int mMaximumFlingVelocity;
private VelocityTracker mVelocityTracker;

private float mLastMotionY;
private boolean isDrag = false;
private int mActivePointerId = -1;


public MyScrollView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}


public MyScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}


public MyScrollView(Context context) {
super(context);
init(context);
}

private void init(Context ctx){
mScroller = new Scroller(ctx);
ViewConfiguration viewConfiguration = ViewConfiguration.get(ctx);
mTouchSlop = viewConfiguration.getScaledTouchSlop();
mMinimumFlingVelocity = viewConfiguration.getScaledMinimumFlingVelocity();
mMaximumFlingVelocity = viewConfiguration.getScaledMaximumFlingVelocity();
}

@Override
protected void measureChildWithMargins(View child,
int parentWidthMeasureSpec, int widthUsed,
int parentHeightMeasureSpec, int heightUsed) {

super.measureChildWithMargins(child, parentWidthMeasureSpec, widthUsed,
parentHeightMeasureSpec, heightUsed);

MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();

int childwidth = getChildMeasureSpec(parentWidthMeasureSpec, 
lp.leftMargin+lp.rightMargin+getPaddingLeft()+getPaddingRight()+widthUsed, 
lp.width);
int childheight = MeasureSpec.makeMeasureSpec(lp.bottomMargin+lp.topMargin, MeasureSpec.UNSPECIFIED);


child.measure(childwidth, childheight);

}

@Override
public void computeScroll() {
// TODO Auto-generated method stub
super.computeScroll();

final Scroller scroller = mScroller;
if(scroller.computeScrollOffset()){
int scrollY = scroller.getCurrY();
int maxY = getChildAt(0).getHeight() - getHeight();
boolean isToEdge = scrollY < 0 || scrollY > maxY;
if(scrollY < 0){
scrollY = 0;
}else if(scrollY > maxY){
scrollY = maxY;
}
scrollTo(0, scrollY);
if(isToEdge){
awakenScrollBars();
}
}
}

private void fling(int velocityY){
int maxY = getChildAt(0).getHeight() - getHeight();
mScroller.fling(getScrollX(), getScrollY(), 0, velocityY, 0, 0, 0, Math.max(0, maxY));
invalidate();
}

@Override
public boolean onTouchEvent(MotionEvent event) {

int contentHeight = getChildAt(0).getHeight();
if(contentHeight > getHeight()){
boolean handled = false;
if(null == mVelocityTracker){
mVelocityTracker = VelocityTracker.obtain();
}
mVelocityTracker.addMovement(event);
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:{
if(!mScroller.isFinished()){
mScroller.forceFinished(true);
}
mLastMotionY = event.getY();
isDrag = true;
mActivePointerId = event.getPointerId(0);
handled = true;
}
break;
case MotionEvent.ACTION_MOVE:{
final int pointerId = mActivePointerId;
if(isDrag && pointerId != INVALI_POINTER_ID){
final int pointerIndex = event.findPointerIndex(pointerId);
final float y = event.getY(pointerIndex);
int deltaY = (int) (mLastMotionY - y);

System.out.println("zxl---myscrollview---move 2--->"+Math.abs(deltaY)+"--->"+mTouchSlop);
if(Math.abs(deltaY) > mTouchSlop){
mLastMotionY = y;
// mScroller.startScroll(getScrollX(), getScrollY(), 0, deltaY);//这个默认是250毫秒完成滑动,在拖拽滑动时不流畅
mScroller.startScroll(getScrollX(), getScrollY(), 0, deltaY, 0);
invalidate();
handled = true;
}
}
}
break;
case MotionEvent.ACTION_UP:{
final int pointerId = mActivePointerId;
if(isDrag && pointerId != INVALI_POINTER_ID){
final VelocityTracker  velocityTracker = mVelocityTracker;
velocityTracker.computeCurrentVelocity(1000, mMaximumFlingVelocity);
int initialVelocityY = (int) velocityTracker.getYVelocity(pointerId);
if(Math.abs(initialVelocityY) > mMinimumFlingVelocity){
fling(-initialVelocityY);
}

isDrag = false;
mActivePointerId = INVALI_POINTER_ID;

if(mVelocityTracker != null){
mVelocityTracker.recycle();
mVelocityTracker = null;
}

handled = true;
}
}
break;
case MotionEvent.ACTION_CANCEL:
break;
}
return handled;
}

return super.onTouchEvent(event);
}


}

上一篇:美团笔试 从矩阵起点到终点的最小花费


下一篇:Day9 - K - Yue Fei's Battle HDU - 5136