How to implement a CustomView with custom selector states?

只谈情不闲聊 提交于 2019-11-30 07:12:28
Philipp Jahoda

Just in case your issue has not resolved itself yet. I do the changing of states with a new implementation of the Android Button.

The states are defined in .xml and set via a selector. Here the three states defined in the attrs.xml file:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="states">
        <attr name="state_on" format="boolean" />
        <attr name="state_off" format="boolean" />
        <attr name="state_notset" format="boolean" />
    </declare-styleable>
</resources>

And the selector (statebutton_selector.xml) inside the drawables folder: (I assume that enabling a specific state automatically disables the other states - the drawables like "state_on" are just .png images representing the individual states)

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res/com.example.statebuttontest">
<item
    app:state_on="true"
    app:state_off="false"
    app:state_notset="false"
    android:drawable="@drawable/state_on" />
<item
    app:state_on="false"
    app:state_off="true"
    app:state_notset="false"
    android:drawable="@drawable/state_off" />
<item
    app:state_on="false"
    app:state_off="false"
    app:state_notset="true" 
    android:drawable="@drawable/state_notset" />
</selector>

Also, be aware to reference your correct package name in the selector xml file, as stated in your Manifest file:

xmlns:app="http://schemas.android.com/apk/res/com.example.statebuttontest"

And finally, the StateButton class that extends Button. With a simple OnClickListener the state is changed. I also implemented an OnStateChangedListener that for example can be implemented by an Activity that contains the Button and will be called whenever the state changes.

The changing of the state itself is done inside the onCreateDrawableState(...) method that is called automatically every time the Button is clicked. "extraspace + 1" means, that there will be one additional state inside the drawableStates array.

public class StateButton extends Button implements OnClickListener {

    private static final int[] mStates = { R.attr.state_notset, R.attr.state_on, R.attr.state_off };
    private int mStateIndex = 0; // first state is "notset"

    private OnStateChangedListener mListener;

    public StateButton(Context context, AttributeSet attrs) {
        super(context, attrs);

        setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        changeState();
    }

    public void changeState() {
        mStateIndex = (mStateIndex+1) % mStates.length;

        // notify listener
        if(mListener != null) mListener.onStateChanged(mStates[mStateIndex]);
    }

    @Override
    protected int[] onCreateDrawableState(int extraSpace) {

        final int[] drawableState = super.onCreateDrawableState(extraSpace+1);

        int [] state = { mStates[mStateIndex] };

        mergeDrawableStates(drawableState, state);

        return drawableState;
    }

    public void setOnStateChangedListener(OnStateChangedListener l) {
        this.mListener = l;
    }
}

Last but not least, set the selector as the background of your Button:

<com.example.statebuttontest.StateButton
        android:id="@+id/stateButton1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:background="@drawable/statebutton_selector"
        android:text="" />

An example of the Activity (with Listener):

public class MainActivity extends Activity implements OnStateChangedListener {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        StateButton s = (StateButton) findViewById(R.id.stateButton1);
        s.setOnStateChangedListener(this);
    }

    @Override
    public void onStateChanged(int state) {
        Log.i("Main", "State changed to: " + getResources().getResourceEntryName(state));
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!