【问题标题】:Setting a spinner onClickListener() in Android在 Android 中设置微调器 onClickListener()
【发布时间】:2011-04-25 02:12:50
【问题描述】:

我试图让 onClickListener 在 Spinner 上触发,但出现以下错误:

Java.lang.RuntimeException 是“不要为 AdapterView 调用 setOnClickListener。您可能需要 setOnItemClickListener”

我确定我想调用 onClickListener 而不是 onItemClickListener。我在 Stack Overflow 上发现了其他人提出的问题,Is there a way to use setOnClickListener with an Android Spinner?

答案是:

您必须设置 Click 底层视图上的监听器 (通常是一个带有 id 的 TextView: android.R.id.text1) 的微调器。到 这样做:

在 构造函数(带属性)创建 通过提供布局的微调器 android.R.layout.simple_spinner_item 做一个 findViewById(android.R.id.text1) 获取 TextView 现在设置 onClickListener 到 TextView

我已经尝试了那里提到的答案,但它似乎不起作用。执行 findViewById() 后,我得到一个指向 TextView 的空指针。

这就是我正在做的:

Spinner spinner = (Spinner) findViewById(R.id.spinner);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,R.layout.layoutspinner,dataArray);

spinner.setAdapter(adapter);

TextView SpinnerText = (TextView)findViewById(R.id.spinnerText);
if (SpinnerText == null) {
    System.out.println("Not found");
}
else {
    SpinnerText.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View arg0) {
            //Do something
        }
    });
}

文件 layoutspinner.xml

<?xml version="1.0" encoding="utf-8"?>
<TextView
    xmlns:android="http://schemas.android.com/apk/res/android"
                  android:id="@+id/spinnerText"
                  android:singleLine ="true"
                  android:layout_width="fill_parent"
                  android:layout_height="wrap_content"
                  android:textSize="6pt"
                  android:gravity="right"/>

我做错了什么?

我是 StackOverflow 的新手,我没有找到任何方法可以在其他线程中发布附加问题(或评论,因为我必须很少代表)所以我开始了一个新问题。

根据建议,我尝试了这个:

int a = spinnerMes.getCount();
int b = spinnerMes.getChildCount();
System.out.println("Count = " + a);
System.out.println("ChildCount = " + b);
for (int i = 0; i < b; i++) {
    View v = spinnerMes.getChildAt(i);
    if (v == null) {
        System.out.println("View not found");
    }
    else {
        v.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //Click code
            }
        });
    }
}

但是LogCat 的结果并不乐观。

10-14 16:09:08.127: INFO/System.out(3116): Count = 7
10-14 16:09:08.127: INFO/System.out(3116): ChildCount = 0

我在 API 级别 7 和 8 上对此进行了测试,结果相同。

【问题讨论】:

    标签: java android onclick spinner


    【解决方案1】:

    这是一个可行的解决方案:

    我们设置的是 OnTouchListener 和 OnKeyListener,而不是设置微调器的 OnClickListener。

    spinner.setOnTouchListener(Spinner_OnTouch);
    spinner.setOnKeyListener(Spinner_OnKey);
    

    和听众:

    private View.OnTouchListener Spinner_OnTouch = new View.OnTouchListener() {
        public boolean onTouch(View v, MotionEvent event) {
            if (event.getAction() == MotionEvent.ACTION_UP) {
                doWhatYouWantHere();
            }
            return true;
        }
    };
    private static View.OnKeyListener Spinner_OnKey = new View.OnKeyListener() {
        public boolean onKey(View v, int keyCode, KeyEvent event) {
            if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
                doWhatYouWantHere();
                return true;
            } else {
                return false;
            }
        }
    };
    

    【讨论】:

    • 当我运行此代码时,我无法访问所选项目 - 它只会给我之前选择的项目???你遇到过这种情况吗?
    • WaterBoy,此行为符合预期,因为这些回调是在 Android 处理事件之前执行的。对于我的应用程序,我不需要所选项目,所以在这里我无法为您提供帮助。对不起。
    • 如果微调器必须显示下拉项目,您可能希望始终返回 false。
    • 这一切都很好,但是通过注册 OnTouchListener,您似乎失去了 Spinner 上的焦点事件,这意味着您看不到漂亮的下划线突出显示等。有没有办法在仍然保留的时候保留它应用您的解决方案?
    【解决方案2】:

    当您必须在 Android 中单击 Spinner 时执行某些操作时,请使用以下方法。

    mspUserState.setOnTouchListener(new OnTouchListener() {
    
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            if (event.getAction() == MotionEvent.ACTION_UP) {
                doWhatIsRequired();
            }
            return false;
        }
    });
    

    要记住的一件事是在使用上述方法时始终返回 False。如果您将返回 True,则在单击 Spinner 时不会显示微调器的下拉项。

    【讨论】:

    • 我明白你说的。但是,例如,如果您尝试显示警报对话框而不是下拉项,则必须返回 true
    【解决方案3】:

    就个人而言,我使用它:

        final Spinner spinner = (Spinner) (view.findViewById(R.id.userList));
        spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {                
    
                userSelectedIndex = position;
            }
    
            @Override
            public void onNothingSelected(AdapterView<?> parent) {
            }
        });  
    

    【讨论】:

      【解决方案4】:

      首先,微调器不支持项目点击事件。调用此方法会引发异常。

      你可以使用 setOnItemSelectedListener:

      Spinner s1;
      s1 = (Spinner)findViewById(R.id.s1);
      int selectionCurrent = s1.getSelectedItemPosition();
      
      spinner.setOnItemSelectedListener(new OnItemSelectedListener() {
              @Override
              public void onItemSelected(AdapterView<?> parentView, View selectedItemView, int position, long id) {
                  if (selectionCurrent != position){
                      // Your code here
                  }
                  selectionCurrent= position;
              }
          }
      
          @Override
          public void onNothingSelected(AdapterView<?> parentView) {
              // Your code here
          }
      });
      

      【讨论】:

        【解决方案5】:

        以下内容可以按照您的意愿工作,但并不理想。

        public class Tester extends Activity {
        
            String[] vals = { "here", "are", "some", "values" };
            Spinner spinner;
        
            /** Called when the activity is first created. */
            @Override
            public void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.main);
                spinner = (Spinner) findViewById(R.id.spin);
                ArrayAdapter<String> ad = new ArrayAdapter<String>(this, android.R.layout.simple_dropdown_item_1line, vals);
                spinner.setAdapter(ad);
                Log.i("", "" + spinner.getChildCount());
                Timer t = new Timer();
                t.schedule(new TimerTask() {
        
                    @Override
                    public void run() {
                        int a = spinner.getCount();
                        int b = spinner.getChildCount();
                        System.out.println("Count =" + a);
                        System.out.println("ChildCount =" + b);
                        for (int i = 0; i < b; i++) {
                            View v = spinner.getChildAt(i);
                            if (v == null) {
                                System.out.println("View not found");
                            } else {
                                v.setOnClickListener(new View.OnClickListener() {
        
                                    @Override
                                    public void onClick(View v) {
                                                Log.i("","click");
                                                }
                                });
                            }
                        }
                    }
                }, 500);
            }
        }
        

        让我确切地知道您需要微调器的行为方式,我们可以制定出更好的解决方案。

        【讨论】:

        • 我相信我今天尝试了这个但没有成功,但我会在我再次尝试后报告以确保。
        • 我刚刚检查了代码,我试过了,但我仍然得到一个空引用作为回报。有什么想法吗?
        • 编辑了我的问题,还没有,但是谢谢你的帮助,我真的迷路了。
        • 我发布的代码的问题是微调器在执行 onCreate 之后的屏幕呈现之前实际上并没有获得任何项目。如果您将循环移动到在视图呈现后触发的计时器中,则它可以工作。但是问题是微调器只有 1 个孩子。当您选择微调器时,会生成一个对话框操作系统,以便您可以选择一个值。当值更改时,会创建一个新子项,并且您添加的事件将丢失。如果您能具体告诉我您需要 apinner 的行为方式,我们可能会想出一个更优雅的解决方案。
        • 这确实有效,但您所描述的问题是一个交易破坏者。让我回到导致我需要这个的问题。我有一个带有 2 个微调器的屏幕,因为我很确定您知道,微调器在创建时会触发 onItemSelected。此活动上的两个 onItemSelected 都启动网络请求,所以我的解决方案是使用一个简单的布尔标志,我们称之为 spinnerClicked。 onItemClickedListener 会查看 spinnerClicked 是否为真,并获取数据,否则它会忽略它。
        【解决方案6】:

        我建议将 Spinner 的所有事件分为两种类型:

        1. 用户事件(你的意思是“点击”事件)。

        2. 节目事件。

        我还建议,当您想捕获用户事件时,您只想摆脱“程序事件”。所以很简单:

        private void setSelectionWithoutDispatch(Spinner spinner, int position) {
            AdapterView.OnItemSelectedListener onItemSelectedListener = spinner.getOnItemSelectedListener();
            spinner.setOnItemSelectedListener(null);
            spinner.setSelection(position, false);
            spinner.setOnItemSelectedListener(onItemSelectedListener);
        }
        

        有一个关键时刻:你需要 setSelection(position, false)。动画参数中的“false”将立即触发事件。默认行为是将事件推送到事件队列。

        【讨论】:

          【解决方案7】:

          Spinner 类实现了DialogInterface.OnClickListener,从而有效地劫持了标准View.OnClickListener

          如果您不使用子类 Spinner 或不打算使用,请选择其他答案。

          否则只需将以下代码添加到您的自定义 Spinner:

          @Override
          /** Override triggered on 'tap' of closed Spinner */
          public boolean performClick() {
              // [ Do anything you like here ]
              return super.performClick();
          }
          

          示例:每当 Spinner 打开时,通过 Snackbar 显示预先提供的提示:

          private String sbMsg=null;      // Message seen by user when Spinner is opened.
          public void setSnackbarMessage(String msg) { sbMsg=msg; }
          @Override
          /** Override triggered on 'tap' of closed Spinner */
          public boolean performClick() {
              if (sbMsg!=null && !sbMsg.isEmpty()) { /* issue Snackbar */ }
              return super.performClick();
          }
          

          自定义 Spinner 是在整个项目中以编程方式标准化 Spinner 外观的绝佳起点。

          如果有兴趣,请看here

          【讨论】:

            猜你喜欢
            • 2012-08-19
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-12-07
            相关资源
            最近更新 更多