How to implement a CustomView with custom selector states?

前端 未结 1 907
小蘑菇
小蘑菇 2020-12-30 10:33

I want to create a CustomView that displays an image. On click the view should change its state. There should be three states (off, set, notset)

相关标签:
1条回答
  • 2020-12-30 11:14

    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));
        }
    }
    
    0 讨论(0)
提交回复
热议问题