无法理解Android自定义可绘制状态

时间:2013-02-12 00:44:01

标签: android

我是Android开发的新手,我正在编写一个小应用程序来了解它是如何工作的。我已经全部工作了,但目前我无法得到关于自定义可绘制状态的观点......让我用一些示例代码解释一下。

这是我的attrs.xml,其中我声明了一个名为“oddMonth”的属性,它是boolean:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="DayView">
        <attr name="oddMonth" format="boolean"/>
    </declare-styleable>
</resources>

然后我有一个自定义视图:

<?xml version="1.0" encoding="utf-8"?>
<com.example.calendar.DayView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="90dp"
    android:background="@drawable/dayview_state" >
    <TextView android:id="@+id/day_number"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_alignParentRight="true"
        android:paddingRight="3dp" />  
</com.example.calendar.DayView>

所以我把行“android:background =”@ drawable / dayview_state“”,它引用文件dayview_state.xml:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:easycalendar="http://schemas.android.com/apk/res/com.example.calendar">

    <item easycalendar:oddMonth ="true" android:drawable="@drawable/customborder_odd" />
    <item easycalendar:oddMonth ="false" android:drawable="@drawable/customborder_even"/>

</selector>

到目前为止......我能理解......我在attrs.xml中定义了一个属性。此属性表示我的自定义视图的状态。根据这个属性的布尔值,我的应用程序将加载两个不同的xml中的一个(这里不重要),每个都定义一个不同的drawable。所以最后一步是构建我的自定义类!跟随课程摘录:

public class DayView extends RelativeLayout {
    private static final int[] STATE_ODD_MONTH = { R.attr.oddMonth };
    private boolean mOddmonth = true;

    public DayView(Context mContext, AttributeSet attrs) {
        super(mContext, attrs);
    }

    @Override
    protected int[] onCreateDrawableState(int extraSpace) {
        if (mOddmonth) {
            final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
            mergeDrawableStates(drawableState, STATE_ODD_MONTH);

            return drawableState;
        } else {
            return super.onCreateDrawableState(extraSpace);
        }
    }

    public boolean isOddMonth() {
        return mOddmonth;
    }

    public void setOddMonth(boolean oddMonth) {
        if (mOddmonth != oddMonth) {
            mOddmonth = oddMonth;

            refreshDrawableState();
        }
    }
}

好的......所以我这里有一个私有变量mOddMonth,有getter和setter。用于在其他地方膨胀此视图的构造函数。另一个私人变量:

private static final int[] STATE_ODD_MONTH = { R.attr.oddMonth };

这是一个只由一个int值组成的数组,它是对attrs.xml中定义的oddMonth属性的引用。和继承的方法:

@Override
    protected int[] onCreateDrawableState(int extraSpace) {
        if (mOddmonth) {
            final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
            mergeDrawableStates(drawableState, STATE_ODD_MONTH);

            return drawableState;
        } else {
            return super.onCreateDrawableState(extraSpace);
        }
    }

我无法“深入”理解......好吧,在我看来,如果局部变量mOddMonth为真,我会添加一个状态,否则不会。所以...我的代码只有在我用以下内容替换dayview_state.xml时才有效:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:easycalendar="http://schemas.android.com/apk/res/com.example.calendar">

    <item easycalendar:oddMonth ="true" android:drawable="@drawable/customborder_odd" />
    <item android:drawable="@drawable/customborder_even"/>

</selector>

这样,如果THERE是状态,则加载第一个布局,否则将加载第二个布局。但关于国家价值的是什么?我的代码中没有任何地方设置此变量/属性的值....我错了吗?

2 个答案:

答案 0 :(得分:0)

你是对的;您需要使用AttributeSet变量在构造函数中分配该值:

TypedArray values = context.obtainStyledAttributes(attrs, STATE_ODD_MONTH);
boolean isOddMonth = values.getBoolean(R.attr.oddMonth, false);
mOddmonth = isOddMonth;
values.recycle();

我相信这应该可以解决问题。我通常在attrs.xml中使用declare-styleable标签而不是硬编码int [],但我相信它应该完全相同。

答案 1 :(得分:0)

我建议你改写你的问题b / c我不清楚你问的是什么,直到我读到你对@ kcoppock的回答的评论,这是 -

  

“我想做什么(或者我认为我应该做的)是设置这个值   根据我的自定义视图的实际状态在代码中的某处,   然后强制它再次渲染....或者我不应该?“

在任何时候,您都可以使用 View.getDrawableState 查询视图以获取可绘制状态。

如果基于此,您想要重新渲染您的drawable,那么您有几个选项。

首先,您可以调用 Drawable.invalidateSelf 。但是你很少需要这样做,因为通常你的drawable被设置为一个视图的背景drawable,它是在draw方法中自动绘制的(而不是onDraw,这是你绘制的)。因此,在这种情况下您需要做的就是使视图无效( view.invalidate ),它会自动重绘您的背景可绘制(因此拾取您的可绘制状态更改)。

如果您使用的是drawable而不是背景而是主画,那么您可以在 onDraw 中绘制您的drawable。一个简单的myDrawable.draw(canvas)就足够了。但请记住vall view.invalidate来触发onDraw方法。