【问题标题】:How to implement a CustomView with custom selector states?如何使用自定义选择器状态实现 CustomView?
【发布时间】:2014-02-25 14:18:57
【问题描述】:

我想创建一个显示图像的CustomView。单击时,视图应更改其状态。视图可以表示三种状态(off、set、notset)。我想用 XML 中的 selector 来做到这一点。它不一定需要是自定义选择器。我可以重用选择器的三种状态(然后状态名称是否不同无关紧要)。

有没有什么好的方法可以做到这一点?

【问题讨论】:

    标签: android android-custom-view android-selector


    【解决方案1】:

    以防万一您的问题尚未自行解决。我使用 Android Button 的新实现来更改状态。

    状态在 .xml 中定义并通过 选择器 设置。这里是attrs.xml文件中定义的三种状态:

    <?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>
    

    以及 drawables 文件夹中的选择器 (statebutton_selector.xml): (我假设启用特定状态会自动禁用其他状态 - 像“state_on”这样的可绘制对象只是代表各个状态的 .png 图像)

    <?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>
    

    另外,请注意在选择器 xml 文件中引用正确的包名称,如清单文件中所述:

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

    最后是扩展ButtonStateButton 类。使用简单的OnClickListener 会更改状态。我还实现了一个OnStateChangedListener,例如,它可以由一个包含 Button 的 Activity 实现,并且只要状态发生变化就会被调用。

    状态本身的改变是在onCreateDrawableState(...) 方法中完成的,每次单击按钮时都会自动调用该方法。 "extraspace + 1" 表示drawableStates 数组中会多出一个状态。

    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;
        }
    }
    

    最后但同样重要的是,将选择器设置为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="" />
    

    Activity 的示例(带有监听器):

    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));
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多