使用Scroller仿QQ刷新

最近突然对QQ的刷新感兴趣,就自己试做了下,目前还差图片的变换以及速度的改变。

package com.luoxf.drag.view;

import android.content.Context;
import android.graphics.Point;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewTreeObserver;
import android.view.WindowManager;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.Scroller;
import android.widget.TextView;
import com.luoxf.drag.R;
import com.nineoldandroids.view.ViewHelper;

/**
 * Created by luoxf on 2015/10/27.
 */
public class PullRelativeLayout extends RelativeLayout{
    private final int REFRESHING = 1;
    private final String TAG = PullRelativeLayout.class.getSimpleName();
    private int screenHeight;
    private int screenWidth;
    private Context mContext;
    private Scroller mScroller;
    private int mLastX;
    private int mLastY;
    private int touchSlop; //最小滑动距离
    private boolean isNeedToUp;
    private View refreshContent; //刷新内容
    private int refreshContentHeight; //刷新高度
    private View content;
    private TextView refreshText; //刷新文本
    private View refreshIcon; //刷新图标
    private Handler handler;
    private VelocityTracker velocityTracker; // 速度捕捉器
    public PullRelativeLayout(Context context) {
        super(context);
        initView(context);
    }

    public PullRelativeLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView(context);
    }

    public PullRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView(context);
    }

    private void initView(Context context) {
        this.mContext = context;
        this.mScroller = new Scroller(context);
        touchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
        WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
        Point point = new Point();
        wm.getDefaultDisplay().getSize(point);
        screenWidth = point.x;
        screenHeight = point.y;
        handler = new Handler() {
            public void handleMessage(Message msg){
                super.handleMessage(msg);
                switch (msg.what) {
                    //正在刷新
                    case REFRESHING:
                        if(refreshText.getText().toString().equals(mContext.getString(R.string.refresh_three))) {
                            smoothScrollTo(0, refreshContentHeight);
                        }
                        break;
                }
            }
        };
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        refreshContent = findViewById(R.id.refresh_content);
        content = findViewById(R.id.content);
        refreshText = (TextView) findViewById(R.id.refresh_text);
        refreshIcon = findViewById(R.id.refresh_icon);
        refreshContent.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                refreshContent.getViewTreeObserver().removeGlobalOnLayoutListener(this);
                refreshContentHeight = refreshContent.getHeight();
                mScroller.setFinalY(refreshContentHeight);
                LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) getLayoutParams();
                layoutParams.height = getHeight() + refreshContentHeight;
                layoutParams.width = getWidth();
                setLayoutParams(layoutParams);
            }
        });
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        boolean intercepted = false;
        int x = (int) ev.getX();
        int y = (int) ev.getY();
        final int action = ev.getAction();
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                velocityTracker = VelocityTracker.obtain();
                intercepted = false;
                break;
            case MotionEvent.ACTION_MOVE:
                int deltaY = y - mLastY;
                //子view需要
                if(mScroller.getFinalY() == refreshContentHeight && (deltaY < 0 || content.getScrollY() != 0)) {
                    return false;
                } else {
                    return true;
                }
            case MotionEvent.ACTION_UP:
                intercepted = false;
                break;
        }
        mLastX = x;
        mLastY = y;
        return intercepted;
    }

    //调用此方法滚动到目标位置
    public void smoothScrollTo(int fx, int fy) {
        int dx = fx - mScroller.getFinalX();
        int dy = fy - mScroller.getFinalY();
        smoothScrollBy(dx, dy);
    }

    //调用此方法设置滚动的相对偏移
    public void smoothScrollBy(int dx, int dy) {
        //设置mScroller的滚动偏移量
        mScroller.startScroll(mScroller.getFinalX(), mScroller.getFinalY(), dx, dy);
        invalidate();//这里必须调用invalidate()才能保证computeScroll()会被调用,否则不一定会刷新界面,看不到滚动效果
    }
    @Override
    public void computeScroll() {
        //先判断mScroller滚动是否完成
        if (mScroller.computeScrollOffset()) {
            //这里调用View的scrollTo()完成实际的滚动
            scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
            //必须调用该方法,否则不一定能看到滚动效果
            postInvalidate();
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int x = (int) event.getX();
        int y = (int) event.getY();
        switch (event.getAction()) {
            case MotionEvent.ACTION_MOVE:
                velocityTracker.computeCurrentVelocity(1000);
                int deltaY = y - mLastY;
                //改变刷新图标和文字
                if(mScroller.getFinalY() <= 0) {
                    ViewHelper.setRotation(refreshIcon, 180);
                    refreshText.setText(mContext.getString(R.string.refresh_two));
                } else {
                    ViewHelper.setRotation(refreshIcon, 180);
                    refreshText.setText(mContext.getString(R.string.refresh_first));
                }
                //滑到顶部
                if(mScroller.getFinalY() - deltaY > refreshContentHeight) {
                    smoothScrollTo(0, refreshContentHeight);
                    isNeedToUp = false;
                }
                //下滑大于屏幕三分之一
                else if(mScroller.getFinalY() - deltaY < -screenHeight / 3) {
                    smoothScrollTo(0, -screenHeight / 3);
                    isNeedToUp = true;
                } else {
                    smoothScrollBy(0, -deltaY);
                    isNeedToUp = true;
                }
                break;
            case MotionEvent.ACTION_UP:
                //自动滑到顶部
                if(isNeedToUp) {
                    //正在刷新
                    if(mScroller.getFinalY() <= 0) {
                        smoothScrollTo(0, 0);
                        refreshText.setText(mContext.getString(R.string.refresh_three));
                        new Thread(new Runnable() {
                            @Override
                            public void run() {
                                try {
                                    Thread.sleep(1000);
                                    handler.sendEmptyMessage(REFRESHING);
                                } catch (InterruptedException e) {
                                    e.printStackTrace();
                                }
                            }
                        }).start();
                    } else {
                        smoothScrollTo(0, refreshContentHeight);
                    }
                }
                //清除速度
                velocityTracker.clear();
                velocityTracker.recycle();
                break;
            default:
                break;
        }
        mLastX = x;
        mLastY = y;
        return true;
    }
}
效果图如下:

使用Scroller仿QQ刷新_第1张图片

接下来边学习边修改,努力。


你可能感兴趣的:(使用Scroller仿QQ刷新)