栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

自定义view拖拽缩放

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

自定义view拖拽缩放

此博客就是为了记录代码​​​​​​​

目标:

1. 点击view,盖住半透明浮层,浮层根据手势缩放和移动,四边任意缩放、四角等比缩放、中间移动;

2. 松开的时候,底层view执行缩放动画变成浮层的大小,,如果是移动,就执行移动动画;

实现:

MainMainActivity.java
public class MainMainActivity extends Activity {


    @SuppressLint("ClickableViewAccessibility")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main_main);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);//隐藏状态栏
        RelativeLayout relativeLayout = findViewById(R.id.relativeLayout);
        int[] size = UIUtil.getWidthAndHeightToSize(this);
        RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(size[0], size[1]);
        params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
        relativeLayout.setLayoutParams(params);
    }
}
activity_main_main.xml



    

        

        
    
TopDrawView.java
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;


public class TopDrawView extends View {

    public static final String ACTION_VIEW_DOWN = "action_view_down";//view的点击事件
    public static final String ACTION_VIEW_MOVE = "action_view_move";//view的移动事件
    public static final String ACTION_VIEW_UP = "action_view_up";//view的离开事件
    public static final String VIEW_MOVE = "view_move";//view的移动
    public static final String VIEW_ZOOM = "view_zoom";//view的缩放

    private Paint paint;
    private Paint paintLine;
    private Rect rect;
    private Rect rectLine;
    private int lineWidth = 2;//黑色边框线的宽度
    private float left, top, right, bottom;

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

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

    public TopDrawView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        paint = new Paint();
        paint.setColor(Color.argb(99, 0, 0, 0));
        paint.setStyle(Paint.Style.FILL);

        paintLine = new Paint();
        paintLine.setColor(Color.YELLOW);
        paintLine.setStrokeWidth(lineWidth);
        paintLine.setStyle(Paint.Style.STROKE);

        rect = new Rect(0, 0, 0, 0);
        rectLine = new Rect(0, 0, 0, 0);

        registerBoradcastReceiver();
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        if (mBroadcastReceiver != null) {
            getContext().unregisterReceiver(mBroadcastReceiver);
            mBroadcastReceiver = null;
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawRect(rect, paint);
        canvas.drawRect(rectLine, paintLine);
    }

    public void registerBoradcastReceiver() {
        IntentFilter myIntentFilter = new IntentFilter();
        myIntentFilter.addAction(ACTION_VIEW_DOWN);
        myIntentFilter.addAction(ACTION_VIEW_MOVE);
        myIntentFilter.addAction(ACTION_VIEW_UP);
        getContext().registerReceiver(mBroadcastReceiver, myIntentFilter);
    }

    private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (action.equals(ACTION_VIEW_DOWN)) {
                left = intent.getFloatExtra("oriLeft", 0);
                top = intent.getFloatExtra("oriTop", 0);
                right = intent.getFloatExtra("oriRight", 0);
                bottom = intent.getFloatExtra("oriBottom", 0);
            } else if (action.equals(ACTION_VIEW_MOVE)) {
                left = intent.getFloatExtra("oriLeft", 0);
                top = intent.getFloatExtra("oriTop", 0);
                right = intent.getFloatExtra("oriRight", 0);
                bottom = intent.getFloatExtra("oriBottom", 0);
            } else if (action.equals(ACTION_VIEW_UP)) {
                left = 0;
                top = 0;
                right = 0;
                bottom = 0;
            }
            rect.set((int) left, (int) top, (int) right, (int) bottom);
            rectLine.set((int) left + lineWidth / 2, (int) top + lineWidth / 2,
                    (int) right - lineWidth / 2, (int) bottom - lineWidth / 2);
            invalidate();
        }
    };
}
CustomView.java
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;


public class CustomView extends HwkDragScaleView {

    @Override
    protected void onLayoutSingleClick() {
        Log.e("hwk", "onLayoutSingleClick----单击");
    }

    @Override
    protected void onLayoutDoubleClick() {
        Log.e("hwk", "onLayoutDoubleClick----双击");
    }

    @Override
    protected void onLayoutLongClick() {
        Log.e("hwk", "onLayoutLongClick----长按");
    }

    @Override
    protected void onLayoutMove(float oldLeft, float oldTop, float oldRight, float oldBottom, float left, float top, float right, float bottom) {
        Log.e("hwk", "onLayoutMove----移动 原始大小 left=" + oldLeft + " top=" + oldTop + " right=" + oldRight + " bottom=" + oldBottom);
        Log.e("hwk", "onLayoutMove----移动 left=" + left + " top=" + top + " right=" + right + " bottom=" + bottom);
    }

    @Override
    protected void onLayoutZoom(float oldLeft, float oldTop, float oldRight, float oldBottom, float left, float top, float right, float bottom) {
        Log.e("hwk", "onLayoutZoom----缩放 原始大小 left=" + oldLeft + " top=" + oldTop + " right=" + oldRight + " bottom=" + oldBottom);
        Log.e("hwk", "onLayoutZoom---- 缩放=" + left + " top=" + top + " right=" + right + " bottom=" + bottom);
    }

    @Override
    protected void onLayoutReset() {

    }

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

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

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

    private void init() {
        View.inflate(getContext(), R.layout.testview, this);
    }

}
HwkDragScaleView.java
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.ScaleAnimation;
import android.view.animation.TranslateAnimation;
import android.widget.RelativeLayout;


public abstract class HwkDragScaleView extends RelativeLayout implements View.OnTouchListener {
    private String TAG = HwkDragScaleView.class.getName();

    private int screenWidth, screenHeight;
    private float lastX, lastY;
    private float oriLeft, oriRight, oriTop, oriBottom;
    private boolean isLeft, isRight, isTop, isBottom;//四边是否到达边距,如果到达边距,则不再继续缩放
    public static final int TOP = 0x15;
    public static final int LEFT = 0x16;
    public static final int BOTTOM = 0x17;
    public static final int RIGHT = 0x18;
    public static final int LEFT_TOP = 0x11;
    public static final int RIGHT_TOP = 0x12;
    public static final int LEFT_BOTTOM = 0x13;
    public static final int RIGHT_BOTTOM = 0x14;
    public static final int CENTER = 0x19;
    private int minWidth = 320, minHeight = 180;//最小矩形
    private int Control_Distance = 55;//手势控制边距
    private static final int MAX_LONG_PRESS_TIME = 400;// 长按/双击最长等待时间
    private static final int MAX_SINGLE_CLICK_TIME = 220;// 单击后等待的时间
    private static final int MIN_DISTANCE = 5; //最小滑动距离
    private int mClickCount;// 点击次数
    private float mDownX;
    private float mDownY;
    private long mLastDownTime;
    private long mFirstClick;
    private long mSecondClick;
    private boolean isDoubleClick = false;
    private final Handler mBaseHandler = new Handler();

    private int dragDirection;
    private float dxNum, dyNum = 0;//xy方向移动的累计距离

    private boolean isCanHandleEdgu = true;//是否可以操作边界,如果不可操作边界,则认为是等比例缩放,16/9
    private static final float defaultScale = (float) 16 / 9;

    
    protected abstract void onLayoutSingleClick();

    
    protected abstract void onLayoutDoubleClick();

    
    protected abstract void onLayoutLongClick();

    
    protected abstract void onLayoutMove(float oldLeft, float oldTop, float oldRight, float oldBottom, float left, float top, float right, float bottom);

    
    protected abstract void onLayoutZoom(float oldLeft, float oldTop, float oldRight, float oldBottom, float left, float top, float right, float bottom);

    
    protected abstract void onLayoutReset();

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

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

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

    private void init() {
        int[] size = UIUtil.getWidthAndHeightToSize(getContext());
        screenWidth = size[0];
        screenHeight = size[1];
        setOnTouchListener(this);
        setWillNotDraw(false);
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        int action = event.getAction();
        if (action == MotionEvent.ACTION_DOWN) {
            isLeft = false;
            isTop = false;
            isRight = false;
            isBottom = false;
            oriLeft = v.getLeft();
            oriTop = v.getTop();
            oriRight = v.getRight();
            oriBottom = v.getBottom();
            lastY = (int) event.getRawY();
            lastX = (int) event.getRawX();

            dragDirection = getDirection(v, event.getX(), event.getY());

            mLastDownTime = System.currentTimeMillis();
            mDownX = event.getX();
            mDownY = event.getY();
            mClickCount++;
            if (mSingleClickTask != null) {
                mBaseHandler.removeCallbacks(mSingleClickTask);
            }
            if (!isDoubleClick) {
                mBaseHandler.postDelayed(mLongPressTask, MAX_LONG_PRESS_TIME);
            }
            if (1 == mClickCount) {
                mFirstClick = System.currentTimeMillis();
            } else if (mClickCount == 2) {// 双击
                mSecondClick = System.currentTimeMillis();
                if (mSecondClick - mFirstClick <= MAX_LONG_PRESS_TIME) {
                    //处理双击
                    mDoubleClickTask();
                }
            }

            Intent intent = new Intent(TopDrawView.ACTION_VIEW_DOWN);
            intent.putExtra("oriLeft", oriLeft);
            intent.putExtra("oriTop", oriTop);
            intent.putExtra("oriRight", oriRight);
            intent.putExtra("oriBottom", oriBottom);
            getContext().sendBroadcast(intent);
        }
        // 处理拖动事件
        delDrag(v, event, action);
        invalidate();
        return true;
    }

    
    protected void delDrag(final View v, MotionEvent event, int action) {
        switch (action) {
            case MotionEvent.ACTION_MOVE:
                if (isTop || isRight || isBottom || isLeft) {
                    return;
                }
                float mMoveX = event.getX();
                float mMoveY = event.getY();
                if (Math.abs(mMoveX - mDownX) > MIN_DISTANCE || Math.abs(mMoveY - mDownY) > MIN_DISTANCE) {
                    //移动了
                    mBaseHandler.removeCallbacks(mLongPressTask);
                    mBaseHandler.removeCallbacks(mSingleClickTask);
                    isDoubleClick = false;
                    mClickCount = 0;
                }

                float dx = event.getRawX() - lastX;
                float dy = event.getRawY() - lastY;
                //是不是XY轴都移动了,四角移动缩放的时候判断条件
                boolean isXYMove = Math.abs(dx) > 0 && Math.abs(dy) > 0;
                float[] ints = new float[2];
                if (isXYMove) {
                    ints = defaultScaleCalculate(dx, dy);
                }
                switch (dragDirection) {
                    case LEFT: // 左边缘
                        if (isCanHandleEdgu)
                            left(v, dx);
                        break;
                    case RIGHT: // 右边缘
                        if (isCanHandleEdgu)
                            right(v, dx);
                        break;
                    case BOTTOM: // 下边缘
                        if (isCanHandleEdgu)
                            bottom(v, dy);
                        break;
                    case TOP: // 上边缘
                        if (isCanHandleEdgu)
                            top(v, dy);
                        break;
                    case CENTER: // 点击中心-->>移动
                        center(v, dx, dy);
                        break;
                    case LEFT_BOTTOM: // 左下
                        if (isXYMove) {
                            left(v, ints[0]);
                            bottom(v, ints[1]);
                        }
                        break;
                    case LEFT_TOP: // 左上
                        if (isXYMove) {
                            left(v, ints[0]);
                            top(v, ints[1]);
                        }
                        break;
                    case RIGHT_BOTTOM: // 右下
                        if (isXYMove) {
                            right(v, ints[0]);
                            bottom(v, ints[1]);
                        }
                        break;
                    case RIGHT_TOP: // 右上
                        if (isXYMove) {
                            right(v, ints[0]);
                            top(v, ints[1]);
                        }
                        break;
                }
                Intent intent = new Intent(TopDrawView.ACTION_VIEW_MOVE);
                if (dragDirection != CENTER) {
                    intent.putExtra("type", TopDrawView.VIEW_ZOOM);
                } else {
                    intent.putExtra("type", TopDrawView.VIEW_MOVE);
                }
                intent.putExtra("oriLeft", oriLeft);
                intent.putExtra("oriTop", oriTop);
                intent.putExtra("oriRight", oriRight);
                intent.putExtra("oriBottom", oriBottom);
                getContext().sendBroadcast(intent);

                lastX = event.getRawX();
                lastY = event.getRawY();
                break;
            case MotionEvent.ACTION_UP:
                long mLastUpTime = System.currentTimeMillis();
                float mUpX = event.getX();
                float mUpY = event.getY();
                if (Math.abs(mUpX - mDownX) <= MIN_DISTANCE && Math.abs(mUpY - mDownY) <= MIN_DISTANCE) {
                    if ((mLastUpTime - mLastDownTime) <= MAX_LONG_PRESS_TIME) {
                        mBaseHandler.removeCallbacks(mLongPressTask);
                        if (!isDoubleClick) {
                            mBaseHandler.postDelayed(mSingleClickTask, MAX_SINGLE_CLICK_TIME);
                        }
                    } else {
                        //超出了双击间隔时间
                        mClickCount = 0;
                    }
                } else {
                    //移动了
                    mBaseHandler.removeCallbacks(mLongPressTask);
                    mBaseHandler.removeCallbacks(mSingleClickTask);
                    isDoubleClick = false;
                    mClickCount = 0;//移动了

                    if (dragDirection == CENTER) {
                        onLayoutMove(getLeft(), getTop(), getRight(), getBottom(), oriLeft, oriTop, oriRight, oriBottom);
                    } else {
                        if (isCanHandleEdgu) {
                            //允许操控边界,任意位置都可触发缩放事件
                            onLayoutZoom(getLeft(), getTop(), getRight(), getBottom(), oriLeft, oriTop, oriRight, oriBottom);
                        } else {
                            //不允许操控边界的时候,只有四个角才能触发缩放事件
                            if (dragDirection == LEFT_TOP || dragDirection == RIGHT_TOP || dragDirection == RIGHT_BOTTOM || dragDirection == LEFT_BOTTOM) {
                                onLayoutZoom(getLeft(), getTop(), getRight(), getBottom(), oriLeft, oriTop, oriRight, oriBottom);
                            }
                        }
                    }
                }
                if (isDoubleClick) {
                    isDoubleClick = false;
                }
                getViewHandleAnimation();

                dragDirection = 0;
                dxNum = 0;
                dyNum = 0;
                getContext().sendBroadcast(new Intent(TopDrawView.ACTION_VIEW_UP));
                break;
        }
    }

    private float[] defaultScaleCalculate(float dx, float dy) {
        float[] result = new float[2];//0标识dx,1标识dy
        result[0] = dx;
        result[1] = dy;
        //X方向移动较多,以X轴移动为基准,计算出Y轴移动距离
        if (Math.abs(dx) > defaultScale * Math.abs(dy)) {
            result[1] = dx / defaultScale;
            if (dragDirection == RIGHT_BOTTOM || dragDirection == LEFT_TOP) {
                if (dx > 0) {
                    result[1] = Math.abs(result[1]);
                } else if (dx < 0) {
                    result[1] = -Math.abs(result[1]);
                }
            } else if (dragDirection == RIGHT_TOP || dragDirection == LEFT_BOTTOM) {
                if (dx > 0) {
                    result[1] = -Math.abs(result[1]);
                } else if (dx < 0) {
                    result[1] = Math.abs(result[1]);
                }
            }
            //Y方向移动较多,以Y轴移动为基准,计算出Y轴移动距离
        } else if (Math.abs(dx) < defaultScale * Math.abs(dy)) {
            result[0] = dy * defaultScale;
            if (dragDirection == RIGHT_BOTTOM || dragDirection == LEFT_TOP) {
                if (dy > 0) {
                    result[0] = Math.abs(result[0]);
                } else if (dy < 0) {
                    result[0] = -Math.abs(result[0]);
                }
            } else if (dragDirection == RIGHT_TOP || dragDirection == LEFT_BOTTOM) {
                if (dy > 0) {
                    result[0] = -Math.abs(result[0]);
                } else if (dy < 0) {
                    result[0] = Math.abs(result[0]);
                }
            }
        }
        return result;
    }

    
    private void center(View v, float dx, float dy) {
        dxNum += dx;
        dyNum += dy;
        oriLeft = v.getLeft() + dxNum;
        oriTop = v.getTop() + dyNum;
        oriRight = v.getRight() + dxNum;
        oriBottom = v.getBottom() + dyNum;
        if (oriLeft < 0) {
            oriLeft = 0;
            oriRight = oriLeft + v.getWidth();
        }
        if (oriRight > screenWidth) {
            oriRight = screenWidth;
            oriLeft = oriRight - v.getWidth();
        }
        if (oriTop < 0) {
            oriTop = 0;
            oriBottom = oriTop + v.getHeight();
        }
        if (oriBottom > screenHeight) {
            oriBottom = screenHeight;
            oriTop = oriBottom - v.getHeight();
        }
    }

    
    private void top(View v, float dy) {
        if (isTop && dy < 0) {
            return;
        }
        oriTop += dy;
        if (oriTop < 0) {
            oriTop = 0;
            isTop = true;
        } else {
            isTop = false;
        }
        if (oriBottom - oriTop < minHeight) {
            oriTop = oriBottom - minHeight;
        }
    }

    
    private void bottom(View v, float dy) {
        if (isBottom && dy > 0) {
            return;
        }
        oriBottom += dy;
        if (oriBottom > screenHeight) {
            oriBottom = screenHeight;
            isBottom = true;
        } else {
            isBottom = false;
        }
        if (oriBottom - oriTop < minHeight) {
            oriBottom = minHeight + oriTop;
        }
    }

    
    private void right(View v, float dx) {
        if (isRight && dx > 0) {
            return;
        }
        oriRight += dx;
        if (oriRight > screenWidth) {
            oriRight = screenWidth;
            isRight = true;
        } else {
            isRight = false;
        }
        if (oriRight - oriLeft < minWidth) {
            oriRight = oriLeft + minWidth;
        }
    }

    
    private void left(View v, float dx) {
        if (isLeft && dx < 0) {
            return;
        }
        oriLeft += dx;
        if (oriLeft < 0) {
            oriLeft = 0;
            isLeft = true;
        } else {
            isLeft = false;
        }
        if (oriRight - oriLeft < minWidth) {
            oriLeft = oriRight - minWidth;
        }
    }

    
    protected int getDirection(View v, float x, float y) {
        int left = v.getLeft();
        int right = v.getRight();
        int bottom = v.getBottom();
        int top = v.getTop();
        if (x < Control_Distance && y < Control_Distance) {
            return LEFT_TOP;
        }
        if (y < Control_Distance && right - left - x < Control_Distance) {
            return RIGHT_TOP;
        }
        if (x < Control_Distance && bottom - top - y < Control_Distance) {
            return LEFT_BOTTOM;
        }
        if (right - left - x < Control_Distance && bottom - top - y < Control_Distance) {
            return RIGHT_BOTTOM;
        }
        if (x < Control_Distance) {
            return LEFT;
        }
        if (y < Control_Distance) {
            return TOP;
        }
        if (right - left - x < Control_Distance) {
            return RIGHT;
        }
        if (bottom - top - y < Control_Distance) {
            return BOTTOM;
        }
        return CENTER;
    }

    
    private Animation getViewHandleAnimation() {
        Animation mAnimation;
        if (dragDirection == CENTER) {//平移
            mAnimation = new TranslateAnimation(0, oriLeft - getLeft(), 0, oriTop - getTop());
        } else {//缩放
            float scaleX = (float) (Math.abs(oriRight - oriLeft)) / getWidth();
            float scaleY = (float) (Math.abs(oriBottom - oriTop)) / getHeight();
            float pivotX = 0;
            float pivotY = 0;
            if (dragDirection == LEFT_TOP) {
                pivotX = 1f;
                pivotY = 1f;
            } else if (dragDirection == RIGHT_TOP) {
                pivotX = 0f;
                pivotY = 1f;
            } else if (dragDirection == RIGHT_BOTTOM) {
                pivotX = 0f;
                pivotY = 0f;
            } else if (dragDirection == LEFT_BOTTOM) {
                pivotX = 1f;
                pivotY = 0f;
            } else if (dragDirection == LEFT) {
                pivotX = 1f;
            } else if (dragDirection == TOP) {
                pivotY = 1f;
            } else if (dragDirection == RIGHT) {
                pivotX = 0f;
            } else if (dragDirection == BOTTOM) {
                pivotY = 0f;
            }
            mAnimation = new ScaleAnimation(1f, scaleX, 1f, scaleY, Animation.RELATIVE_TO_SELF, pivotX, Animation.RELATIVE_TO_SELF, pivotY);
        }
        mAnimation.setDuration(400);//时长
        mAnimation.setFillAfter(true);
        mAnimation.setFillEnabled(true);//填充效果不回到原地
        setAnimation(mAnimation);//为控件绑定动画
        startAnimation(mAnimation);
        mAnimation.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {
            }

            @Override
            public void onAnimationEnd(Animation animation) {
                clearAnimation();
                postInvalidate();
                RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams((int) (oriRight - oriLeft), (int) (oriBottom - oriTop));
                params.leftMargin = (int) oriLeft;
                params.topMargin = (int) oriTop;
                setLayoutParams(params);
            }

            @Override
            public void onAnimationRepeat(Animation animation) {
            }
        });
        return mAnimation;
    }

    private final Runnable mSingleClickTask = new Runnable() {
        @Override
        public void run() {
            // 处理单击
            mClickCount = 0;
            onLayoutSingleClick();
        }
    };
    private final Runnable mLongPressTask = new Runnable() {
        @Override
        public void run() {
            //处理长按
            mClickCount = 0;
            onLayoutLongClick();
        }
    };

    private void mDoubleClickTask() {
        //处理双击
        isDoubleClick = true;
        mClickCount = 0;
        mFirstClick = 0;
        mSecondClick = 0;
        mBaseHandler.removeCallbacks(mSingleClickTask);
        mBaseHandler.removeCallbacks(mLongPressTask);
        //双击
        onLayoutDoubleClick();
    }
}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1014920.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号