Android Spinner:在初始化期间避免onItemSelected调用

时间:2012-11-15 12:55:24

标签: android android-layout android-spinner

我使用SpinnerTextView创建了Android应用程序。我的任务是在TextView的Spinner下拉列表中显示所选项目。我在onCreate方法中实现了Spinner,所以当我运行程序时,它会在TextView中显示一个值(在从下拉列表中选择一个项目之前)。

我想在从下拉列表中选择一个项目后才显示TextView中的值。我该怎么做?

这是我的代码:

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import android.widget.TextView;

public class GPACal01Activity extends Activity implements OnItemSelectedListener {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        Spinner spinner = (Spinner) findViewById(R.id.noOfSubjects);

        // Create an ArrayAdapter using the string array and a default spinner layout
        ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this,R.array.noofsubjects_array, android.R.layout.simple_spinner_item);
        // Specify the layout to use when the list of choices appears
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        // Apply the adapter to the spinner
        spinner.setAdapter(adapter);
        spinner.setOnItemSelectedListener(this);
    }

    public void onItemSelected(AdapterView<?> parent, View arg1, int pos,long id) {
        TextView textView = (TextView) findViewById(R.id.textView1);
        String str = (String) parent.getItemAtPosition(pos);
        textView.setText(str);
    }

    public void onNothingSelected(AdapterView<?> arg0) {
        // TODO Auto-generated method stub

    }
}

19 个答案:

答案 0 :(得分:143)

spinner.setOnItemSelectedListener(this); // Will call onItemSelected() Listener.

因此,首次使用任何整数值

处理此问题

实施例:  最初选择int check = 0;

public void onItemSelected(AdapterView<?> parent, View arg1, int pos,long id) {
   if(++check > 1) {
      TextView textView = (TextView) findViewById(R.id.textView1);
      String str = (String) parent.getItemAtPosition(pos);
      textView.setText(str);
   }
}

您可以使用布尔值以及检查当前位置和之前位置来执行此操作。 See here

答案 1 :(得分:76)

在设置 OnItemSelectedListener

之前放置此行
spinner.setSelection(0,false)

答案 2 :(得分:55)

从API级别3开始,您可以在具有布尔值的Activity上使用onUserInteraction()来确定用户是否正在与设备进行交互。

http://developer.android.com/reference/android/app/Activity.html#onUserInteraction()

@Override
public void onUserInteraction() {
     super.onUserInteraction();
     userIsInteracting = true;
}

作为我所拥有的活动的一个字段:

 private boolean userIsInteracting;

最后,我的微调器:

      mSpinnerView.setOnItemSelectedListener(new OnItemSelectedListener() {

           @Override
           public void onItemSelected(AdapterView<?> arg0, View view, int position, long arg3) {
                spinnerAdapter.setmPreviousSelectedIndex(position);
                if (userIsInteracting) {
                     updateGUI();
                }
           }

           @Override
           public void onNothingSelected(AdapterView<?> arg0) {

           }
      });

当你来完成活动时,布尔值会重置为false。像魅力一样。

答案 3 :(得分:15)

这对我有用

Spinner在Android中的初始化有时会出现问题 这种模式解决了上述问题。

Spinner.setAdapter();
Spinner.setSelected(false);  // must
Spinner.setSelection(0,true);  //must
Spinner.setonItemSelectedListener(this);

设置适配器应该是第一部分,onItemSelectedListener(this)在初始化微调器时将是最后一个。通过上面的模式,在初始化微调器

期间不会调用OnItemSelected()

答案 4 :(得分:10)

哈哈......我有同样的问题。 当initViews()只是这样做时。序列是关键,监听器是最后一个。祝你好运!

spinner.setAdapter(adapter);
spinner.setSelection(position);
spinner.setOnItemSelectedListener(listener);

答案 5 :(得分:7)

我的解决方案:

protected boolean inhibit_spinner = true;


@Override
        public void onItemSelected(AdapterView<?> arg0, View arg1,
                int pos, long arg3) {

            if (inhibit_spinner) {
                inhibit_spinner = false;
            }else {

            if (getDataTask != null) getDataTask.cancel(true);
            updateData();
            }

        }

答案 6 :(得分:6)

你可以这样做:

AdapterView.OnItemSelectedListener listener = new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
            //set the text of TextView
        }

        @Override
        public void onNothingSelected(AdapterView<?> adapterView) {

        }
    });

yourSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
            yourSpinner.setOnItemSelectedListener(listener);
        }

        @Override
        public void onNothingSelected(AdapterView<?> adapterView) {

        }
    });

首先,我创建一个监听器并归因于一个变量回调;然后我创建一个匿名的第二个监听器,当第一次调用它时,这会改变监听器 =]

答案 7 :(得分:2)

启用多个微调器的类似简单解决方案是将AdapterView放在一个集合中 - 在活动超类中 - 首次执行onItemSelected(...)然后在执行之前检查AdapterView是否在集合中。这样就可以在超类中启用一组方法,并支持多个AdapterViews,从而支持多个微调器。

超级......

private Collection<AdapterView> AdapterViewCollection = new ArrayList<AdapterView>();

   protected boolean firstTimeThrough(AdapterView parent) {
    boolean firstTimeThrough = ! AdapterViewCollection.contains(parent);
    if (firstTimeThrough) {
       AdapterViewCollection.add(parent);
     }
    return firstTimeThrough;
   }

子类...

public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
      if (! firstTimeThrough(parent)) {
        String value = safeString(parent.getItemAtPosition(pos).toString());
        String extraMessage = EXTRA_MESSAGE;
        Intent sharedPreferencesDisplayIntent = new         Intent(SharedPreferencesSelectionActivity.this,SharedPreferencesDisplayActivity.class);
    sharedPreferencesDisplayIntent.putExtra(extraMessage,value);
    startActivity(sharedPreferencesDisplayIntent);
  }
  // don't execute the above code if its the first time through
  // do to onItemSelected being called during view initialization.

}

答案 8 :(得分:2)

为避免在初始化期间调用spinner.setOnItemSelectedListener()

spinner.setSelection(Adapter.NO_SELECTION, true); //Add this line before setting listener
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {

    }

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

    }
});

答案 9 :(得分:2)

尝试一下

spinner.postDelayed(new Runnable() {
        @Override
        public void run() {
            addListeners();
        }
    }, 1000);.o

答案 10 :(得分:1)

我在Spinner的顶部放置了一个TextView,其大小和背景与Spinner相同,以便在用户单击它之前可以更好地控制它的外观。有了TextView,我还可以使用TextView在用户开始交互时进行标记。

我的Kotlin代码看起来像这样:

private var mySpinnerHasBeenTapped = false

private fun initializeMySpinner() {

    my_hint_text_view.setOnClickListener {
        mySpinnerHasBeenTapped = true //turn flag to true
        my_spinner.performClick() //call spinner click
    }

    //Basic spinner setup stuff
    val myList = listOf("Leonardo", "Michelangelo", "Rafael", "Donatello")
    val dataAdapter: ArrayAdapter<String> = ArrayAdapter<String>(this, android.R.layout.simple_spinner_dropdown_item, myList)
    my_spinner.adapter = dataAdapter

    my_spinner.onItemSelectedListener = object : OnItemSelectedListener {

        override fun onItemSelected(parent: AdapterView<*>?, view: View, position: Int, id: Long) {

            if (mySpinnerHasBeenTapped) { //code below will only run after the user has clicked
                my_hint_text_view.visibility = View.GONE //once an item has been selected, hide the textView
                //Perform action here
            }
        }

        override fun onNothingSelected(parent: AdapterView<*>?) {
            //Do nothing
        }
    }
}

布局文件看起来像这样,重要的部分是Spinner和TextView共享相同的宽度,高度和边距:

        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <Spinner
                android:id="@+id/my_spinner"
                android:layout_width="match_parent"
                android:layout_height="35dp"
                android:layout_marginStart="10dp"
                android:layout_marginEnd="10dp"
                android:background="@drawable/bg_for_spinners"

                android:paddingStart="8dp"
                android:paddingEnd="30dp"
                android:singleLine="true" />

            <TextView
                android:id="@+id/my_hint_text_view"
                android:layout_width="match_parent"
                android:layout_height="35dp"                
                android:layout_marginStart="10dp"
                android:layout_marginEnd="10dp"
                android:background="@drawable/bg_for_spinners"

                android:paddingStart="8dp"
                android:paddingEnd="30dp"
                android:singleLine="true"
                android:gravity="center_vertical"
                android:text="*Select A Turtle"
                android:textColor="@color/green_ooze"
                android:textSize="16sp" />

        </FrameLayout>

我确定其他解决方案都可以在您忽略第一个onItemSelected调用的情况下使用,但是我真的不喜欢假设它将始终被调用的想法。

答案 11 :(得分:1)

根据阿披的回答,我做了一个简单的听众

class SpinnerListener constructor(private val onItemSelected: (position: Int) -> Unit) : AdapterView.OnItemSelectedListener {

    private var selectionCount = 0

    override fun onNothingSelected(parent: AdapterView<*>?) {
        //no op
    }

    override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
        if (selectionCount++ > 1) {
           onItemSelected(position)
        }
    }
}

答案 12 :(得分:1)

这对我有用:

public ActionResult editExchangePost(int id)
{
    exchangeViewModel viewModel = new exchangeViewModel();
    viewModel.Poster = DB.Posters.Where(x => x.PostID == id).FirstOrDefault();
    viewModel.ExchangeImageList = DB.ExchangeImageGalleries.Where(x => x.PostIDFK == id).ToList();
    return PartialView("_editExchangePostPartialView" , viewModel);
}

[HttpPost]
public ActionResult editExchangePost(Poster post , IEnumerable<HttpPostedFileBase> thumb , ExchangeImageGallery images)
{
    // other operations
    return View()
}

[HttpPost]
public ActionResult postExchangeAd(Poster post , IEnumerable<HttpPostedFileBase> thumb , ExchangeImageGallery images)
{
    // other operations
    return View();
}

答案 13 :(得分:1)

创建一个布尔字段

private boolean inispinner;

在创建活动中

    spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
            if (!inispinner) {
                inispinner = true;
                return;
            }
            //do your work here
        }

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

        }
    });

答案 14 :(得分:1)

然后,可以在onTouch方法中将用户交互标志设置为true,并在处理选择更改后在onItemSelected()中重置。我更喜欢这种解决方案,因为用户交互标志专门为微调器处理,而不是为活动中可能影响所需行为的其他视图处理。

在代码中:

为微调器创建监听器:

public class SpinnerInteractionListener implements AdapterView.OnItemSelectedListener, View.OnTouchListener {

    boolean userSelect = false;

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        userSelect = true;
        return false;
    }

    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
        if (userSelect) { 
            userSelect = false;
            // Your selection handling code here
        }
    }

}

将监听器添加为微调器OnItemSelectedListenerOnTouchListener

SpinnerInteractionListener listener = new SpinnerInteractionListener();
mSpinnerView.setOnTouchListener(listener);
mSpinnerView.setOnItemSelectedListener(listener);

答案 15 :(得分:1)

首先可以通过setOnTouchListener实现它,然后在onTouch中实现setOnItemSelectedListener

@Override
public boolean onTouch(final View view, final MotionEvent event) {
 view.setOnItemSelectedListener(this)
 return false;
}

答案 16 :(得分:1)

有同样的问题,这对我有用:

我有2个微调器,我在初始化期间以及与其他控件交互期间或从服务器获取数据后更新它们。

这是我的模板:

public class MyClass extends <Activity/Fragment/Whatever> implements Spinner.OnItemSelectedListener {

    private void removeSpinnersListeners() {
        spn1.setOnItemSelectedListener(null);
        spn2.setOnItemSelectedListener(null);
    }

    private void setSpinnersListeners() {
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                spn1.setOnItemSelectedListener(MyClass.this);
                spn2.setOnItemSelectedListener(MyClass.this);
            }
        }, 1);
    }

    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
        // Your code here
    }

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

    }
}

当班级开始使用 setSpinnersListeners()时,而不是直接设置监听器。

Runnable将阻止微调器在您设置其值后立即触发onItemSelected。

如果您需要更新微调器(在服务器调用之后等),请在更新行之前使用 removeSpinnersListeners(),并在更新后立即使用 setSpinnersListeners()线。这将阻止onItemSelected在更新后触发。

答案 17 :(得分:0)

代码

public class GTLMTCallEmployesVM
{
        private ApplicationDbContext db;

        System.Security.Principal.IPrincipal user = HttpContext.Current.User;

        public GTLMTCallEmployesVM()
        {
            db = new ApplicationDbContext();

        } 

        [Required]
        [Display(Name = "Month")]
        public string TransactionMonth { get; set; }

        [Required]
        [Display(Name = "Year")]
        public string TransactionYear { get; set; }


        [Required]
        [Display(Name = "To Date")]
        public DateTime SalaryToDate { get; set; }


        [Required]
        [Display(Name = "From Date")]
        public DateTime SalaryFromDate { get; set; }


        [Required]
        [Display(Name = "Distributor")]
        public string BranchCode { get; set; }



        private SelectList _branchSelectListGT { get; set; }
        public SelectList BranchSelectListGT
        {
            get
            {
                if (_branchSelectListGT != null) return _branchSelectListGT;
                else
                {
                    if (user.IsInRole(constant.Roles.SuperAdmin) || user.IsInRole(constant.Roles.Admin))
                    {
                        return new SelectList(db.Branches.Where(x => x.DistributorType == SalaryModuleHelper.DistributorType.GT && x.DisableDate == null).ToList().Select(y => new BranchSelectListVM { BranchCode = y.BranchCode, BranchName = y.Name + "(" + y.BranchCode + ") " + y.DistributorType }).ToList(), "BranchCode", "BranchName");
                    }
                    else
                    {
                        var loggedInUserBranches = constant.GlobalHelper.GetBranchIds(user.Identity.GetUserId());

                        return new SelectList(db.Branches.Where(x => loggedInUserBranches.Any(y => y.Trim() == x.BranchCode.Trim()) && x.DistributorType == SalaryModuleHelper.DistributorType.GT && x.DisableDate == null).Select(x => new BranchSelectListVM { BranchCode = x.BranchCode, BranchName = x.Name + " (" + x.BranchCode + ") "+ x.DistributorType }).ToList(), "BranchCode", "BranchName");

                    }
                }
            }
            set { _branchSelectListGT = value; }
        }
}

答案 18 :(得分:0)

对我来说,Abhi的解决方案在Api级别27上都能很好地工作。

但是从Api级别28开始,似乎在设置侦听器时不会调用onItemSelected(),这意味着从不调用onItemSelected()。

因此,我添加了一个简短的if语句来检查Api级别:

public void onItemSelected(AdapterView<?> parent, View arg1, int pos,long id) {

            if(Build.VERSION.SDK_INT >= 28){ //onItemSelected() doesn't seem to be called when listener is set on Api 28+
                check = 1;
            }

            if(++check > 1) {
                //Do your action here
            }
        }

我认为这很奇怪,我不确定其他人是否也有此问题,但就我而言,它运行良好。