自定义ZoomRecyclerView可缩放可点击

可直接使用喔~ 

public class PinchRecyclerView extends RecyclerView implements View.OnTouchListener {
    private static final int INVALID_POINTER_ID = -1;
    private int mActivePointerId = INVALID_POINTER_ID;
    private ScaleGestureDetector mScaleDetector;
    private float mScaleFactor = 1.f;
    private float maxWidth = 0.0f;
    private float maxHeight = 0.0f;
    private float mLastTouchX;
    private float mLastTouchY;
    private float mPosX;
    private float mPosY;
    private float width;
    private float height;

    public PinchRecyclerView(Context context) {
        this(context, null);
    }

    public PinchRecyclerView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public PinchRecyclerView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        setOnTouchListener(this);
        if (!isInEditMode())
            mScaleDetector = new ScaleGestureDetector(getContext(), new ScaleListener());
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        width = View.MeasureSpec.getSize(widthMeasureSpec);
        height = View.MeasureSpec.getSize(heightMeasureSpec);
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        try {
            boolean resp = super.onInterceptTouchEvent(ev);
            Log.d(TAG, "onInterceptTouchEvent: " + resp);
            return resp;
        } catch (IllegalArgumentException ex) {
            ex.printStackTrace();
        }
        return false;
    }

    @Override
    public boolean onTouchEvent(@NonNull MotionEvent ev) {
        super.onTouchEvent(ev);
        final int action = ev.getAction();
        mScaleDetector.onTouchEvent(ev);
        switch (action & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN: {
                final float x = ev.getX();
                final float y = ev.getY();
                mLastTouchX = x;
                mLastTouchY = y;
                mActivePointerId = ev.getPointerId(0);
                break;
            }

            case MotionEvent.ACTION_MOVE: {
                final int pointerIndex = (action & MotionEvent.ACTION_POINTER_INDEX_MASK)
                        >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
                final float x = ev.getX(pointerIndex);
                final float y = ev.getY(pointerIndex);
                final float dx = x - mLastTouchX;
                final float dy = y - mLastTouchY;

                mPosX += dx;
                mPosY += dy;

                if (mPosX > 0.0f)
                    mPosX = 0.0f;
                else if (mPosX < maxWidth)
                    mPosX = maxWidth;

                if (mPosY > 0.0f)
                    mPosY = 0.0f;
                else if (mPosY < maxHeight)
                    mPosY = maxHeight;

                mLastTouchX = x;
                mLastTouchY = y;
                invalidate();
                break;
            }

            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL: {
                mActivePointerId = INVALID_POINTER_ID;
                break;
            }

            case MotionEvent.ACTION_POINTER_UP: {
                final int pointerIndex = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
                final int pointerId = ev.getPointerId(pointerIndex);
                if (pointerId == mActivePointerId) {
                    final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
                    mLastTouchX = ev.getX(newPointerIndex);
                    mLastTouchY = ev.getY(newPointerIndex);
                    mActivePointerId = ev.getPointerId(newPointerIndex);
                }
                break;
            }
        }

        return true;
    }

    @Override
    public void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.save();
        canvas.translate(mPosX, mPosY);
        canvas.scale(mScaleFactor, mScaleFactor);
        canvas.restore();
    }

    @Override
    protected void dispatchDraw(@NonNull Canvas canvas) {
        canvas.save();
        if (mScaleFactor == 1.0f) {
            mPosX = 0.0f;
            mPosY = 0.0f;
        }
        canvas.translate(mPosX, mPosY);
        canvas.scale(mScaleFactor, mScaleFactor);
        super.dispatchDraw(canvas);
        canvas.restore();
        invalidate();
    }

    private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
        @Override
        public boolean onScale(ScaleGestureDetector detector) {
            mScaleFactor *= detector.getScaleFactor();
            mScaleFactor = Math.max(1.0f, Math.min(mScaleFactor, 3.0f));
            maxWidth = width - (width * mScaleFactor);
            maxHeight = height - (height * mScaleFactor);
            invalidate();
            return true;
        }
    }

    private float getScaleFactor() {
        return mScaleFactor;
    }

    private float getPosX() {
        return mPosX;
    }

    private float getPosY() {
        return mPosY;
    }

    // Map what appeared to be clicked in the potentially zoomed view back to the scale = 1 view.
    private View getMappedView(float x, float y) {
        final int NO_POSITION = -1;
        View expectedView = null;
        View scanView;
        final int mappedX = (int) (getWidth() * (x - getPosX()) / (getWidth() * getScaleFactor()));
        final int mappedY = (int) (getHeight() * (y - getPosY()) / (getHeight() * getScaleFactor()));
        int foundColumn = NO_POSITION;
        int lastLeft = NO_POSITION;

        // Look for the column of the expected view.
        for (int i = 0; i < getChildCount() && foundColumn == NO_POSITION; i++) {
            scanView = getChildAt(i);
            int thisLeft = scanView.getLeft();
            if ((mappedX <= scanView.getRight()) && (mappedX >= thisLeft)) {
                foundColumn = i;
            }
            if (thisLeft < lastLeft) { // Wrapped around. Touch outside of our area.
                break;
            }
            lastLeft = scanView.getLeft();
        }
        if (foundColumn == NO_POSITION) {
            return null;
        }

        // Find out how many columns we have.
        int colCount = foundColumn;
        while (++colCount < getChildCount()) {
            if (getChildAt(colCount).getLeft() <= lastLeft) {
                break;
            }
        }

        // Look for the row.
        for (int i = foundColumn; i < getChildCount(); i += colCount) {
            scanView = getChildAt(i);
            if ((mappedY >= scanView.getTop()) && (mappedY <= scanView.getBottom())) {
                expectedView = scanView;
                break;
            }
        }
        return expectedView;
    }

    private boolean mClickCandidate = false;
    private float mLastX;
    private float mLastY;

    @Override
    public boolean onTouch(View view, MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mClickCandidate = true;
                break;
            case MotionEvent.ACTION_MOVE:
                float x = Math.abs(event.getX() - mLastX);
                float y = Math.abs(event.getY() - mLastY);
                if (x > 0 || y > 0) {
                    mClickCandidate = false;
                } else {
                    mClickCandidate = true;
                }
                mLastX = event.getX();
                mLastY = event.getY();

                break;
            case MotionEvent.ACTION_UP:
                if (mClickCandidate) {
                    View v = getMappedView(event.getX() + view.getLeft(), event.getY() + view.getTop());
                    if (v != null && v.hasOnClickListeners()) {
                        v.performClick();
                    }
                    mClickCandidate = false;
                }

                return true;
        }
        return false;
    }

    private static final String TAG = PinchRecyclerView.class.getClass().getSimpleName();
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
在Qt中,可以通过自定义窗口标题栏的方式来实现功能。 首先,需要创建一个继承自QWidget的自定义窗口类(例如CustomWindow),并重写其鼠标按下、移动和释事件的处理函数: ```c++ class CustomWindow : public QWidget { // ... protected: void mousePressEvent(QMouseEvent* event) override { if (event->button() == Qt::LeftButton) { // 记录鼠标按下时的窗口位置和大小 m_startPos = event->globalPos(); m_startGeometry = geometry(); } } void mouseMoveEvent(QMouseEvent* event) override { if (event->buttons() & Qt::LeftButton) { // 计算鼠标移动的偏移量 QPoint offset = event->globalPos() - m_startPos; // 根据偏移量来设置新的窗口位置和大小 QRect newGeometry = m_startGeometry.translated(offset); setGeometry(newGeometry); } } void mouseReleaseEvent(QMouseEvent* event) override { if (event->button() == Qt::LeftButton) { // 释鼠标时重置起始位置和窗口大小 m_startPos = QPoint(); m_startGeometry = QRect(); } } private: QPoint m_startPos; QRect m_startGeometry; }; ``` 接下来,在主窗口中使用自定义窗口类替代原始的QWidget窗口: ```c++ int main(int argc, char *argv[]) { QApplication a(argc, argv); CustomWindow w; w.show(); return a.exec(); } ``` 这样就实现了自定义标题栏的功能了。当鼠标按下标题栏左键并移动时,窗口会跟随鼠标的移动而改变位置和大小。释鼠标按钮后,窗口将保持在新的位置和大小上。 注意:为了实现这个功能,可能还需要对标题栏的样式进行进一步的自定义

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值