admin管理员组

文章数量:1334191

I want to create a custom EditText in Android that shows a blinking red background when there is an error. The idea is to visually indicate to the user that input is invalid.

Here is what I have tried so far:

  1. I created a custom EditText class by extending the EditText class.
  2. I tried changing the background color programmatically using postDelayed for blinking.

Here is the code I have written:

class BlinkingEditText(context: Context, attrs: AttributeSet?) : AppCompatEditText(context, attrs) {

    fun showErrorBlink() {
        val handler = Handler(Looper.getMainLooper())
        var isRed = false

        val runnable = object : Runnable {
            override fun run() {
                if (isRed) {
                    setBackgroundColor(Color.WHITE)
                } else {
                    setBackgroundColor(Color.RED)
                }
                isRed = !isRed
                handler.postDelayed(this, 500) // Blink every 500ms
            }
        }

        handler.post(runnable)

        // Stop blinking after 3 seconds
        handler.postDelayed({ handler.removeCallbacks(runnable) }, 3000)
    }
}

This works, but I am facing the following issues:

  1. The blinking effect sometimes continues even after it is supposed to stop.
  2. Is this the best way to handle a blinking effect, or is there a better approach using animations or XML?

I would like to know:

  1. How can I ensure the blinking stops reliably after a fixed duration?
  2. Is there a more efficient way to achieve this effect, such as using Android's animation framework or XML drawables?

Any guidance or suggestions for improving this implementation would be greatly appreciated.

I want to create a custom EditText in Android that shows a blinking red background when there is an error. The idea is to visually indicate to the user that input is invalid.

Here is what I have tried so far:

  1. I created a custom EditText class by extending the EditText class.
  2. I tried changing the background color programmatically using postDelayed for blinking.

Here is the code I have written:

class BlinkingEditText(context: Context, attrs: AttributeSet?) : AppCompatEditText(context, attrs) {

    fun showErrorBlink() {
        val handler = Handler(Looper.getMainLooper())
        var isRed = false

        val runnable = object : Runnable {
            override fun run() {
                if (isRed) {
                    setBackgroundColor(Color.WHITE)
                } else {
                    setBackgroundColor(Color.RED)
                }
                isRed = !isRed
                handler.postDelayed(this, 500) // Blink every 500ms
            }
        }

        handler.post(runnable)

        // Stop blinking after 3 seconds
        handler.postDelayed({ handler.removeCallbacks(runnable) }, 3000)
    }
}

This works, but I am facing the following issues:

  1. The blinking effect sometimes continues even after it is supposed to stop.
  2. Is this the best way to handle a blinking effect, or is there a better approach using animations or XML?

I would like to know:

  1. How can I ensure the blinking stops reliably after a fixed duration?
  2. Is there a more efficient way to achieve this effect, such as using Android's animation framework or XML drawables?

Any guidance or suggestions for improving this implementation would be greatly appreciated.

Share asked Nov 22, 2024 at 5:39 Lily MontaLily Monta 194 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 0

I have the best solution for this issue. i have recently implemented this into my android project.

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;

import com.app.materialwallpaperapps.R;
import com.app.materialwallpaperapps.base.BaseActivity;


public class CustomEditText extends androidx.appcompat.widget.AppCompatEditText {

    private static final String TAG = BaseActivity.TAG;

    public CustomEditText(@NonNull Context context) {
        super(context);
        init();
    }

    public CustomEditText(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public CustomEditText(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        // Add a TextWatcher to listen for user input and reset the background if necessary
        this.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
                // No action needed here
            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                // Reset the background to the default when the user starts typing
                if (s.length() > 0) {
                    setBackgroundResource(R.drawable.edittext_bg); // Reset to original background
                }
            }

            @Override
            public void afterTextChanged(Editable s) {
                // No action needed here
            }
        });
    }

    /**
     * Shows a blinking error background to indicate an error.
     */
    public void showBlinkableError() {
        // Ensure the current background is mutable to modify its color dynamically
        Drawable background = getBackground().mutate();

        if (background instanceof GradientDrawable) {
            GradientDrawable gradientDrawable = (GradientDrawable) background;

            // Define the error color (light red) and original color
            int errorColor = Color.parseColor("#FFCDD2"); // Light red
            int originalColor = ContextCompat.getColor(getContext(), R.color.lightBlueEt);

            // Store the original drawable
            Drawable originalBackground = background.getConstantState().newDrawable();

            // Create an ObjectAnimator to animate the color
            ObjectAnimator animator = ObjectAnimator.ofArgb(gradientDrawable, "color", errorColor, originalColor);

            // Set animation properties
            animator.setDuration(200); // 500ms per blink
            animator.setRepeatCount(3); // Blink 3 times
            animator.setRepeatMode(ValueAnimator.REVERSE); // Reverse back to the original color

            // Start the animation
            animator.start();
            animator.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    super.onAnimationEnd(animation);
                    // Restore the original background after animation end
                    Log.d(TAG, "onAnimationEnd: originalBackground = " + originalBackground);
                    setBackground(originalBackground);
                }
            });

            // Set focus on the EditText
            this.requestFocus();
        } else {
            Log.e("CustomEditText", "Background is not a GradientDrawable. Ensure correct drawable is used.");
        }
    }


    /**
     * Validates if the EditText is not empty.
     *
     * @return true if not empty, false otherwise
     */
    public boolean validateEmpty() {
        if (getText() == null || getText().toString().trim().isEmpty()) {
            showBlinkableError();
            return true;
        }
        return false;
    }
} 

you can implement this in .xml file and do validation process in java or kotlin file as below

<com.app.materialwallpaperapps.util.custom.CustomEditText
                android:id="@+id/etName"
                style="@style/CustomEditTextStyleOneLine"
                android:hint="Example Corp"
                android:text="@={viewModel.mainBoardRootpanyContactDetails.name}" /> 

Put this into java or kotlin file for validation.

if (binding.etName.validateEmpty()) {
                showToast("Please enter Name");
                return;
            }

本文标签: