自定义ScrollView实现阻尼效果(类似于QQ下拉一段距离)

来源:互联网 发布:如何判断淘宝号被黑 编辑:程序博客网 时间:2024/05/21 10:57
public class DampingScrollView extends ScrollView{    private View activityView;  //activity传递进来的View用来控制其高度(可以是ImageViewTextView 等)    private Scroller mScroller; //    /** 回弹时所用的时间 */    private static final int DURATION = 100;    /** 最大Y坐标 其值一般设定为Scroller对应控件的高度 */    private static final int MAX_DY = 100;    TouchTool tool;    int left, top;    float startX, startY, currentX, currentY;    int imageViewH;    int rootW, rootH;    boolean scrollerType;    public DampingScrollView(Context context, AttributeSet attrs) {        super(context, attrs);        mScroller=new Scroller(context);    }    public DampingScrollView(Context context) {        super(context);        mScroller=new Scroller(context);    }    public void setActivityView(View activityView) {//设置要改变高度的视图        this.activityView = activityView;    }    @Override    public boolean onTouchEvent(MotionEvent event) {        int action = event.getAction();        if (!mScroller.isFinished()) {            return super.onTouchEvent(event);        }        currentX = event.getX();        currentY = event.getY();        switch (action) {            case MotionEvent.ACTION_DOWN:// 变量赋初始值                left = activityView.getLeft();                top = activityView.getBottom();                rootW = getWidth();                rootH = getHeight();                imageViewH = activityView.getHeight();                startX = currentX;                startY = currentY;                tool = new TouchTool(activityView.getBottom());                break;            case MotionEvent.ACTION_MOVE:                if (activityView.isShown() && activityView.getTop() >= 0) {                    if (tool != null) {                        int t = tool.getScrollY(currentY - startY);                        if (t >= top ) {                            android.view.ViewGroup.LayoutParams params = activityView                                    .getLayoutParams();                            params.height = t;// 改变高度                            activityView.setLayoutParams(params);                        }                    }                    scrollerType = false;                }                break;            case MotionEvent.ACTION_UP:                scrollerType = true;                // 松手后 回弹                // 开始一个动画控制,由(startX , startY)duration时间内前进(dx,dy)个单位                // ,即到达坐标为(startX+dx , startY+dy)                mScroller.startScroll(activityView.getLeft(), activityView.getBottom(),                        0 - activityView.getLeft(),                        imageViewH - activityView.getBottom(), DURATION);                invalidate();                break;        }        return super.onTouchEvent(event);    }    /**     * onDraw()执行时调用此方法     */    // //mScroller针对于imageView的变化    // 被父视图调用,用于必要时候对其子视图的值(mScrollXmScrollY    // 进行更新。典型的情况如:父视图中某个子视图使用一个Scroller对象来实现滚动操作,会使得此方法被调用。    @Override    public void computeScroll() {        if (mScroller.computeScrollOffset()) {            int x = mScroller.getCurrX();            int y = mScroller.getCurrY();// ImageView的当前Y坐标            activityView.layout(0, 0, x + activityView.getWidth(), y);//使imageView本身做相应变化            invalidate();            // 滑动还未完成时,手指抬起时,当前y坐标大于其实imageView的高度时            //设定imageView的布局参数  作用:使除imageView之外的控件做相应变化            if (!mScroller.isFinished() && scrollerType && y > MAX_DY) {                android.view.ViewGroup.LayoutParams params = activityView                        .getLayoutParams();                params.height = y;                activityView.setLayoutParams(params);            }        }    }    public class TouchTool {        private int startY;        public TouchTool( int startY) {            this.startY = startY;        }        public int getScrollY(float dy) {            int yy = (int) (startY + dy / 2.5F);//手势滑动距离/2.5 才是屏幕滑动的距离  此内部类主要做此用            return yy;        }    }
}

我们先来看一下,Scroller,这个对象里有startScroll方法 

 void Android.widget.Scroller.startScroll(int startX, int startY, int dx, int dy, int duration)第一个参数是起始移动的x坐标值,第二个是起始移动的y坐标值,第三个第四个参数都是移到某点的坐标值,而duration 当然就是执行移动的时间。这个有什么用呢。要知道有什么用还得再看一个方法

boolean android.widget.Scroller.computeScrollOffset()
当startScroll执行过程中即在duration时间内,computeScrollOffset  方法会一直返回false,但当动画执行完成后会返回返加true.

有了这两个方法还不够,我们还需要再重写viewGroup的一个方法,

computeScroll 这个方法什么时候会被调用呢

官网上这样说的

public void computeScroll ()

Since: API Level 1

Called by a parent to request that a child update its values for mScrollX and mScrollY if necessary. This will typically be done if the child is animating a scroll using a Scroller object.

当我们执行ontouch或invalidate()或postInvalidate()都会导致这个方法的执行

所以我们像下面这样调用,postInvalidate执行后,会去调computeScroll 方法,而这个方法里再去调postInvalidate,这样就可以不断地去调用scrollTo方法了,直到mScroller动画结束,当然第一次时,我们需要手动去调用一次postInvalidate才会去调用 

computeScroll 方法

[java] view plain copy
  1. @Override  
  2. public void computeScroll() {  
  3.     if (mScroller.computeScrollOffset()) {  
  4.         scrollTo(mScroller.getCurrX(), 0);  
  5.         postInvalidate();  
  6.     }  
  7. }  
下载:http://download.csdn.net/detail/qq_15796477/9508798
                                             
0 0
原创粉丝点击