如何扩展 Android 中的按钮 class?

How to extend the Button class in Android?

我正在尝试扩展 Android 中的 Button class。我有一个 flicker.java 和一个 MainActivity.java。我想扩展 Button class 并向其添加类似 public void flicker_with_current_color(){} 的方法,以便我可以在 MainActivity.java 中使用 flicker.flicker_with_current_color();。不幸的是,Android Studio 给了我错误(作为提示):

This custom view should extend androidx.appcompat.widget.AppCompatButton instead

我想做的是添加一个自定义方法,这样我就可以在任何地方使用它。我知道这可以通过在 MainActivity.java 中创建一个方法来完成,但我正在尝试制作一个与 Android 的 Button [=] 相同的自定义按钮 class 32=] 但有更多的方法。我不知道我哪里错了。

flicker.java:

package com.its.me;

import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.provider.CalendarContract;
import android.util.AttributeSet;
import android.widget.Button;
import android.widget.TextView;

import org.w3c.dom.Text;

import java.util.Timer;

public class flicker extends Button{

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

    public void flicker_with_current_color(Button btn, String color_to_flicker, String color_to_switch_back_to, int time_interval, int times_to_flicker){

        for(int i=0; i<times_to_flicker; i++){

            btn.setTextColor(Color.parseColor(color_to_flicker));

            Timer t = new java.util.Timer();
            t.schedule(
                    new java.util.TimerTask() {
                        @Override
                        public void run() {

                            btn.setTextColor(Color.parseColor(color_to_switch_back_to));

                            t.cancel();
                        }
                    },
                    time_interval
            );

        }
    }

    public void flicker_with_current_color(String color_to_flicker, String color_to_switch_back_to, int time_interval, int times_to_flicker){

        for(int i=0; i<times_to_flicker; i++){

            this.setTextColor(Color.parseColor(color_to_flicker));

            Timer t = new java.util.Timer();
            t.schedule(
                    new java.util.TimerTask() {
                        @Override
                        public void run() {

                            //this.setTextColor(Color.parseColor(color_to_switch_back_to));

                            t.cancel();
                        }
                    },
                    time_interval
            );

        }
    }

    public void flicker_with_current_color(Button btn, int total_time, int times_to_flicker, String color_to_flicker, String color_to_switch_back_to){

        int time_interval = total_time/times_to_flicker;

        for(int i=0; i<times_to_flicker; i++){

            btn.setTextColor(Color.parseColor(color_to_flicker));

            Timer t = new java.util.Timer();
            t.schedule(
                    new java.util.TimerTask() {
                        @Override
                        public void run() {

                            btn.setTextColor(Color.parseColor(color_to_switch_back_to));

                            t.cancel();
                        }
                    },
                    time_interval
            );

        }

    }

}

首先你必须记住,你将需要额外的、重载的构造函数。最重要的是您提供 XML 属性 attrs 的那个 - 没有它甚至无法创建按钮。您可以在您的代码中使用这组构造函数,这很好:

public FlickerButton(Context context) {
    super(context, null, android.R.attr.buttonStyle);
}

public FlickerButton(Context context, AttributeSet attrs) {
    super(context, attrs, android.R.attr.buttonStyle);
}

public FlickerButton(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
}

您的代码中可能出现的第二个问题是 CalledFromWrongThreadException。当您在不同的线程中设置一个计时器及其任务时,Android 会抱怨视图,在本例中是我们的 FlickerButton,正在与创建它的线程不同的线程上进行操作:

Only the original thread that created a view hierarchy can touch its views.

为此,我将更改 闪烁 动画的方法。我不使用计时器,而是使用 ValueAnimator 来设置颜色闪烁的动画。仔细分析代码:

private int buttonTextColor = Color.BLACK; // Initially we will set the color to black
private ValueAnimator flickerAnimation; // Animator that will animate between the colors

public void flicker_with_current_color(String colorToFlicker, String colorToSwitchBackTo, int timeInterval, int timesToFlicker) {

    // Animator will animate from the colorToSwitchBackTo 
    // through colorToFlicker and back to the colorToSwitchBackTo
    flickerAnimation = ValueAnimator.ofArgb(
            Color.parseColor(colorToSwitchBackTo),
            Color.parseColor(colorToFlicker),
            Color.parseColor(colorToSwitchBackTo)
    );

    // The duration of one animation interval and how many times teh animation will repeat
    flickerAnimation.setDuration(timeInterval).setRepeatCount(timesToFlicker);

    // Specify what will happen when the animated value will change
    flickerAnimation.addUpdateListener(valueAnimator -> {
        buttonTextColor = (int) valueAnimator.getAnimatedValue();

        // invalidate() will invalidate the view and in turn call the onDraw() method
        invalidate();
    });

    flickerAnimation.start(); // start the animation
}

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

    setTextColor(buttonTextColor);
}

为了向后兼容,所有代码都在 AppCompatButton 的子类中 您将可以使用按钮:

public class FlickerButton extends AppCompatButton {

    // Insert all the code from above here

}

在 XML 文件中:

<com.example.flickerbutton.FlickerButton
        android:id="@+id/flicker_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Flicker Button" />

FlickerButton 的父项中:

((FlickerButton) findViewById(R.id.flicker_button)).setOnClickListener(view -> {
        ((FlickerButton) view).flicker_with_current_color(
                "white", "black", 500, 10);
    });

使用所有这些代码,按钮的文本颜色将通过黑白颜色闪烁 10 次半秒。

现在我不会只给您留下这段代码 - 我建议您阅读 Android 中关于自定义视图的 this 指南,以更好地理解上述代码中发生的事情以及改进您现有的项目。祝你好运:)