android selector 自定义 drawable state

本文探讨了Android中Selector的工作原理,它基于StateListDrawable,通过DrawableContainer的selectDrawable方法和setVisible实现图像变化。在项目中,特别是在实现夜间模式切换时,利用Selector结合自定义drawable状态可以高效地改变UI颜色图案。切换夜间模式会触发整个UI的刷新,通过遍历并刷新所有View来实现这一效果,而这个过程涉及到重写多个DrawableState相关函数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

selector<对应的drawable是StateListDrawable> 的运作原理 这一篇已经讲的很清楚了:

http://blog.youkuaiyun.com/guolin_blog/article/details/17045157

最后一步显示是通过DrawableContainer(StateListDrawable的基类)<DrawableContainer extends Drawable implements Drawable.Callback>

的selectDrawable(int idx)

然后mCurrDrawable.setVisible(......) 来实现的图像变化。

setVisible(......)在有变化的情况下调用invalidateSelf()->注册的callback->invalidateDrawable(this).........一路callback,

最后到View<View implements Drawable.Callback>->invalidateDrawable()

public void invalidateDrawable(Drawable drawable) {
        if (verifyDrawable(drawable)) {
            final Rect dirty = drawable.getBounds();
            final int scrollX = mScrollX;
            final int scrollY = mScrollY;

            invalidate(dirty.left + scrollX, dirty.top + scrollY,
                    dirty.right + scrollX, dirty.bottom + scrollY);
        }
    }
最后还是invaldate制定的区域来实现图片的刷新.



目前项目中实现夜间模式等需要大规模切换整体UI颜色图案 就采用了这种结合selector 与 自定义 drawable 状态的方式来实现,

切换夜间模式相当于某个drawable状态发生变化,selector便会跟着改变,

当然肯定不会和系统提供的点击或者focus 变化那么简单,

因为夜间模式这种是牵一发动全身,整个UI全部换,因此,也从根View开始主动的触发强制性的refreshDrawableState()

来遍历刷新(BFS/DFS)整个UI, 并且每个view 在attach到window时,也要做相应的nighemode检测(onAttachToWindow中), 不过这么做的前提工作是每一个使用的

view都要重载DrawableState相关的函数。

    /**
     * Call this to force a view to update its drawable state. This will cause
     * drawableStateChanged to be called on this view. Views that are interested
     * in the new state should call getDrawableState.
     *
     * @see #drawableStateChanged
     * @see #getDrawableState
     */
    public void refreshDrawableState() {
        mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY;
        drawableStateChanged();

        ViewParent parent = mParent;
        if (parent != null) {
            parent.childDrawableStateChanged(this);
        }
    }
parent的childDrawableStateChanged()会触发自己的refreshDrawableState()。
    /**
     * If {@link #addStatesFromChildren} is true, refreshes this group's
     * drawable state (to include the states from its children).
     */
    public void childDrawableStateChanged(View child) {
        if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0) {
            refreshDrawableState();
        }
    }

protected void drawableStateChanged() {
        Drawable d = mBackground;
        if (d != null && d.isStateful()) {
            d.setState(getDrawableState());
            注意的这里的isStateful的判断,一般的drawable的isStateful()返回是true, 不过使用了selector的
            StateListDrawable返回的是true,也定义了自己的onStateChange函数(在setState变化的时候调用)
        }
    }





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值