Fau*_*eal 405 android spinner android-spinner
我想到了一些不太优雅的方法来解决这个问题,但我知道我必须遗漏一些东西.
我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.
}
}
}
Run Code Online (Sandbox Code Playgroud)
Bra*_*rad 365
Runnables的使用完全不正确.
setSelection(position, false);
在之前的初始选择中使用setOnItemSelectedListener(listener)
这样,您可以在没有动画的情况下设置选择,从而调用on项目选定的侦听器.但是侦听器为null,因此无法运行.然后分配你的听众.
所以按照这个确切的顺序:
Spinner s = (Spinner)Util.findViewById(view, R.id.sound, R.id.spinner);
s.setAdapter(adapter);
s.setSelection(position, false);
s.setOnItemSelectedListener(listener);
Run Code Online (Sandbox Code Playgroud)
小智 191
参考Dan Dyer的回答,尝试OnSelectListener
在post(Runnable)
方法中注册:
spinner.post(new Runnable() {
public void run() {
spinner.setOnItemSelectedListener(listener);
}
});
Run Code Online (Sandbox Code Playgroud)
通过这样做,我终于发生了希望的行为.
在这种情况下,它还意味着侦听器仅触发更改的项目.
Com*_*are 75
我希望你的解决方案能够正常工作 - 如果你在设置监听器之前设置了适配器,那么选择事件就不会激活.
话虽这么说,一个简单的布尔标志将允许您检测恶意第一选择事件并忽略它.
小智 47
我创建了一个小实用程序方法来更改Spinner
选择而不通知用户:
private void setSpinnerSelectionWithoutCallingListener(final Spinner spinner, final int selection) {
final OnItemSelectedListener l = spinner.getOnItemSelectedListener();
spinner.setOnItemSelectedListener(null);
spinner.post(new Runnable() {
@Override
public void run() {
spinner.setSelection(selection);
spinner.post(new Runnable() {
@Override
public void run() {
spinner.setOnItemSelectedListener(l);
}
});
}
});
}
Run Code Online (Sandbox Code Playgroud)
它会禁用侦听器,更改选择,然后重新启用侦听器.
诀窍是调用与UI线程异步,因此您必须在连续的处理程序帖子中执行此操作.
Jor*_*rit 33
不幸的是,似乎这个问题的两个最常见的建议解决方案,即计算回调事件和发布Runnable以便稍后设置回调,例如在启用可访问性选项时都会失败.这是一个解决这些问题的助手类.进一步的explenation在注释块中.
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.Spinner;
import android.widget.SpinnerAdapter;
/**
* Spinner Helper class that works around some common issues
* with the stock Android Spinner
*
* A Spinner will normally call it's OnItemSelectedListener
* when you use setSelection(...) in your initialization code.
* This is usually unwanted behavior, and a common work-around
* is to use spinner.post(...) with a Runnable to assign the
* OnItemSelectedListener after layout.
*
* If you do not call setSelection(...) manually, the callback
* may be called with the first item in the adapter you have
* set. The common work-around for that is to count callbacks.
*
* While these workarounds usually *seem* to work, the callback
* may still be called repeatedly for other reasons while the
* selection hasn't actually changed. This will happen for
* example, if the user has accessibility options enabled -
* which is more common than you might think as several apps
* use this for different purposes, like detecting which
* notifications are active.
*
* Ideally, your OnItemSelectedListener callback should be
* coded defensively so that no problem would occur even
* if the callback was called repeatedly with the same values
* without any user interaction, so no workarounds are needed.
*
* This class does that for you. It keeps track of the values
* you have set with the setSelection(...) methods, and
* proxies the OnItemSelectedListener callback so your callback
* only gets called if the selected item's position differs
* from the one you have set by code, or the first item if you
* did not set it.
*
* This also means that if the user actually clicks the item
* that was previously selected by code (or the first item
* if you didn't set a selection by code), the callback will
* not fire.
*
* To implement, replace current occurrences of:
*
* Spinner spinner =
* (Spinner)findViewById(R.id.xxx);
*
* with:
*
* SpinnerHelper spinner =
* new SpinnerHelper(findViewById(R.id.xxx))
*
* SpinnerHelper proxies the (my) most used calls to Spinner
* but not all of them. Should a method not be available, use:
*
* spinner.getSpinner().someMethod(...)
*
* Or just add the proxy method yourself :)
*
* (Quickly) Tested on devices from 2.3.6 through 4.2.2
*
* @author Jorrit "Chainfire" Jongma
* @license WTFPL (do whatever you want with this, nobody cares)
*/
public class SpinnerHelper implements OnItemSelectedListener {
private final Spinner spinner;
private int lastPosition = -1;
private OnItemSelectedListener proxiedItemSelectedListener = null;
public SpinnerHelper(Object spinner) {
this.spinner = (spinner != null) ? (Spinner)spinner : null;
}
public Spinner getSpinner() {
return spinner;
}
public void setSelection(int position) {
lastPosition = Math.max(-1, position);
spinner.setSelection(position);
}
public void setSelection(int position, boolean animate) {
lastPosition = Math.max(-1, position);
spinner.setSelection(position, animate);
}
public void setOnItemSelectedListener(OnItemSelectedListener listener) {
proxiedItemSelectedListener = listener;
spinner.setOnItemSelectedListener(listener == null ? null : this);
}
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if (position != lastPosition) {
lastPosition = position;
if (proxiedItemSelectedListener != null) {
proxiedItemSelectedListener.onItemSelected(
parent, view, position, id
);
}
}
}
public void onNothingSelected(AdapterView<?> parent) {
if (-1 != lastPosition) {
lastPosition = -1;
if (proxiedItemSelectedListener != null) {
proxiedItemSelectedListener.onNothingSelected(
parent
);
}
}
}
public void setAdapter(SpinnerAdapter adapter) {
if (adapter.getCount() > 0) {
lastPosition = 0;
}
spinner.setAdapter(adapter);
}
public SpinnerAdapter getAdapter() { return spinner.getAdapter(); }
public int getCount() { return spinner.getCount(); }
public Object getItemAtPosition(int position) { return spinner.getItemAtPosition(position); }
public long getItemIdAtPosition(int position) { return spinner.getItemIdAtPosition(position); }
public Object getSelectedItem() { return spinner.getSelectedItem(); }
public long getSelectedItemId() { return spinner.getSelectedItemId(); }
public int getSelectedItemPosition() { return spinner.getSelectedItemPosition(); }
public void setEnabled(boolean enabled) { spinner.setEnabled(enabled); }
public boolean isEnabled() { return spinner.isEnabled(); }
}
Run Code Online (Sandbox Code Playgroud)
Chr*_*ris 31
当我不想要的时候,我有很多关于旋转器触发的问题,而且这里的所有答案都是不可靠的.他们工作 - 但有时只是.您最终会遇到失败的情况,并在您的代码中引入错误.
对我有用的是将最后选择的索引存储在变量中并在侦听器中对其进行评估.如果它与新选择的索引相同,则不执行任何操作并返回,否则继续使用侦听器.做这个:
//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
}
Run Code Online (Sandbox Code Playgroud)
相信我这样说,这是迄今为止最可靠的解决方案.一个黑客,但它的工作原理!
Mic*_*hal 25
我处于类似的情况,我有一个简单的解决方案为我工作.
它看起来像方法setSelection(int position)
并且setSelected(int position, boolean animate)
具有不同的内部实现.
当您使用setSelected(int position, boolean animate)
带有false animate标志的第二种方法时,您可以在不触发onItemSelected
侦听器的情况下进行选择.
JAS*_*SON 21
只是为了充实提示使用onTouchListener来区分对setOnItemSelectedListener的自动调用(它是Activity初始化的一部分等)与实际用户交互触发的对它的调用,我在这里尝试了一些其他建议之后做了以下操作发现它在最少的代码行中运行良好.
只需为您的Activity/Fragment设置一个布尔字段,如:
private Boolean spinnerTouched = false;
Run Code Online (Sandbox Code Playgroud)
然后在设置微调器的setOnItemSelectedListener之前,设置onTouchListener:
spinner.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
System.out.println("Real touch felt.");
spinnerTouched = true;
return false;
}
});
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
...
if (spinnerTouched){
//Do the stuff you only want triggered by real user interaction.
}
spinnerTouched = false;
Run Code Online (Sandbox Code Playgroud)
j2e*_*nue 13
spinner.setSelection(Adapter.NO_SELECTION, false);
Run Code Online (Sandbox Code Playgroud)
把头发拉了很长时间后,我已经创建了自己的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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
像这样在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" />
Run Code Online (Sandbox Code Playgroud)
您需要做的就是在充气后调用SaneSpinner的实例并调用集合选择,如下所示:
mMySaneSpinner.setSelection(1, true, true);
Run Code Online (Sandbox Code Playgroud)
这样,就不会触发任何事件,也不会中断用户交互.这大大降低了我的代码复杂性.这应该包含在现货Android中,因为它确实是PITA.
如果您推迟添加侦听器直到布局完成,则不会从布局阶段发生不需要的事件:
spinner.getViewTreeObserver().addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
// Ensure you call it only once works for JELLY_BEAN and later
spinner.getViewTreeObserver().removeOnGlobalLayoutListener(this);
// add the listener
spinner.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
// check if pos has changed
// then do your work
}
@Override
public void onNothingSelected(AdapterView<?> arg0) {
}
});
}
});
Run Code Online (Sandbox Code Playgroud)
小智 5
我得到了一个非常简单的答案,100% 确定它有效:
boolean Touched=false; // this a a global variable
public void changetouchvalue()
{
Touched=true;
}
// this code is written just before onItemSelectedListener
spinner.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
System.out.println("Real touch felt.");
changetouchvalue();
return false;
}
});
//inside your spinner.SetonItemSelectedListener , you have a function named OnItemSelected iside that function write the following code
if(Touched)
{
// the code u want to do in touch event
}
Run Code Online (Sandbox Code Playgroud)
如果您在代码中进行选择,则会发生这种情况;
Run Code Online (Sandbox Code Playgroud)mSpinner.setSelection(0);
代替上述声明使用
Run Code Online (Sandbox Code Playgroud)mSpinner.setSelection(0,false);//just simply do not animate it.
编辑:此方法不适用于Mi Android版本Mi UI。
归档时间: |
|
查看次数: |
131361 次 |
最近记录: |