Spinner:当所选项目保持不变时,不会调用 onItemSelected

问题描述 投票:0回答:12

我的

OnItemSelectedListener
有一个
Spinner
,但是当所选项目与上一个项目相同时不会调用它。显然,
OnClickListener
不是
Spinner
的选项。 我需要捕捉用户每次点击某个项目的时间。有什么想法吗?

也许这个

Spinner
ActionBar
内部会扰乱正常行为?

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    inflater.inflate(R.menu.tracklist_menu, menu);
    Spinner spinner = (Spinner) menu.findItem(R.id.option_ordering_spinner)
            .getActionView();
    spinner.setAdapter(mSpinnerAdapter);
    spinner.setSelection(PrefsHelper.getOrderingSpinnerPos(prefs));
    spinner.setOnItemSelectedListener(new OnItemSelectedListener() {

        @Override
        public void onItemSelected(AdapterView<?> parent, View view,
                int position, long id) {
            String str = "selected";
            System.out.println(str);
            if (optionMenuInitialized) {

                switch (position) {
                case 0:
                    // rdm
                    getActivity()
                            .sendBroadcast(
                                    new Intent(
                                            MyIntentAction.DO_RESHUFFLE_PLAYLIST));
                    smp.setCurrentTracklistCursorPos(-1);
                    trackAdapter.notifyDataSetChanged();
                    break;
                case 1:
                    // artist
                    getActivity()
                            .sendBroadcast(
                                    new Intent(
                                            MyIntentAction.DO_ORDER_PLAYLIST_BY_ARTIST));
                    smp.setCurrentTracklistCursorPos(-1);
                    trackAdapter.notifyDataSetChanged();
                    break;
                case 2:
                    // folder
                    getActivity()
                            .sendBroadcast(
                                    new Intent(
                                            MyIntentAction.DO_ORDER_PLAYLIST_BY_FOLDER));
                    smp.setCurrentTracklistCursorPos(-1);
                    trackAdapter.notifyDataSetChanged();
                    break;
                }
                PrefsHelper.setOrderingSpinnerPos(prefEditor, position);
                prefEditor.commit();
            }
            optionMenuInitialized = true;
        }

        @Override
        public void onNothingSelected(AdapterView<?> parent) {
        }
    });
}
android spinner listener android-actionbar actionbarsherlock
12个回答
90
投票

好吧,我终于找到了一个解决方案,通过创建我自己的类来扩展 Spinner :

public class MySpinner extends Spinner {
OnItemSelectedListener listener;

public MySpinner(Context context, AttributeSet attrs) {
    super(context, attrs);
}

@Override
public void setSelection(int position) {
    super.setSelection(position);
    if (listener != null)
        listener.onItemSelected(null, null, position, 0);
}

public void setOnItemSelectedEvenIfUnchangedListener(
        OnItemSelectedListener listener) {
    this.listener = listener;
}
}

26
投票

我发现了这项工作,而不是提供的工作

/** Spinner extension that calls onItemSelected even when the selection is the same as its previous value */
public class NDSpinner extends Spinner {

  public NDSpinner(Context context)
  { super(context); }

  public NDSpinner(Context context, AttributeSet attrs)
  { super(context, attrs); }

  public NDSpinner(Context context, AttributeSet attrs, int defStyle)
  { super(context, attrs, defStyle); }

  @Override public void
  setSelection(int position, boolean animate)
  {
    boolean sameSelected = position == getSelectedItemPosition();
    super.setSelection(position, animate);
    if (sameSelected) {
      // Spinner does not call the OnItemSelectedListener if the same item is selected, so do it manually now
      getOnItemSelectedListener().onItemSelected(this, getSelectedView(), position, getSelectedItemId());
    }
  }

  @Override public void
  setSelection(int position)
  {
    boolean sameSelected = position == getSelectedItemPosition();
    super.setSelection(position);
    if (sameSelected) {
      // Spinner does not call the OnItemSelectedListener if the same item is selected, so do it manually now
      getOnItemSelectedListener().onItemSelected(this, getSelectedView(), position, getSelectedItemId());
    }
  }
}

6
投票

这里有一个更好的实现:

public class SpinnerPlus extends Spinner {
    AdapterView.OnItemSelectedListener listener;

    public SpinnerPlus(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public void setSelection(int position) {
        super.setSelection(position);
        if (listener != null)
            listener.onItemSelected(this, getSelectedView(), position, 0);
    }

    public void setOnItemSelectedEvenIfUnchangedListener(
            AdapterView.OnItemSelectedListener listener) {
        this.listener = listener;
    }
}

6
投票

要使微调器发生变化,无论最后选择的索引值如何,只需使用:

spinner.setSelection(0); 

在调用您的其他选择之前

spinner.setSelection(number); 

这样,微调器将触发两次 OnItemSelected 事件。只要确保第二次它能满足您的需要即可。


6
投票

重写了常见的解决方案,但使用:

  1. androidx 铭记于心
  2. 扩展自
    AppCompatSpinner
  3. 使用内置的
    OnItemSelectedListener
    监听器而不是创建自己的
  4. 添加了初始侦听器调用 hack

这里:

import android.content.Context;

import androidx.annotation.Nullable;
import androidx.appcompat.widget.AppCompatSpinner;


public class FixedSpinner extends AppCompatSpinner {
    // add other constructors that you need
    public FixedSpinner(Context context, int mode) {
        super(context, mode);
    }

    private void processSelection(int position) {
        boolean sameSelected = position == getSelectedItemPosition();
        final OnItemSelectedListener listener = getOnItemSelectedListener();
        if (sameSelected && listener != null) {
            // Spinner does not call the OnItemSelectedListener if the same item is selected, so do it manually now
            listener.onItemSelected(this, getSelectedView(), position, getSelectedItemId());
        }
    }

    @Override
    public void setSelection(int position) {
        processSelection(position);
        super.setSelection(position);
    }

    @Override
    public void setSelection(int position, boolean animate) {
        processSelection(position);
        super.setSelection(position, animate);
    }

    @Override
    public void setOnItemSelectedListener(@Nullable OnItemSelectedListener listener) {
        // This hack fixes bug, when immediately after initialization, listener is called
        // To make this fix work, first add data, only then set listener
        // Having done this, you may refresh adapter data as many times as you want
        setSelection(0, false);
        super.setOnItemSelectedListener(listener);
    }
}

5
投票

这是一个更好的实现 -

自定义 Spinner 类 -

import android.content.Context;
import android.util.AttributeSet;
import androidx.appcompat.widget.AppCompatSpinner;

public class CSpinner extends AppCompatSpinner {

    private int lastPosition = 0;

    public CSpinner(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public void setSelection(int position) {
        super.setSelection(position);
        boolean sameSelected = lastPosition == getSelectedItemPosition();
        OnItemSelectedListener onItemSelectedListener = getOnItemSelectedListener();
        if (sameSelected && onItemSelectedListener != null) {
            onItemSelectedListener.onItemSelected(this, getSelectedView(), position, getSelectedItemId());
        }
        lastPosition = position;
    }
}

设置监听器 -

spn.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
            Log.d("onItemSelected", String.valueOf(position));
        }

        @Override
        public void onNothingSelected(AdapterView<?> parent) {
            
        }
    });

2
投票

如果它仍然是实际的,正确的回调调用应该是

@Override
public void setSelection(int position) {
    super.setSelection(position);
    if(listener != null)
        listener.onItemSelected(this, getChildAt(position), position, 0);
}

1
投票

最简单的解决方案:

spinner.performItemClick(视图,位置,id)


0
投票

我遇到了同样的问题,我通过每次适配器更改项目时设置 onItemSelectedListener 来解决它。


0
投票

进一步来自@Vishal Yadav的答案,如果您想通过调用

spinner.setSelection(pos, false);
来设置初始位置而不触发OnItemSelectedListener,那么自定义微调器应该是:

public class CSpinner extends AppCompatSpinner {

    private int lastPosition = 0;

    public CSpinner(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public void setSelection(int position, boolean animate) {
        OnItemSelectedListener listener = getOnItemSelectedListener();
        setOnItemSelectedListener(null);
        super.setSelection(position, animate);
        lastPosition = position;
        setOnItemSelectedListener(listener);
    }

    @Override
    public void setSelection(int position) {
        super.setSelection(position);
        boolean sameSelected = lastPosition == getSelectedItemPosition();
        OnItemSelectedListener onItemSelectedListener = getOnItemSelectedListener();
        if (sameSelected && onItemSelectedListener != null) {
            onItemSelectedListener.onItemSelected(this, getSelectedView(), position, getSelectedItemId());
        }
        lastPosition = position;
    }
}

0
投票
class MySpinner(context: Context, attrs: AttributeSet?) : AppCompatSpinner(
    context, attrs
) {
    var listener: OnItemSelectedListener? = null
    override fun setSelection(position: Int) {
        if (position == selectedItemPosition) {
            listener?.onItemSelected(this, selectedView, position, selectedItemId)
        }
        super.setSelection(position)
    }

    override fun setOnItemSelectedListener(listener: OnItemSelectedListener?) {
        this.listener = listener
        super.setOnItemSelectedListener(this.listener)
    }
}

-1
投票

我找到了一个简单的解决方案

只需再次调用 setAdapter 来代替第二个微调器的 notificationDataSetChanged

© www.soinside.com 2019 - 2024. All rights reserved.