如何判断ImageView移动指定距离的时机并修复Toast重复弹出问题
问题原因
AnimatorUpdateListener会在动画执行过程中每帧回调一次,只要当前移动距离超过阈值,每帧都会触发一次Toast,导致多次弹出。- 若上一次点击触发的动画未结束就再次点击,旧动画的监听器还会持续运行,用旧的起始坐标计算距离,会出现距离未达标也弹出Toast的误触发问题。
修复方案
- 增加一个布尔标志位,标记本次动画是否已经弹出过Toast,避免同一次动画重复触发。
- 每次启动新动画前,先取消上一次正在运行的动画,移除旧的监听器,避免旧逻辑干扰。
- 可选优化:预先计算本次动画的总移动距离,如果总距离本身小于阈值,无需在帧回调中做判断,减少不必要的性能消耗。
修复后代码示例
private final int MAX_LENGTH = 420; private int xRand, yRand; private int xStart, yStart; private boolean hasShownToast = false; // 新增标志位 private View unlimitePlayView; private ImageView circle; private ObjectAnimator animCircle; // 需将animCircle声明为成员变量 public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { super.onCreateView(inflater, container, savedInstanceState); unlimitePlayView = inflater.inflate(R.layout.fragment_tournament, container, false); circle = unlimitePlayView.findViewById(R.id.circle); circle.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { // 先取消上一次动画,移除旧监听器 if (animCircle != null && animCircle.isRunning()) { animCircle.cancel(); animCircle.removeAllUpdateListeners(); } // 重置标志位 hasShownToast = false; xStart = (int) circle.getX(); yStart = (int) circle.getY(); xRand = new Random().nextInt(deviceWidth - circle.getWidth()); yRand = new Random().nextInt(deviceHeight - circle.getHeight()); // 可选:先计算总距离,不足阈值直接执行动画无需后续判断 int totalDistance = (int) Math.sqrt(Math.pow(Math.abs(xRand - xStart), 2) + Math.pow(Math.abs(yRand - yStart), 2)); if (totalDistance < MAX_LENGTH) { Path path = new Path(); path.moveTo(xStart, yStart); path.lineTo(xRand, yRand); animCircle = ObjectAnimator.ofFloat(circle, "x", "y", path); animCircle.setDuration(1000); animCircle.start(); return; } Path path = new Path(); path.moveTo(xStart, yStart); path.lineTo(xRand, yRand); animCircle = ObjectAnimator.ofFloat(circle, "x", "y", path); animCircle.setDuration(1000); animCircle.start(); animCircle.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { float currentX = (float) valueAnimator.getAnimatedValue("x"); float currentY = (float) valueAnimator.getAnimatedValue("y"); int currentLength = (int) Math.sqrt(Math.pow(Math.abs(currentX - xStart), 2) + Math.pow(Math.abs(currentY - yStart), 2)); // 增加标志位判断,仅第一次满足条件时弹出Toast if (currentLength > MAX_LENGTH && !hasShownToast) { hasShownToast = true; Toast.makeText(getActivity(), "DONE", Toast.LENGTH_SHORT).show(); } } }); } }); return unlimitePlayView; }
内容的提问来源于stack exchange,提问作者AnatolyS
相关产品推荐
相关产品推荐

