CountDownTimer结束后TextView闪烁致点击无响应问题排查
Hey there! Let's break down why your "Play Again?" TextView stopped responding after adding that blink animation, and how to fix it while keeping your object-oriented structure intact.
First, Let's Confirm the Root Cause
From your description, it’s clear the blink animation is interfering with the TextView’s click event—your playAgain() method isn’t being triggered at all. The most common culprits here are:
- Legacy Animation vs. Property Animation: If you used old-style
Animationclasses (likeAlphaAnimationorColorAnimation), they manipulate the view’s drawing transform instead of its actual properties. This can disconnect the visual animation from the view’s touchable area, making clicks register nowhere. - Unintended State Changes: Some animation setups accidentally toggle the TextView’s
clickableflag, or leave the view in an unstable state (like partial transparency) that blocks touch event dispatch. - Animation Loop Interference: If your animation runs infinitely without proper handling, it might hog the UI thread or prevent the click listener from being registered/triggered.
Fix: Build a Reusable, Object-Oriented Blink Animator
Since you want to keep things modular, let’s create a standalone TextBlinkAnimator class that handles the animation without breaking click functionality. We’ll use ValueAnimator (Android’s modern property animation system) because it modifies the view’s actual properties, so touch events work as expected.
Step 1: Create the Animator Module
public class TextBlinkAnimator { private final TextView targetTextView; private ValueAnimator blinkAnimator; private final int originalTextColor; public TextBlinkAnimator(TextView textView) { this.targetTextView = textView; this.originalTextColor = textView.getCurrentTextColor(); setupBlinkAnimation(); } private void setupBlinkAnimation() { // Animate between 30% and 100% opacity, reverse infinitely blinkAnimator = ValueAnimator.ofFloat(0.3f, 1.0f); blinkAnimator.setDuration(700); blinkAnimator.setRepeatCount(ValueAnimator.INFINITE); blinkAnimator.setRepeatMode(ValueAnimator.REVERSE); // Update TextView properties on each animation tick blinkAnimator.addUpdateListener(animation -> { float alphaValue = (float) animation.getAnimatedValue(); targetTextView.setAlpha(alphaValue); // Fade text color alongside opacity int fadedColor = adjustColorAlpha(originalTextColor, alphaValue); targetTextView.setTextColor(fadedColor); }); } // Helper to adjust color alpha without changing RGB values private int adjustColorAlpha(int color, float alpha) { int red = Color.red(color); int green = Color.green(color); int blue = Color.blue(color); return Color.argb((int) (alpha * 255), red, green, blue); } public void startBlinking() { if (blinkAnimator != null && !blinkAnimator.isRunning()) { targetTextView.setVisibility(View.VISIBLE); blinkAnimator.start(); } } public void stopBlinking() { if (blinkAnimator != null && blinkAnimator.isRunning()) { blinkAnimator.end(); // Reset TextView to original state to avoid lingering issues targetTextView.setAlpha(1.0f); targetTextView.setTextColor(originalTextColor); targetTextView.setVisibility(View.GONE); } } }
Step 2: Integrate the Animator Into Your Game Logic
In your main game class (Activity/ViewModel), use this animator to handle the blink effect, and ensure the click listener stops the animation before triggering playAgain():
// Initialize the animator with your "Play Again?" TextView private TextBlinkAnimator playAgainBlinker; private TextView playAgainTextView; private CountDownTimer gameTimer; private int userScore = 0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_game); playAgainTextView = findViewById(R.id.tv_play_again); playAgainBlinker = new TextBlinkAnimator(playAgainTextView); // Bind click listener to trigger playAgain() playAgainTextView.setOnClickListener(v -> { playAgainBlinker.stopBlinking(); // Stop animation first! playAgain(); }); startGameTimer(); } private void startGameTimer() { gameTimer = new CountDownTimer(60000, 1000) { // 60-second timer @Override public void onTick(long millisUntilFinished) { // Update timer display here } @Override public void onFinish() { // Show final score findViewById(R.id.tv_score).setText("Final Score: " + userScore); // Start blinking the Play Again prompt playAgainBlinker.startBlinking(); } }.start(); } private void playAgain() { // Reset game state: clear score, regenerate math problems, restart timer userScore = 0; findViewById(R.id.tv_score).setText("Score: 0"); startGameTimer(); // Regenerate your arithmetic problems here }
Why This Works
- Property Animation:
ValueAnimatormodifies the TextView’s actualalphaandtextColorproperties, so the view’s touchable area stays aligned with its visual position. - Modular Design: The
TextBlinkAnimatorclass encapsulates all animation logic, keeping your game code clean and adhering to object-oriented principles. - State Reset: When the user clicks "Play Again?", we explicitly stop the animation and reset the TextView to its original state, preventing any lingering animation-related issues.
Quick Checks to Rule Out Other Issues
- Verify your
playAgain()method is correctly defined (public, takes no parameters if using XMLandroid:onClick, or matches theOnClickListenersignature). - Temporarily remove the blink animation and confirm the click works—this confirms the animation was the root cause.
- Ensure no other views are overlapping the "Play Again?" TextView (use Layout Inspector to check view hierarchy).
内容的提问来源于stack exchange,提问作者Milie

