带有Checked状态的ImageView

Table of Contents

  • 1. xml中的与代码中的StateListDrawable
  • 2. 给ImageView添加上自己额外的状态: CheckableImageView
  • 3. 其它参考链接

带有Checked状态的ImageView

View一般可用的状态有 pressed, selected, focused, enabled(可以通过View
找到)。那么当我想在不影响这4中状态的情况下,使用上新的标记位(就像
CheckBox那样,但在xml的UI定义上不需要其它改变,保持和ImageView一样的属
性)。于是有了这篇记录。

xml中的与代码中的StateListDrawable

在定制Btn按下效果时,我们会用到xml, 并在其中定义selector节点,并按照
需求添加不同的item定义。如果跳过android-runtime对xml的解析,我们也可以
从java代码中,实现同样的效果,只要使用 setStateDrawable即可:

ImageView iv = (ImageView) this.findViewById(R.id.selector_iv);
iv.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
    }
});

StateListDrawable slD = new StateListDrawable();
slD.addState(new int[] {android.R.attr.state_enabled, android.R.attr.state_pressed, }, getResources().getDrawable(R.mipmap.ic_launcher));
slD.addState(new int[] {android.R.attr.state_enabled, }, getResources().getDrawable(R.mipmap.ic_launcher2));
iv.setBackground(slD);

这样,当View的State变化时,就能通知StateListDrawable变化。但是这边隐藏
的点,StateListDrawable变化后,view是如何知道要重新绘制的—答案就是
Drawable.Callback。View继承的这个接口,并在setBackgroundDrawable(…)
是,将自己挂到StateListDrawable的listener实现上了:

public void setBackgroundDrawable(Drawable background) {
...
        background.setCallback(this);
...
}

于是,View和Background Drawable双方都知道了要怎么做了。

其实让我比较疑惑的是 int数组中的flag是在哪里定义的来着,最后找到是在
android.jar的/res/values/attrs.xml中(所以理论上每次build出来的jar会有
不一样的flag值)

官方介绍 有个点要注意下,就是需要在StateList中寻找’best match’的
Drawable时,是使用第一个找到的’best match’,而不是最合适的’best match’。
所以我们在写selector时,最好把条件越多的放在最上面。有种fallback的备胎
感。

给ImageView添加上自己额外的状态: CheckableImageView

主要是2个api和一个接口:

View.onCreateDrawableState()
View.mergeDrawableStates()
android.widget.Checkable

分析一下现成的代码

public class CheckableImageView extends ImageView implements Checkable {
    private boolean mChecked;
    // 增加需要支持新的flag
    private static final int[] CHECKED_STATE_SET = { android.R.attr.state_checked };

    public CheckableImageView(final Context context, final AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public int[] onCreateDrawableState(final int extraSpace) {
        // 复写 onCreateDrawableState, 并增加给出新的flag位置, 并根据当前状态,merge进相应的flag
        final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
        if (isChecked())
            mergeDrawableStates(drawableState, CHECKED_STATE_SET);
        return drawableState;
    }

    // 实现 Checkable方法,能够类似CheckBox般的调用
    @Override
    public void toggle() {
        setChecked(!mChecked);
    }

    @Override
    public boolean isChecked() {
        return mChecked;
    }

    @Override
    public void setChecked(final boolean checked) {
        if (mChecked == checked)
            return;
        mChecked = checked;
        refreshDrawableState();
    }
}

其它参考链接

http://blog.csdn.net/qinjuning/article/details/7474827

你可能感兴趣的:(记录)