自定义 ImageButton,最简单的 RadioButton 接口要覆盖哪个方法?
Custom ImageButton, which method to override for simplest RadioButton interface?
我正在制作一个自定义视图,该视图本质上是一个添加了逻辑的 ImageButton,因此它也具有 RadioButton 的行为。我想要做的就是将它内置到视图中,当用户单击按钮时图像会更改,内部布尔值标记为 true 以注意它已被选中,并调用接口方法让 RadioGroup 它成为一部分取消选择其中的所有其他视图。 我不想影响基本 ImageButton 的现有行为。
我之前只制作过一个自定义视图,那是几乎完全按照教程进行的,因为从 View 继承了很多不同的方法来处理 clicks/touches(即 onTouch, onClick、动作事件等)全部考虑在内让我有点困惑。我很好地编写了界面本身,它是对 ImageButton 的修改,我不太确定如何攻击它。
所以,我问大家:我需要重写什么 method/methods 才能添加这个简单的功能,同时不影响 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 class 的源代码并将我的设置为近似副本是一个好的开始,这样我就可以了解它是如何工作的,然后从那里进行修改,但是我真正能找到的是这个:
这不可能是实际来源,因为按 Ctrl+O 会显示 ImageButton 定义的更多功能,这些功能不是从另一个 class 继承的;无论如何,link 根本没有帮助,因为它基本上是一个巨大的注释,几乎没有代码。
感谢任何能帮助我以最直接的方式完成此任务的建议。
编辑: @pskink - 查看您提供的代码,似乎它正在尝试生成一个矩阵以转换提供的可绘制对象(src),以便它适合新的矩形 (dst),同时保持纵横比和定位(因此 ScaleToFit.CENTER)。我假设目标矩形是包含可绘制对象的视图的边界,在本例中是 RadioButton,但是在逐步执行 "draw()" 方法的重写时,它似乎并没有真正做到那,虽然我不太确定 cavas.concat(matrix) 是如何解决的,所以我不是很肯定。无论它似乎没有按预期工作,还是我以某种方式使用错误。
虽然这可能不是最稳健的方法,但它似乎是处理我想做的事情的最直接但有效的方法,那就是利用 Matrix class 及其强大的 scaling/transformation 工具,具体来说 "setRectToRect()"。创建一个扩展 RadioButton 而不是 ImageButton 的自定义视图允许我利用现有的 RadioGroup,同时在新的 classes 构造函数中操纵按钮的可绘制对象的特性实现了我正在寻找的行为。
自定义单选按钮class:
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
自定义可绘制对象 class "D" 包括 fitCenter 缩放感谢 @pskink:
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 也可以证明对这项任务有帮助,因为它也利用矩阵 class 来实现多种类型的图像缩放:https://github.com/yqritc/Android-ScalableImageView
我正在制作一个自定义视图,该视图本质上是一个添加了逻辑的 ImageButton,因此它也具有 RadioButton 的行为。我想要做的就是将它内置到视图中,当用户单击按钮时图像会更改,内部布尔值标记为 true 以注意它已被选中,并调用接口方法让 RadioGroup 它成为一部分取消选择其中的所有其他视图。 我不想影响基本 ImageButton 的现有行为。
我之前只制作过一个自定义视图,那是几乎完全按照教程进行的,因为从 View 继承了很多不同的方法来处理 clicks/touches(即 onTouch, onClick、动作事件等)全部考虑在内让我有点困惑。我很好地编写了界面本身,它是对 ImageButton 的修改,我不太确定如何攻击它。
所以,我问大家:我需要重写什么 method/methods 才能添加这个简单的功能,同时不影响 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 class 的源代码并将我的设置为近似副本是一个好的开始,这样我就可以了解它是如何工作的,然后从那里进行修改,但是我真正能找到的是这个:
这不可能是实际来源,因为按 Ctrl+O 会显示 ImageButton 定义的更多功能,这些功能不是从另一个 class 继承的;无论如何,link 根本没有帮助,因为它基本上是一个巨大的注释,几乎没有代码。
感谢任何能帮助我以最直接的方式完成此任务的建议。
编辑: @pskink - 查看您提供的代码,似乎它正在尝试生成一个矩阵以转换提供的可绘制对象(src),以便它适合新的矩形 (dst),同时保持纵横比和定位(因此 ScaleToFit.CENTER)。我假设目标矩形是包含可绘制对象的视图的边界,在本例中是 RadioButton,但是在逐步执行 "draw()" 方法的重写时,它似乎并没有真正做到那,虽然我不太确定 cavas.concat(matrix) 是如何解决的,所以我不是很肯定。无论它似乎没有按预期工作,还是我以某种方式使用错误。
虽然这可能不是最稳健的方法,但它似乎是处理我想做的事情的最直接但有效的方法,那就是利用 Matrix class 及其强大的 scaling/transformation 工具,具体来说 "setRectToRect()"。创建一个扩展 RadioButton 而不是 ImageButton 的自定义视图允许我利用现有的 RadioGroup,同时在新的 classes 构造函数中操纵按钮的可绘制对象的特性实现了我正在寻找的行为。
自定义单选按钮class:
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
自定义可绘制对象 class "D" 包括 fitCenter 缩放感谢 @pskink:
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 也可以证明对这项任务有帮助,因为它也利用矩阵 class 来实现多种类型的图像缩放:https://github.com/yqritc/Android-ScalableImageView