微调:获得状态或打开时得到通知
是否有可能知道Spinner
是打开还是closures? 如果有一些onSpinner的onLpenListener会更好。
我试过使用这样的OnItemSelectedListener:
spinnerType.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { executeSomething(); } @Override public void onNothingSelected(AdapterView<?> parent) { Log.d("nothing" , "selected"); } });
我可以知道,如果select了某些东西(在executeSomething()),窗口将会closures。 但是,如果我单击对话框外部,也会收到通知,这也会closures微调框
另一种观察这些事件的方法是扩展Spinner
类,并使用其中一个方法( performClick()
来触发其对话框/popup窗口),然后监视持有该自定义Spinner
的窗口的焦点。 这应该为您提供所需的closures事件的所有可能的完成可能性(无论是对话框或下拉模式)。
自定义的Spinner
类:
public class CustomSpinner extends Spinner { /** * An interface which a client of this Spinner could use to receive * open/closed events for this Spinner. */ public interface OnSpinnerEventsListener { /** * Callback triggered when the spinner was opened. */ void onSpinnerOpened(Spinner spinner); /** * Callback triggered when the spinner was closed. */ void onSpinnerClosed(Spinner spinner); } private OnSpinnerEventsListener mListener; private boolean mOpenInitiated = false; // implement the Spinner constructors that you need @Override public boolean performClick() { // register that the Spinner was opened so we have a status // indicator for when the container holding this Spinner may lose focus mOpenInitiated = true; if (mListener != null) { mListener.onSpinnerOpened(this); } return super.performClick(); } /** * Register the listener which will listen for events. */ public void setSpinnerEventsListener( OnSpinnerEventsListener onSpinnerEventsListener) { mListener = onSpinnerEventsListener; } /** * Propagate the closed Spinner event to the listener from outside if needed. */ public void performClosedEvent() { mOpenInitiated = false; if (mListener != null) { mListener.onSpinnerClosed(this); } } /** * A boolean flag indicating that the Spinner triggered an open event. * * @return true for opened Spinner */ public boolean hasBeenOpened() { return mOpenInitiated; } public void onWindowFocusChanged (boolean hasFocus) { if (hasBeenOpened() && hasFocus) { performClosedEvent(); } } }
基于@Luksprog美妙的解决scheme,我只是想添加一个小的变化,这将是非常有用的情况下,有人在片段内使用CustomSpinner。 而不是使用Activity.onWindowFocusChanged
函数,我们重写View.onWindowFocusChanged
函数。 从而整个CustomSpinner类成为
import android.content.Context; import android.util.AttributeSet; import android.widget.Spinner; public class CustomSpinner extends Spinner { private static final String TAG = "CustomSpinner"; private OnSpinnerEventsListener mListener; private boolean mOpenInitiated = false; public CustomSpinner(Context context, AttributeSet attrs, int defStyleAttr, int mode) { super(context, attrs, defStyleAttr, mode); } public CustomSpinner(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } public CustomSpinner(Context context, AttributeSet attrs) { super(context, attrs); } public CustomSpinner(Context context, int mode) { super(context, mode); } public CustomSpinner(Context context) { super(context); } public interface OnSpinnerEventsListener { void onSpinnerOpened(); void onSpinnerClosed(); } @Override public boolean performClick() { // register that the Spinner was opened so we have a status // indicator for the activity(which may lose focus for some other // reasons) mOpenInitiated = true; if (mListener != null) { mListener.onSpinnerOpened(); } return super.performClick(); } public void setSpinnerEventsListener(OnSpinnerEventsListener onSpinnerEventsListener) { mListener = onSpinnerEventsListener; } /** * Propagate the closed Spinner event to the listener from outside. */ public void performClosedEvent() { mOpenInitiated = false; if (mListener != null) { mListener.onSpinnerClosed(); } } /** * A boolean flag indicating that the Spinner triggered an open event. * * @return true for opened Spinner */ public boolean hasBeenOpened() { return mOpenInitiated; } @Override public void onWindowFocusChanged(boolean hasWindowFocus) { android.util.Log.d(TAG, "onWindowFocusChanged"); super.onWindowFocusChanged(hasWindowFocus); if (hasBeenOpened() && hasWindowFocus) { android.util.Log.i(TAG, "closing popup"); performClosedEvent(); } } }
嗨朋友,我在这个问题上挣扎了两天,最后我得到了解决scheme,完成了我的工作。 我试了一下,效果很好。 谢谢
mSpinner.setOnTouchListener(new OnTouchListener(){ @Override public boolean onTouch(View v, MotionEvent event) { if(event.getAction() == MotionEvent.ACTION_DOWN){ Toast.makeText(MapActivity.this,"down",Toast.LENGTH_LONG).show(); // Load your spinner here } return false; } });
没有内置函数,但使用OnTouchListener
和OnItemSelectedListener
很容易。
abstract class OnOpenListener implements OnTouchListener, OnItemSelectedListener { public OnOpenListener(Spinner spinner) { spinner.setOnTouchListener(this); spinner.setOnItemSelectedListener(this); } @Override public boolean onTouch(View v, MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_UP) { onOpen(); } return false; } @Override public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) { onClose(); } @Override public void onNothingSelected(AdapterView<?> arg0) { onClose(); } abstract public void onOpen(); abstract public void onClose(); }
然后分配适当的监听器:
OnOpenListener onOpenListener = new OnOpenListener(mySpinner) { @Override public void onOpen() { // spinner was opened } @Override public void onClose() { // spinner was closed } };
我找不到一种方法来获得这种行为与微调,所以唯一的工作是我使用微调(自定义)适配器,而不是:
public interface SpinnerListener { void onSpinnerExpanded(); void onSpinnerCollapsed(); }
然后,可以编写一个自定义适配器来抓取“微调器扩展”视图,并添加一个侦听器来侦听“展开”和“折叠”事件。 我使用的自定义适配器是:
public class ListeningArrayAdapter<T> extends ArrayAdapter<T> { private ViewGroup itemParent; private final Collection<SpinnerListener> spinnerListeners = new ArrayList<SpinnerListener>(); public ListeningArrayAdapter(Context context, int resource, T[] objects) { super(context, resource, objects); } // Add the rest of the constructors here ... // Just grab the spinner view (parent of the spinner item view) and add a listener to it. @Override public View getDropDownView(int position, View convertView, ViewGroup parent) { if (isParentTheListView(parent)) { itemParent = parent; addFocusListenerAsExpansionListener(); } return super.getDropDownView(position, convertView, parent); } // Assumes the item view parent is a ListView (which it is when a Spinner class is used) private boolean isParentTheListView(ViewGroup parent) { return (parent != itemParent && parent != null && ListView.class.isAssignableFrom(parent.getClass())); } // Add a focus listener to listen to spinner expansion and collapse events. private void addFocusListenerAsExpansionListener() { final View.OnFocusChangeListener listenerWrapper = new OnFocusChangeListenerWrapper(itemParent.getOnFocusChangeListener(), spinnerListeners); itemParent.setOnFocusChangeListener(listenerWrapper); } // Utility method. public boolean isExpanded() { return (itemParent != null && itemParent.hasFocus()); } public void addSpinnerListener(SpinnerListener spinnerListener) { spinnerListeners.add(spinnerListener); } public boolean removeSpinnerListener(SpinnerListener spinnerListener) { return spinnerListeners.remove(spinnerListener); } // Listener that listens for 'expand' and 'collapse' events. private static class OnFocusChangeListenerWrapper implements View.OnFocusChangeListener { private final Collection<SpinnerListener> spinnerListeners; private final View.OnFocusChangeListener originalFocusListener; private OnFocusChangeListenerWrapper(View.OnFocusChangeListener originalFocusListener, Collection<SpinnerListener> spinnerListeners) { this.spinnerListeners = spinnerListeners; this.originalFocusListener = originalFocusListener; } @Override public void onFocusChange(View view, boolean hasFocus) { if (originalFocusListener != null) { originalFocusListener.onFocusChange(view, hasFocus); // Preserve the pre-existing focus listener (if any). } callSpinnerListeners(hasFocus); } private void callSpinnerListeners(boolean hasFocus) { for (SpinnerListener spinnerListener : spinnerListeners) { if (spinnerListener != null) { callSpinnerListener(hasFocus, spinnerListener); } } } private void callSpinnerListener(boolean hasFocus, SpinnerListener spinnerListener) { if (hasFocus) { spinnerListener.onSpinnerExpanded(); } else { spinnerListener.onSpinnerCollapsed(); } } } }
然后,当我在我的活动或片段中使用微调器时,我所要做的就是将微调器适配器设置为上述自定义适配器:
private ListeningArrayAdapter<CharSequence> adapter; private Spinner buildSpinner() { final CharSequence[] items = {"One", "Two", "Three"}; final Spinner spinner = (Spinner)getActivity().getLayoutInflater().inflate(R.layout.item_spinner, null); adapter = new ListeningArrayAdapter<CharSequence>(getActivity(), R.layout.item_spinner_item, items); adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); adapter.addSpinnerListener(new TestSpinnerListener(getActivity())); // Add your own spinner listener implementation here. spinner.setAdapter(adapter); return spinner; }
我知道这是一个黑客和一点点脆弱,但它为我工作。 如果Spinner类具有所有这些function,并允许您设置展开 – 折叠监听器,那将会好得多。 就目前而言,我将不得不采取这种做法。
我想最好的方法是什么时候打开和closures是这样的:
-
如果closures了,现在它在适配器中调用“getDropDownView”,可以假定它已经打开。
-
如果“onItemSelected”或“onNothingSelected”被调用,现在它closures。
编辑:这是一个示例代码
public class MainActivity extends AppCompatActivity { boolean isSpinnerClosed = true; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); AppCompatSpinner spinner2 = (AppCompatSpinner) findViewById(R.id.spinner2); List<String> list = new ArrayList<String>(); list.add("list 1"); list.add("list 2"); list.add("list 3"); Log.d("AppLog", "started"); //spinner2.setondi ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, list) { @Override public View getDropDownView(final int position, @Nullable final View convertView, @NonNull final ViewGroup parent) { if (isSpinnerClosed) { Log.d("AppLog", "closed->open"); isSpinnerClosed = false; } return super.getDropDownView(position, convertView, parent); } }; spinner2.setOnItemSelectedListener(new OnItemSelectedListener() { @Override public void onItemSelected(final AdapterView<?> adapterView, final View view, final int i, final long l) { Log.d("AppLog", "onItemSelected"); if (!isSpinnerClosed) { Log.d("AppLog", "open->closed"); isSpinnerClosed = true; } } @Override public void onNothingSelected(final AdapterView<?> adapterView) { Log.d("AppLog", "onNothingSelected"); if (!isSpinnerClosed) { Log.d("AppLog", "open->closed"); isSpinnerClosed = true; } } }); dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); spinner2.setAdapter(dataAdapter); } @Override public void onWindowFocusChanged(final boolean hasFocus) { super.onWindowFocusChanged(hasFocus); if (hasFocus && isSpinnerClosed) { Log.d("AppLog", "open->closed"); isSpinnerClosed = true; } } }