如何在 Android Kotlin 中创建带有闪烁红色背景的自定义 EditText 以设置错误?

问题描述 投票:0回答:1

我想在 Android 中创建一个自定义 EditText,当出现错误时显示闪烁的红色背景。这个想法是直观地向用户表明输入无效。

这是我迄今为止尝试过的:

  1. 我通过扩展 EditText 类创建了一个自定义 EditText 类。
  2. 我尝试使用 postDelayed 进行闪烁以编程方式更改背景颜色。

这是我写的代码:

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)
    }
}

这可行,但我面临以下问题:

  1. 闪烁效果有时甚至在应该停止后仍然持续。
  2. 这是处理闪烁效果的最佳方法,还是有使用动画或 XML 的更好方法?

我想知道:

  1. 如何确保闪烁在固定时间后可靠地停止?
  2. 是否有更有效的方法来实现这种效果,例如使用Android的动画框架或XML可绘制对象?

任何改进此实施的指导或建议将不胜感激。

android kotlin animation android-edittext android-custom-view
1个回答
0
投票

我对这个问题有最好的解决方案。 我最近已将其实现到我的 Android 项目中。

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;
    }
} 

您可以在 .xml 文件中实现此功能,并在 java 或 kotlin 文件中执行验证过程,如下所示

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

将其放入 java 或 kotlin 文件中进行验证。

if (binding.etName.validateEmpty()) {
                showToast("Please enter Name");
                return;
            }
© www.soinside.com 2019 - 2024. All rights reserved.