android仿地铁行进线路图

在坐地铁的时候,能看到有些地铁上是有地铁行进动画和站点到达动画的,最近在做项目的时候,就有一个类似这样的需求,不同的是展示的点有限制,多出来的点是需要是折贴起来的,当需要展示时再拉出来,大致动画如下:
在这里插入图片描述
看到这样一个动画,你有什么想法呢?对于这个动画,我有一个同事使用的是RecycleView去做的,做出来后差不多有十几个类,里面的逻辑还是比较复杂的,由于同事离职,这里面还有一些问题存在,由我接手修改,确实不太好改,没办法,尝试自己撸一个。对于这样一个动画,我首先想到的是使用自定义View来解决。先来说一下绘制这个View的大致思路:先绘制静态的,在绘制动态的。
1、如何绘制静态的呢,这个比较简单,不过这里需要考虑一个问题,站点抽出是向左抽出的,所以绘制时应该从右边开始画,主要的界面是由圆还有线绘制成的,这些都很简单,现在主要来说说这写点线位置的计算,首先一开始左右位置的间隙是对称的,这里可以根据预先设置的点的个数,根据屏宽和预先设置的参数计算出线的长短,这样就可以画出这些点还有线了,点还有线绘制完后,就差文字及其背景了,文字这个不多说,背景其实也就是一条线,只不过是比较宽而已。
2、比较难的是动态绘制的处理,可以看出,点一次可以拉出1~3个,这里将一个点和一条线看做是一段长,这里先上一段代码:

private void initAnimator() {
        animator = new ValueAnimator();
        animator.addUpdateListener(animation -> {
            changeX = (float) animation.getAnimatedValue();
            if ((int) (changeX / lineWithdotWidth) == flag) {
                headPositionIndex++;
                flag++;
            }
            changeX = changeX % lineWithdotWidth;
            isScrolling = true;
            invalidate();
        });
        animator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                isScrolling = false;
                flag = 1;
            }
        });
    }

后面动画用到的主要就是这个changeX,根据这个changX去绘制点和线,由于拉出的过程都是在一个点和线之间的距离变化的,所以这个changeX就是在这个范围内变化的,大致的思路就是这样,当然里面还有好多细节需要去处理,代码主要分为三个类,其中两个是处理点位数据的,比较简单:

public class IndicatorPositionDatas {

    private List<PositionData> positionList = new ArrayList<>();

    public IndicatorPositionDatas(List<String> list) {
        boolean isTextUp;
        int size = list.size();
        for (int i = 0; i < size-1; i++) {
            isTextUp = (i % 2 == 0);
            PositionData positionData = new PositionData(list.get(i),isTextUp,i);
            positionList.add(positionData);
        }
        PositionData positionData = new PositionData(list.get(size-1),true,size-1);
        positionList.add(positionData);
    }

    public PositionData getLastPosition(){
        return positionList.get(positionList.size()-1);
    }

    public PositionData getCurrentPosition(int position){
        return positionList.get(position);
    }

    public int size(){
        return positionList.size();
    }

}
public class PositionData {

    private String positionText;
    private boolean isTextUp;
    private int position;

    public PositionData(String positionText, boolean isTextUp,int position) {
        this.positionText = positionText;
        this.isTextUp = isTextUp;
        this.position = position;
    }

    public String getText() {
        return positionText;
    }

    public boolean isTextUp() {
        return isTextUp;
    }

    public int getPosition() {
        return position;
    }

    public void setPosition(int position) {
        this.position = position;
    }
}

接下来就是自定义的View类:

public class IndicatorViewGroup extends View {
    private static final String TAG = "IndicatorViewGroup";
    private Paint mPaintText;
    private Paint mPaintLine;
    private Paint mPaintTextBg;
    private Paint mPaintDot;
    private Paint mPaintLoopDot;
    private int lineNoWalkColor = 0xFF219BFF;
    private int lineWalkedColor = 0xFF999999;
    private int dotStartColor = 0xFFFCB300;
    private int dotEndColor = 0xFFEA0075;
    private int textBackground = 0xFFF4F4F9;
    private int dotWidthAndHeight;
    private int lineLength;
    private int leftRightPadding;
    private int lineWidth;
    private int textBgWidth;
    //绘制文字背景时,背景距离dot的距离
    private int textBgMarginDot;
    //绘制文字时定位的Y方向坐标
    private float textTopBaseline;
    private float textBottomBaseline;
    //绘制文字背景定位的中心线
    private float textBgTopCenter;
    private float textBgBottomCenter;
    private float changeX = 0;
    private int animatorTime = 4000;
    private int dotFlashTime = 500;
    private ValueAnimator animator;
    private int textSize = 16;
    private IndicatorPositionDatas positionDatas;
    private int headPositionIndex = 0;
    private int arrivePosition = 0;
    private String textMore = "更多(%d)";
    //绘制在上边文本的位置信息
    private int dotTopPosition;
    //绘制下边文本的位置信息
    private int dotBottomPosition;
    private int flag = 1;
    private boolean isScrolling;
    //view的垂直居中位置
    private int centerY;
    private int lineWithdotWidth;
    private boolean isWalking = false;
    private long timeFlag;
    //外圆环的宽度
    private int loopDotStroke;
    //绘制点所需要的参数,cx是点的中心点
    private float cx;
    private float dotRadius;
    private float loopDotRadius;
    private float lineWithCircleGap;
    private float dotOffset;

    /**
     * 去往目的点的途中
     */
    public void arriveNext() {
        if (!isWalking && arrivePosition == positionDatas.size() - 1) {
            Toast.makeText(getContext(), "已经到终点了", Toast.LENGTH_SHORT).show();
            return;
        }
        if (isWalking) {
            isWalking = false;
            if (headPositionIndex + 3 == arrivePosition) {
                if (arrivePosition < positionDatas.size() - 3) {
                    startAnimator();
                }
            }
            return;
        }
        timeFlag = System.currentTimeMillis();
        isWalking = true;
        arrivePosition++;
        invalidate();
    }

    /**
     * 到达目的点
     */
    public void arriveTo() {
        if (!isWalking && arrivePosition == positionDatas.size() - 1) {
            Toast.makeText(getContext(), "已经到终点了", Toast.LENGTH_SHORT).show();
            return;
        }
        if (isWalking) {
            isWalking = false;
            if (headPositionIndex + 3 == arrivePosition) {
                if (arrivePosition < positionDatas.size() - 3) {
                    startAnimator();
                }
            }
        }
    }

    /**
     * 开启展开动画
     */
    public void startAnimator() {
        int count = isScrolling ? 6 : 5;
        int moreCount = positionDatas.size() - headPositionIndex - count;
        if (moreCount == 3) {
            animator.setFloatValues(2 * lineWithdotWidth);
            animator.setDuration(animatorTime * 2 / 3);
        } else if (moreCount == 2) {
            animator.setFloatValues(lineWithdotWidth);
            animator.setDuration(animatorTime / 3);
        } else {
            animator.setFloatValues(3 * lineWithdotWidth);
            animator.setDuration(animatorTime);
        }
        animator.start();
    }

    /**
     * @param arrivePosition 所在的位置点
     */
    public void setArrivePosition(int arrivePosition) {
        this.arrivePosition = arrivePosition;
    }

    /**
     * @param list 点位数据
     */
    public void setPositionDatas(ArrayList<String> list) {
        positionDatas = new IndicatorPositionDatas(list);
    }

    /**
     * @param size 位置点上文字的大小
     */
    public void setTextSize(int size) {
        textSize = size;
    }

    /**
     * @param lineWidth 路线线条的宽度
     */
    public void setLineWidth(int lineWidth) {
        this.lineWidth = lineWidth;
    }

    /**
     * @param textBgWidth 文字背景的宽度
     */
    public void setTextBgWidth(int textBgWidth) {
        this.textBgWidth = textBgWidth;
    }

    /**
     * @param marginDot 文字距离原点的距离
     */
    public void setTextBgMarginDot(int marginDot) {
        textBgMarginDot = marginDot;
    }


    /**
     * @param animatorTime 设置展开三个点所需的时间,单位是ms
     */
    public void setAnimatorTime(int animatorTime) {
        this.animatorTime = animatorTime;
    }

    /**
     * @param dotFlashTime 设置点位闪动的时间间隔
     */
    public void setDotFlashTime(int dotFlashTime) {
        this.dotFlashTime = dotFlashTime;
    }

    /**
     * @param lineWithCircleGap 线与点之间的间隔
     */
    public void setLineWithCircleGap(float lineWithCircleGap) {
        this.lineWithCircleGap = lineWithCircleGap;
    }

    public IndicatorViewGroup(Context context) {
        super(context);
    }

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

    public IndicatorViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initParams();
        initDotParams();
        initPaint();
        initAnimator();
    }

    private void initPaint() {
        mPaintText = new Paint();
        mPaintText.setAntiAlias(true);
        mPaintText.setColor(Color.BLACK);
        mPaintText.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, textSize, getResources().getDisplayMetrics()));

        mPaintLine = new Paint();
        mPaintLine.setAntiAlias(true);
        mPaintLine.setColor(lineNoWalkColor);
        mPaintLine.setStrokeWidth(lineWidth);
        mPaintLine.setStyle(Paint.Style.FILL);
        mPaintLine.setStrokeCap(Paint.Cap.ROUND);

        mPaintTextBg = new Paint();
        mPaintTextBg.setAntiAlias(true);
        mPaintTextBg.setColor(textBackground);
        mPaintTextBg.setStrokeWidth(textBgWidth);
        mPaintTextBg.setStyle(Paint.Style.FILL);
        mPaintTextBg.setStrokeCap(Paint.Cap.ROUND);

        mPaintDot = new Paint();
        mPaintDot.setAntiAlias(true);
        mPaintDot.setColor(lineNoWalkColor);
        mPaintDot.setStyle(Paint.Style.FILL);

        mPaintLoopDot = new Paint();
        mPaintLoopDot.setAntiAlias(true);
        mPaintLoopDot.setColor(Color.parseColor("#FFFFFF"));
        mPaintLoopDot.setStrokeWidth(loopDotStroke);
        mPaintLoopDot.setStyle(Paint.Style.STROKE);
    }

    private void initParams() {
        leftRightPadding = (int) px2Dp(27);
        lineWidth = (int) px2Dp(10);
        textBgWidth = (int) px2Dp(30);
        textBgMarginDot = (int) px2Dp(5);
        dotRadius = px2Dp(14);
        lineWithCircleGap = px2Dp(13);
        loopDotStroke = (int) px2Dp(3);
        dotOffset = px2Dp(6);
    }

    private float px2Dp(int px) {
        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, px, getContext().getResources().getDisplayMetrics());
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int width = MeasureSpec.getSize(widthMeasureSpec);
        lineLength = (width - 2 * leftRightPadding - 6 * dotWidthAndHeight) / 5;
        lineWithdotWidth = dotWidthAndHeight + lineLength;
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = dotWidthAndHeight + textBgMarginDot * 2 + textBgWidth * 2 + (int) px2Dp(10);
        if (heightSize > MeasureSpec.getSize(heightMeasureSpec)) {
            heightMeasureSpec = MeasureSpec.makeMeasureSpec(heightSize, heightMode);
        }
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        initArrivePosition();
    }

    /**
     * 初始化所在的位置点是否需要展开
     */
    private void initArrivePosition() {
        if (!isMorePosition() || arrivePosition == 0) return;
        if (arrivePosition % 3 == 0) {
            headPositionIndex = (arrivePosition - 1) / 3 * 3;
            postDelayed(this::startAnimator, 1000);
        }
    }

    private boolean isMorePosition() {
        return positionDatas.size() > 6;
    }

    private void initDotParams() {
        dotWidthAndHeight = (int) (dotRadius + lineWithCircleGap) * 2;
        loopDotRadius = dotRadius + loopDotStroke / 2f;
        cx = dotWidthAndHeight / 2f;
    }

    private void initAnimator() {
        animator = new ValueAnimator();
        animator.addUpdateListener(animation -> {
            changeX = (float) animation.getAnimatedValue();
            if ((int) (changeX / lineWithdotWidth) == flag) {
                headPositionIndex++;
                flag++;
            }
            changeX = changeX % lineWithdotWidth;
            isScrolling = true;
            invalidate();
        });
        animator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                isScrolling = false;
                flag = 1;
            }
        });
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        centerY = getHeight() / 2;
        dotTopPosition = centerY - dotWidthAndHeight / 2;
        dotBottomPosition = centerY + dotWidthAndHeight / 2;
        mPaintText.measureText(positionDatas.getLastPosition().getText());
        Paint.FontMetrics fm = mPaintText.getFontMetrics();
        textTopBaseline = dotTopPosition - fm.descent - textBgMarginDot;
        textBottomBaseline = dotBottomPosition + fm.descent - fm.ascent + textBgMarginDot - px2Dp(2);
        textBgTopCenter = dotTopPosition - (fm.bottom - fm.top) / 2 - textBgMarginDot;
        textBgBottomCenter = dotBottomPosition + (fm.bottom - fm.top) / 2 + textBgMarginDot;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        drawPosition(canvas);
    }

    private void drawPosition(Canvas canvas) {
        if (isMorePosition()) {
            canvas.translate(getWidth() - dotWidthAndHeight - leftRightPadding + dotOffset, 0);
        } else {
            canvas.translate(getWidth() - dotWidthAndHeight - leftRightPadding - (6 - positionDatas.size()) * lineWithdotWidth, 0);
        }
        drawDot(canvas, positionDatas.getLastPosition());
        translateLine(canvas);
        if (arrivePosition == positionDatas.size() - 1) {
            mPaintLine.setColor(lineWalkedColor);
        } else {
            mPaintLine.setColor(lineNoWalkColor);
        }
        drawLine(canvas, positionDatas.getLastPosition());
        int dotIndex = 3;
        translateBit(canvas);
        if (isMorePosition()) {
            //绘制拉出的那个点
            canvas.translate(-2 * dotOffset, 0);
            if (changeX != 0) {
                unfoldPosition(canvas);
            }
        } else {
            dotIndex = positionDatas.size() - 3;
        }
        //绘制倒数第二个点
        drawDot(canvas, positionDatas.getCurrentPosition(positionDatas.size() - 2));

        int index;
        for (int i = dotIndex; 0 <= i; i--) {
            translateLine(canvas);
            index = headPositionIndex + i;
            int lineColor = arrivePosition <= index ? lineNoWalkColor : lineWalkedColor;
            mPaintLine.setColor(lineColor);
            PositionData currentPosition = positionDatas.getCurrentPosition(index);
            drawLine(canvas, currentPosition);
            translateBit(canvas);
            drawDot(canvas, currentPosition);
        }
        if (headPositionIndex != 0) {
            mPaintLine.setColor(lineWalkedColor);
            mPaintLine.setShader(null);
            canvas.drawLine(-lineLength / 2f, centerY, 0, centerY, mPaintLine);
        }

        if (!isScrolling) {
            invalidate();
        }
    }

    private void unfoldPosition(Canvas canvas) {
        canvas.translate(-changeX, 0);
        mPaintDot.setColor(lineNoWalkColor);
        canvas.drawCircle(cx, centerY, dotRadius, mPaintDot);
        canvas.drawCircle(cx, centerY, loopDotRadius, mPaintLoopDot);
        if (changeX > dotWidthAndHeight) {
            float stopX;
            if (changeX > dotWidthAndHeight + lineLength) {
                stopX = dotWidthAndHeight + lineLength;
            } else {
                stopX = changeX + 10;
            }
            canvas.drawLine(dotWidthAndHeight, centerY, stopX, centerY, mPaintLine);
        }

        if (lineLength > changeX) {
            int alpha = (int) (changeX / lineLength * 255);
            mPaintText.setAlpha(alpha);
        }
        drawText(canvas, positionDatas.getCurrentPosition(headPositionIndex + 4));
        mPaintText.setAlpha(255);
    }

    private void translateLine(Canvas canvas) {
        canvas.translate(-lineLength, 0);
    }

    private void translateBit(Canvas canvas) {
        canvas.translate(-dotWidthAndHeight, 0);
    }

    //绘制线以及移动时相应的动画
    private float offsetFlashX;

    private void drawLine(Canvas canvas, PositionData msg) {
        if (msg.getPosition() == arrivePosition - 1 || (arrivePosition == positionDatas.size() - 1 && msg.getPosition() == positionDatas.size() - 1)) {
            if (isWalking) {
                mPaintLine.setColor(dotStartColor);
                LinearGradient backGradient = new LinearGradient(-lineLength + offsetFlashX, 0, offsetFlashX, 0, new int[]{dotStartColor, 0xffffffff, dotStartColor}, null, Shader.TileMode.CLAMP);
                mPaintLine.setShader(backGradient);
            }
        } else {
            mPaintLine.setShader(null);
        }
        offsetFlashX = offsetFlashX + 1f;
        if (offsetFlashX > lineLength * 2) offsetFlashX = 0;
        canvas.drawLine(0, centerY, lineLength, centerY, mPaintLine);
    }

    private void drawDot(Canvas canvas, PositionData msg) {
        int position = msg.getPosition();
        long time = System.currentTimeMillis();
        long toLastTime = time - timeFlag;
        Log.d(TAG, "drawDot: toLastTime = " + toLastTime);
        if (position == arrivePosition) {
            if (toLastTime / dotFlashTime % 2 == 1) {
                mPaintDot.setColor(dotStartColor);
            } else {
                mPaintDot.setColor(0x00000000);
            }
        } else {
            if (position == 0 && arrivePosition == 0) {
                mPaintDot.setColor(dotStartColor);
            } else if (position == positionDatas.size() - 1) {
                mPaintDot.setColor(dotEndColor);
            } else {
                if (position < arrivePosition) {
                    mPaintDot.setColor(lineWalkedColor);
                } else {
                    mPaintDot.setColor(lineNoWalkColor);
                }
            }
        }
        int count = isScrolling ? 6 : 5;
        int moreCount = positionDatas.size() - headPositionIndex - count;
        if (position == positionDatas.size() - 2) {
            if (isMorePosition()) {
                //绘制倒数第二个点
                drawMoreDot(canvas, moreCount);
            } else {
                canvas.drawCircle(cx + changeX, centerY, dotRadius, mPaintDot);
                canvas.drawCircle(cx + changeX, centerY, loopDotRadius, mPaintLoopDot);
            }
            if ((headPositionIndex + 6) < positionDatas.size()) {
                String textName = String.format(textMore, moreCount);
                float textWidth = mPaintText.measureText(textName);
                //绘制文字背景色
                canvas.drawLine(changeX + (-textWidth + dotWidthAndHeight) / 2 + dotOffset, textBgTopCenter,
                        changeX + (textWidth + dotWidthAndHeight) / 2 + dotOffset, textBgTopCenter, mPaintTextBg);
                canvas.drawText(textName, (-textWidth + dotWidthAndHeight) / 2 + changeX + dotOffset, textTopBaseline, mPaintText);
            } else {
                float textWidth = mPaintText.measureText(msg.getText());
                //绘制文字背景
                if (msg.getPosition() == arrivePosition) {
                    mPaintTextBg.setColor(dotStartColor);
                } else {
                    mPaintTextBg.setColor(textBackground);
                }
                if (msg.isTextUp()) {
                    canvas.drawLine((-textWidth + dotWidthAndHeight) / 2 + dotOffset, textBgTopCenter,
                            (textWidth + dotWidthAndHeight) / 2, textBgTopCenter, mPaintTextBg);
                } else {
                    canvas.drawLine((-textWidth + dotWidthAndHeight) / 2 + dotOffset, textBgBottomCenter,
                            (textWidth + dotWidthAndHeight) / 2, textBgBottomCenter, mPaintTextBg);
                }
                //绘制文字
                if (msg.isTextUp()) {
                    canvas.drawText(msg.getText(), (-textWidth + dotWidthAndHeight) / 2 + dotOffset, textTopBaseline, mPaintText);
                } else {
                    canvas.drawText(msg.getText(), (-textWidth + dotWidthAndHeight) / 2 + dotOffset, textBottomBaseline, mPaintText);
                }
            }
        } else {
            canvas.drawCircle(cx, centerY, dotRadius, mPaintDot);
            canvas.drawCircle(cx, centerY, loopDotRadius, mPaintLoopDot);
            drawText(canvas, msg);
        }
    }

    private void drawMoreDot(Canvas canvas, int moreCount) {
        float factor1 = 2;
        float factor2 = 0;
        if (moreCount == 2) {
            factor1 = 2 - changeX / lineWithdotWidth / 2;
            factor2 = changeX / lineWithdotWidth / 2;
            if (changeX == 0) {
                factor1 = 1.5f;
                factor2 = 0.5f;
            }
        }
        if (moreCount == 1) {
            if ((headPositionIndex + 6) < positionDatas.size()) {
                factor1 = 1.5f - changeX / lineWithdotWidth / 2;
                factor2 = changeX / lineWithdotWidth / 2 + 0.5f;
            } else {
                factor1 = factor2 = 1;
            }
        }
        if (factor1 != 1) {
            canvas.drawCircle(cx + changeX + factor1 * dotOffset, centerY, dotRadius, mPaintDot);
            canvas.drawCircle(cx + changeX + factor1 * dotOffset, centerY, loopDotRadius, mPaintLoopDot);
        }
        canvas.drawCircle(cx + changeX + dotOffset, centerY, dotRadius, mPaintDot);
        canvas.drawCircle(cx + changeX + dotOffset, centerY, loopDotRadius, mPaintLoopDot);
        if (factor2 != 1) {
            canvas.drawCircle(cx + changeX + factor2 * dotOffset, centerY, dotRadius, mPaintDot);
            canvas.drawCircle(cx + changeX + factor2 * dotOffset, centerY, loopDotRadius, mPaintLoopDot);
        }
    }


    private void drawText(Canvas canvas, PositionData msg) {
        float textWidth = mPaintText.measureText(msg.getText());
        drawTextBackground(canvas, textWidth, msg);
        if (msg.isTextUp()) {
            canvas.drawText(msg.getText(), (-textWidth + dotWidthAndHeight) / 2, textTopBaseline, mPaintText);
        } else {
            canvas.drawText(msg.getText(), (-textWidth + dotWidthAndHeight) / 2, textBottomBaseline, mPaintText);
        }
    }

    private void drawTextBackground(Canvas canvas, float textWidth, PositionData msg) {
        if (msg.getPosition() == arrivePosition) {
            mPaintTextBg.setColor(dotStartColor);
        } else {
            mPaintTextBg.setColor(textBackground);
        }
        if (msg.isTextUp()) {
            canvas.drawLine((-textWidth + dotWidthAndHeight) / 2, textBgTopCenter,
                    (textWidth + dotWidthAndHeight) / 2, textBgTopCenter, mPaintTextBg);
        } else {
            canvas.drawLine((-textWidth + dotWidthAndHeight) / 2, textBgBottomCenter,
                    (textWidth + dotWidthAndHeight) / 2, textBgBottomCenter, mPaintTextBg);
        }
    }

}

代码到这就算是完成了,代码量不多,用起来也很简单,首先就是在xml中进行添加:

    <com.example.ubt.myapplication.view.IndicatorViewGroup
        android:id="@+id/iv_animator"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        
    </com.example.ubt.myapplication.view.IndicatorViewGroup>

高度这里可以指定高度,但都是会居中绘制的,最后就是在Activity中进行使用了,也比较简单:

		IndicatorViewGroup ivAnimator = (IndicatorViewGroup) findViewById(R.id.iv_animator);
        ivAnimator.setPositionDatas(list);
        findViewById(R.id.btn_start).setOnClickListener(v->ivAnimator.arriveNext());

这样完成后,点击按钮就可以动起来了,代码中还提供了一个arriveTo()方法,为了方便调试,直接将这个方法添加到了arriveNext()中,如果需要使用两个方法,直接把arriveNext()中相同的代码去掉即可,为了整体的视觉感,这里建议将屏幕设置成横屏

  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值