我想过一些不那么优雅的方法来解决这个问题,但我知道我一定遗漏了什么。
我的onItemSelected立即启动,没有与用户进行任何交互,这是不希望的行为。我希望UI能够等到用户选择某样东西后再执行任何操作。
我甚至尝试在onResume()中设置监听器,希望能有所帮助,但它没有。
我怎样才能阻止它在用户可以触摸控件之前发射?
public class CMSHome extends Activity {
private Spinner spinner;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Heres my spinner ///////////////////////////////////////////
spinner = (Spinner) findViewById(R.id.spinner);
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(
this, R.array.pm_list, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);
};
public void onResume() {
super.onResume();
spinner.setOnItemSelectedListener(new MyOnItemSelectedListener());
}
public class MyOnItemSelectedListener implements OnItemSelectedListener {
public void onItemSelected(AdapterView<?> parent,
View view, int pos, long id) {
Intent i = new Intent(CMSHome.this, ListProjects.class);
i.putExtra("bEmpID", parent.getItemAtPosition(pos).toString());
startActivity(i);
Toast.makeText(parent.getContext(), "The pm is " +
parent.getItemAtPosition(pos).toString(), Toast.LENGTH_LONG).show();
}
public void onNothingSelected(AdapterView parent) {
// Do nothing.
}
}
}
在抽出我的头发很长一段时间后,现在我已经创建了自己的Spinner类。我已经添加了一个方法,它可以适当地断开和连接侦听器。
public class SaneSpinner extends Spinner {
public SaneSpinner(Context context) {
super(context);
}
public SaneSpinner(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SaneSpinner(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
// set the ceaseFireOnItemClickEvent argument to true to avoid firing an event
public void setSelection(int position, boolean animate, boolean ceaseFireOnItemClickEvent) {
OnItemSelectedListener l = getOnItemSelectedListener();
if (ceaseFireOnItemClickEvent) {
setOnItemSelectedListener(null);
}
super.setSelection(position, animate);
if (ceaseFireOnItemClickEvent) {
setOnItemSelectedListener(l);
}
}
}
在XML中像这样使用它:
<my.package.name.SaneSpinner
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/mySaneSpinner"
android:entries="@array/supportedCurrenciesFullName"
android:layout_weight="2" />
你所要做的就是在膨胀和调用集选择之后检索SaneSpinner实例:
mMySaneSpinner.setSelection(1, true, true);
这样,就不会触发任何事件,用户交互也不会中断。这大大降低了我的代码复杂性。这应该包括在Android的股票,因为它确实是一个PITA。
这也不是一个优雅的解决方案。事实上,这有点像鲁布-戈德堡,但似乎很有效。通过扩展数组适配器并覆盖其getDropDownView,我确保旋转器至少被使用过一次。在新的getDropDownView方法中,我有一个布尔标志,被设置为显示下拉菜单至少被使用过一次。在设置标志之前,我会忽略对侦听器的调用。
MainActivity.onCreate ():
ActionBar ab = getActionBar();
ab.setDisplayShowTitleEnabled(false);
ab.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
ab.setListNavigationCallbacks(null, null);
ArrayList<String> abList = new ArrayList<String>();
abList.add("line 1");
...
ArAd abAdapt = new ArAd (this
, android.R.layout.simple_list_item_1
, android.R.id.text1, abList);
ab.setListNavigationCallbacks(abAdapt, MainActivity.this);
覆盖的数组适配器:
private static boolean viewed = false;
private class ArAd extends ArrayAdapter<String> {
private ArAd(Activity a
, int layoutId, int resId, ArrayList<String> list) {
super(a, layoutId, resId, list);
viewed = false;
}
@Override
public View getDropDownView(int position, View convertView,
ViewGroup parent) {
viewed = true;
return super.getDropDownView(position, convertView, parent);
}
}
修改监听器:
@Override
public boolean onNavigationItemSelected(
int itemPosition, long itemId) {
if (viewed) {
...
}
return false;
}
我可能在帖子上回答得太迟了,但是我设法实现了这一点,使用Android数据绑定库Android Databinding。我创建了一个自定义绑定,以确保监听器不被调用,直到选定的项目被改变,所以即使用户选择相同的位置,一遍又一遍地事件不会被触发。
布局xml文件
<layout>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/activity_vertical_margin"
xmlns:app="http://schemas.android.com/apk/res-auto">
<Spinner
android:id="@+id/spinner"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:spinnerMode="dropdown"
android:layout_below="@id/member_img"
android:layout_marginTop="@dimen/activity_vertical_margin"
android:background="@drawable/member_btn"
android:padding="@dimen/activity_horizontal_margin"
android:layout_marginStart="@dimen/activity_horizontal_margin"
android:textColor="@color/colorAccent"
app:position="@{0}"
/>
</RelativeLayout>
</layout>
App:position是你传递要选择的位置。
定制绑定
@BindingAdapter(value={ "position"}, requireAll=false)
public static void setSpinnerAdapter(Spinner spinner, int selected)
{
final int [] selectedposition= new int[1];
selectedposition[0]=selected;
// custom adapter or you can set default adapter
CustomSpinnerAdapter customSpinnerAdapter = new CustomSpinnerAdapter(spinner.getContext(), <arraylist you want to add to spinner>);
spinner.setAdapter(customSpinnerAdapter);
spinner.setSelection(selected,false);
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
String item = parent.getItemAtPosition(position).toString();
if( position!=selectedposition[0]) {
selectedposition[0]=position;
// do your stuff here
}
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
}
你可以阅读更多关于自定义数据绑定在这里Android自定义Setter
NOTE
不要忘记在Gradle文件中启用数据绑定
android {
....
数据绑定{
Enabled = true
}
}
包括你的布局文件在<layout>标签
在抽出我的头发很长一段时间后,现在我已经创建了自己的Spinner类。我已经添加了一个方法,它可以适当地断开和连接侦听器。
public class SaneSpinner extends Spinner {
public SaneSpinner(Context context) {
super(context);
}
public SaneSpinner(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SaneSpinner(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
// set the ceaseFireOnItemClickEvent argument to true to avoid firing an event
public void setSelection(int position, boolean animate, boolean ceaseFireOnItemClickEvent) {
OnItemSelectedListener l = getOnItemSelectedListener();
if (ceaseFireOnItemClickEvent) {
setOnItemSelectedListener(null);
}
super.setSelection(position, animate);
if (ceaseFireOnItemClickEvent) {
setOnItemSelectedListener(l);
}
}
}
在XML中像这样使用它:
<my.package.name.SaneSpinner
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/mySaneSpinner"
android:entries="@array/supportedCurrenciesFullName"
android:layout_weight="2" />
你所要做的就是在膨胀和调用集选择之后检索SaneSpinner实例:
mMySaneSpinner.setSelection(1, true, true);
这样,就不会触发任何事件,用户交互也不会中断。这大大降低了我的代码复杂性。这应该包括在Android的股票,因为它确实是一个PITA。
我有很多问题与旋转发射时,我不想,所有的答案在这里是不可靠的。它们确实有效——但只是有时有效。您最终会遇到它们失败并将错误引入代码的情况。
对我来说,有效的方法是将最后选中的索引存储在一个变量中,并在侦听器中对其求值。如果它与新选定的索引相同,则不做任何操作并返回,否则继续使用侦听器。这样做:
//Declare a int member variable and initialize to 0 (at the top of your class)
private int mLastSpinnerPosition = 0;
//then evaluate it in your listener
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
if(mLastSpinnerPosition == i){
return; //do nothing
}
mLastSpinnerPosition = i;
//do the rest of your code now
}
相信我,这是目前为止最可靠的解决方案。一个黑客,但它工作!