首页 > 解决方案 > 自定义 ImageButton,最简单的 RadioButton 接口要覆盖哪种方法?

问题描述

我正在制作一个自定义视图,该视图本质上是一个带有附加逻辑的 ImageButton,因此它也具有 RadioButton 的行为。我想要做的就是将它内置到视图中,当用户单击按钮时图像被更改,内部布尔值被标记为 true 以说明它被选中,并调用接口方法以使其成为 RadioGroup 的一部分取消选择其中的所有其他视图。我不想影响基本 ImageButton 的现有行为。

我之前只制作了另一个自定义视图,那是通过几乎完全按照教程进行操作,因为 View 继承了许多不同的方法来处理点击/触摸(即 onTouch、onClick、运动事件等)。 ) 全部考虑让我有点困惑。我很好地编写了界面本身,它是对 ImageButton 的修改,我不太确定如何攻击它。

所以,我问大家:我需要重写哪些方法/方法来添加这个简单的功能,同时不会影响 ImageButton 的当前行为,也不会破坏为按钮设置 onTouchListener 的能力,该按钮将在单击时执行其他操作在不影响内置单选按钮逻辑的情况下?如果我需要覆盖一些会影响我提到的默认行为的东西,我需要在新方法中添加什么来恢复该功能?

这是我到目前为止所拥有的:

public class RadioImageButton extends AppCompatImageButton implements RadioCheckable {

//Default constructor
public RadioImageButton(Context context) {
    super(context);
    initView();
}

//Constructor with defined attributes
public RadioImageButton(Context context, AttributeSet attrs) {
    super(context, attrs);
    parseAttributes();
    initView();
}

//Constructor with defined attributes and attributes taken from style defaults that aren't defined
public RadioImageButton(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
}



//=========================================================================
// Setup
//=========================================================================

private void initView()
{

}

private void parseAttributes()
{

}

}

我想采取的方法是这样的:

...All other code I already showed

mChecked = false;

@Overide
void onClick(...)
{
       mChecked = true;
       setImageSource(R.example.checked_image); // Or I can use a selector resource
       *Call to Radio Interface*;
       mOnTouchListener.onTouch(v, event); //Handle user onTouchListener
}
...   

并留下所有其他代码,尽管我确信它不是那么简单。

我认为一个好的开始是尝试找到默认 ImageButton 类的源代码并将我的设置为接近副本,这样我就可以了解它是如何工作的,然后从那里进行修改,但我真正能找到的是:

https://android.googlesource.com/platform/frameworks/base/+/android-7.0.0_r35/core/java/android/widget/ImageButton.java

并且不可能是实际来源,因为按 Ctrl+O 会显示 ImageButton 定义的更多函数,这些函数不是从另一个类继承的;无论如何,该链接根本没有帮助,因为它基本上是一个几乎没有代码的巨大评论。

感谢您提供任何可以帮助我以最直接的方式完成此任务的建议。

编辑: @pskink - 查看您提供的代码,它似乎正在尝试生成一个矩阵以转换提供的可绘制对象(src),使其适合新的矩形(dst),同时保持纵横比和定位(因此 ScaleToFit.CENTER)。我会假设目标矩形将是包含可绘制对象的视图的边界,在这种情况下是 RadioButton,但是在逐步覆盖“draw()”方法时,它似乎并没有做那个,虽然我不太确定 cavas.concat(matrix) 是如何解决的,所以我不肯定。不管它似乎没有按预期工作,或者我以某种方式错误地使用它。

标签: androidradio-buttonandroid-custom-viewontouchlistenerandroid-imagebutton

解决方案


虽然可能不是最强大的方法,但它似乎是处理我想做的最直接但最有效的方法是利用 Matrix 类及其强大的缩放/转换工具,特别是“setRectToRect()”。创建扩展 RadioButton 而不是 ImageButton 的自定义视图允许我利用现有的 RadioGroup,同时在新类 Constructor 中操作按钮的可绘制对象的特性实现了我正在寻找的行为。

自定义 RadioButton 类:

public class RadioImageButton extends android.support.v7.widget.AppCompatRadioButton {

    int stateDrawable; //Resource ID for RadioButton selector Drawable
    D scaledDrawable; //Post-scaling drawable

    public RadioImageButtonTwo(Context context) {
        super(context);
        initView();
    }

    public RadioImageButtonTwo(Context context, AttributeSet attrs) {
        super(context, attrs);
        parseAttributes(attrs);
        initView();
    }


    private void parseAttributes(AttributeSet attrs)
    {
        TypedArray styledAttrs = getContext().obtainStyledAttributes(attrs,R.styleable.RadioImageButtonTwo);
        try {
            // Obtain selector drawable from attributes
            stateDrawable = styledAttrs.getResourceId(R.styleable.RadioImageButtonTwo_button_sDrawable, R.drawable.test_draw2);
        } finally {
            styledAttrs.recycle(); //Required for public shared view
        }

    }

    private void initView()
    {
        scaledDrawable = new D(getResources(),stateDrawable); // Create scaled drawable
        setBackground(scaledDrawable); // Apply scaled drawable
        setButtonDrawable(android.R.color.transparent); // "Disable" button graphic
    }
}

在此处查看有关设置自定义视图的更多信息:https ://developer.android.com/training/custom-views/create-view#customattr

由于@pskink,包含fitCenter缩放的自定义可绘制类“D”:

class D extends StateListDrawable {
    private Rect bounds = new Rect();
    private RectF src = new RectF();
    private RectF dst = new RectF();
    private Matrix matrix = new Matrix();

    public D(Resources r, int resId) {
        try {
            XmlResourceParser parser = r.getXml(resId);
            int type;
            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
                if (type == XmlPullParser.START_TAG && parser.getName().equals("selector")) {
                    inflate(r, parser, Xml.asAttributeSet(parser));
                    break;
                }
            }
        } catch (XmlPullParserException | IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void draw(Canvas canvas) {
        Drawable current = getCurrent();
        bounds.set(0, 0, current.getIntrinsicWidth(), current.getIntrinsicHeight());
        current.setBounds(bounds);

        src.set(bounds);
        dst.set(getBounds());
        matrix.setRectToRect(src, dst, Matrix.ScaleToFit.CENTER);

        canvas.concat(matrix);
        super.draw(canvas);
    }
}

请注意,无论出于何种原因,将可绘制按钮本身设置为此自定义可绘制对象都会破坏缩放,因此将背景更改为自定义可绘制对象并将可绘制按钮设置为透明是唯一可行的方法。这个自定义的可绘制对象可以很容易地扩展为具有更多缩放类型选项,并且可以定义另一个视图属性以允许用户通过 XML 选择缩放类型。

这种模仿(pskink 也指出)的自定义 ImageView 也可以证明对这项任务很有帮助,因为它也利用 Matrix 类来实现多种类型的图像缩放: https ://github.com/yqritc/Android-ScalableImageView


推荐阅读