在用户界面中必须有一个微调器,其中包含一些名称(名称是可见的)并且每个名称都有自己的 ID(ID 不等于显示顺序)。当用户从列表中选择名称时,必须更改变量 currentID。
该应用程序包含 ArrayList
其中 User 是具有 ID 和名称的对象:
public class User{
public int ID;
public String name;
}
What I don't know is how to create a spinner which displays the list of user's names and bind spinner items to IDs so when the spinner item is selected/changed the variable currentID is set to appropriate value.
如果有人可以展示所描述问题的解决方案或提供任何有助于解决问题的链接,我将不胜感激。
谢谢!
我知道线程是旧的,但以防万一......
用户对象:
public class User{
private int _id;
private String _name;
public User(){
this._id = 0;
this._name = "";
}
public void setId(int id){
this._id = id;
}
public int getId(){
return this._id;
}
public void setName(String name){
this._name = name;
}
public String getName(){
return this._name;
}
}
自定义微调器适配器 (ArrayAdapter)
public class SpinAdapter extends ArrayAdapter<User>{
// Your sent context
private Context context;
// Your custom values for the spinner (User)
private User[] values;
public SpinAdapter(Context context, int textViewResourceId,
User[] values) {
super(context, textViewResourceId, values);
this.context = context;
this.values = values;
}
@Override
public int getCount(){
return values.length;
}
@Override
public User getItem(int position){
return values[position];
}
@Override
public long getItemId(int position){
return position;
}
// And the "magic" goes here
// This is for the "passive" state of the spinner
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// I created a dynamic TextView here, but you can reference your own custom layout for each spinner item
TextView label = (TextView) super.getView(position, convertView, parent);
label.setTextColor(Color.BLACK);
// Then you can get the current item using the values array (Users array) and the current position
// You can NOW reference each method you has created in your bean object (User class)
label.setText(values[position].getName());
// And finally return your dynamic (or custom) view for each spinner item
return label;
}
// And here is when the "chooser" is popped up
// Normally is the same view, but you can customize it if you want
@Override
public View getDropDownView(int position, View convertView,
ViewGroup parent) {
TextView label = (TextView) super.getDropDownView(position, convertView, parent);
label.setTextColor(Color.BLACK);
label.setText(values[position].getName());
return label;
}
}
和实施:
public class Main extends Activity {
// You spinner view
private Spinner mySpinner;
// Custom Spinner adapter (ArrayAdapter<User>)
// You can define as a private to use it in the all class
// This is the object that is going to do the "magic"
private SpinAdapter adapter;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Create the Users array
// You can get this retrieving from an external source
User[] users = new User[2];
users[0] = new User();
users[0].setId(1);
users[0].setName("Joaquin");
users[1] = new User();
users[1].setId(2);
users[1].setName("Alberto");
// Initialize the adapter sending the current context
// Send the simple_spinner_item layout
// And finally send the Users array (Your data)
adapter = new SpinAdapter(Main.this,
android.R.layout.simple_spinner_item,
users);
mySpinner = (Spinner) findViewById(R.id.miSpinner);
mySpinner.setAdapter(adapter); // Set the custom adapter to the spinner
// You can create an anonymous listener to handle the event when is selected an spinner item
mySpinner.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view,
int position, long id) {
// Here you get the current item (a User object) that is selected by its position
User user = adapter.getItem(position);
// Here you can do the action you want to...
Toast.makeText(Main.this, "ID: " + user.getId() + "\nName: " + user.getName(),
Toast.LENGTH_SHORT).show();
}
@Override
public void onNothingSelected(AdapterView<?> adapter) { }
});
}
}
最简单的解决方案
在搜索了 SO 上的不同解决方案后,我发现以下是使用自定义 Objects
填充 Spinner
的最简单和最干净的解决方案。这是完整的实现:
用户.java
public class User{
public int ID;
public String name;
@Override
public String toString() {
return this.name; // What to display in the Spinner list.
}
}
res/layout/spinner.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:textSize="14sp"
android:textColor="#FFFFFF"
android:spinnerMode="dialog" />
res/layout/your_activity_view.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<Spinner android:id="@+id/user" />
</LinearLayout>
在您的活动中
List<User> users = User.all(); // This example assumes you're getting all Users but adjust it for your Class and needs.
ArrayAdapter userAdapter = new ArrayAdapter(this, R.layout.spinner, users);
Spinner userSpinner = (Spinner) findViewById(R.id.user);
userSpinner.setAdapter(userAdapter);
userSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
// Get the value selected by the user
// e.g. to store it as a field or immediately call a method
User user = (User) parent.getSelectedItem();
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
currentID
。大多数情况下,您只需要在随后点击一个按钮(例如 Submit 或 Save)之后才需要 Spinner 的值,而不是在 Spinner 之后立即i>Spinner 发生变化,如果可以避免,这提供了一个更简单的解决方案。
getSelectedItem()
调用放入其中。谢谢你的提示。
对于简单的解决方案,您只需覆盖对象中的“toString”
public class User{
public int ID;
public String name;
@Override
public String toString() {
return name;
}
}
然后你可以使用:
ArrayAdapter<User> dataAdapter = new ArrayAdapter<User>(mContext, android.R.layout.simple_spinner_item, listOfUsers);
这样,您的微调器将仅显示用户名。
您可以look at this answer。您也可以使用自定义适配器,但以下解决方案适用于简单情况。
这是一个重新发布:
因此,如果您来这里是因为您想在 Spinner 中同时拥有标签和值 - 我就是这样做的:
只需按照通常的方式创建 Spinner 在您的 array.xml 文件中定义 2 个大小相等的数组 - 一个用于标签的数组,一个用于值的数组 使用 android:entries="@array/labels" 设置您的 Spinner 当您需要一个值时,请执行像这样的东西(不,你不必链接它): String selectedVal = getResources().getStringArray(R.array.values)[spinner.getSelectedItemPosition()];
到目前为止,我发现的最简单的方法:
@Override
public String toString() {
return this.label;
}
现在你可以在你的微调器中粘贴任何物体,它会显示指定的标签。
只需对 Joaquin Alberto 的回答稍作调整即可解决样式问题。只需替换自定义适配器中的 getDropDownView 函数,如下所示,
@Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
View v = super.getDropDownView(position, convertView, parent);
TextView tv = ((TextView) v);
tv.setText(values[position].getName());
tv.setTextColor(Color.BLACK);
return v;
}
对我来说很好,围绕 getResource() 事情所需的代码如下:
spinner = (Spinner) findViewById(R.id.spinner);
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> spinner, View v,
int arg2, long arg3) {
String selectedVal = getResources().getStringArray(R.array.compass_rate_values)[spinner.getSelectedItemPosition()];
//Do something with the value
}
@Override
public void onNothingSelected(AdapterView<?> arg0) {
// TODO Auto-generated method stub
}
});
只需要确保(自己)两个数组中的值正确对齐!
受华金·阿尔贝托的启发,这对我有用:
public class SpinAdapter extends ArrayAdapter<User>{
public SpinAdapter(Context context, int textViewResourceId,
User[] values) {
super(context, textViewResourceId, values);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
TextView label = (TextView) super.getView(position, convertView, parent);
label.setTextColor(Color.BLACK);
label.setText(this.getItem(position).getName());
return label;
}
@Override
public View getDropDownView(int position, View convertView,ViewGroup parent) {
TextView label = (TextView) super.getView(position, convertView, parent);
label.setTextColor(Color.BLACK);
label.setText(this.getItem(position).getName());
return label;
}
}
基于 Joaquin Alberto(感谢)示例,但它适用于任何类型(您应该在类型中实现 toString(),以便您可以格式化输出。
import java.util.List;
import android.content.Context;
import android.graphics.Color;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
public class SpinAdapter<T> extends ArrayAdapter<T> {
private Context context;
private List<T> values;
public SpinAdapter(Context context, int textViewResourceId, List<T> values) {
super(context, textViewResourceId, values);
this.context = context;
this.values = values;
}
public int getCount() {
return values.size();
}
public T getItem(int position) {
return values.get(position);
}
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
TextView label = new TextView(context);
label.setTextColor(Color.BLACK);
label.setText(values.toArray(new Object[values.size()])[position]
.toString());
return label;
}
@Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
TextView label = new TextView(context);
label.setTextColor(Color.BLACK);
label.setText(values.toArray(new Object[values.size()])[position]
.toString());
return label;
}
}
另外我认为你可以用数组替换列表,所以你不需要在列表中做 toArray,但我有一个列表..... :)
科特林:
data class User(
var id: Long,
var name : String? ){
override fun toString(): String {
return name
}
}
执行
mBinding.ddUser.setOnItemClickListener { parent, view, position, id ->
val user = adapter.getItem(position)
Log.i("idUser","${user?.idtoString()} - ${user?.name}")
}
为了理解这个技巧,必须知道适配器一般是如何工作的,特别是 ArrayAdapter。
适配器:是能够将数据结构绑定到小部件的对象,然后这些小部件在 List 或 Spinner 中显示该数据。
所以适配器回答的两个问题是:
哪个小部件或复合视图需要与某个索引的数据结构(您的类的对象)相关联?如何从数据结构(您的类的对象)中提取数据以及如何根据这些数据设置小部件或复合视图的字段,即 EditText?
ArrayAdapter 的答案是:
任何索引的每个小部件(即 row.xml 或 android.R.layout.simple_spinner_item)都是相同的,并且从其 ID 提供给 ArrayAdapter 的构造函数的资源中膨胀。
每个小部件都应该是 TextView(或后代)的一个实例。小部件的 .setText() 方法将与支持数据结构中项目的字符串格式一起使用。字符串格式将通过在项目上调用 .toString() 来获得。
CustomListViewDemo.java
public class CustomListViewDemo extends ListActivity {
private EfficientAdapter adap;
private static String[] data = new String[] { "0", "1", "2", "3", "4" };
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.main);
adap = new EfficientAdapter(this);
setListAdapter(adap);
}
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
// TODO Auto-generated method stub
super.onListItemClick(l, v, position, id);
Toast.makeText(this, "Click-" + String.valueOf(position), Toast.LENGTH_SHORT).show();
}
public static class EfficientAdapter extends BaseAdapter implements Filterable {
private LayoutInflater mInflater;
private Bitmap mIcon1;
private Context context;
int firstpos=0;
public EfficientAdapter(Context context) {
// Cache the LayoutInflate to avoid asking for a new one each time.
mInflater = LayoutInflater.from(context);
this.context = context;
}
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.adaptor_content, null);
holder = new ViewHolder();
holder.sp = (Spinner) convertView.findViewById(R.id.spinner1);
holder.ArrayAdapter_sp = new ArrayAdapter(parent.getContext(),android.R.layout.simple_spinner_item,data);
holder.ArrayAdapter_sp.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
holder.sp.setAdapter( holder.ArrayAdapter_sp);
holder.sp.setOnItemSelectedListener(new OnItemSelectedListener()
{
private int pos = position;
@Override
public void onItemSelected(AdapterView<?> arg0, View arg1,
int p, long arg3)
{
// TODO Auto-generated method stub
Toast.makeText(context, "select spinner " + String.valueOf(pos)+" with value ID "+p, Toast.LENGTH_SHORT).show();
}
@Override
public void onNothingSelected(AdapterView<?> arg0)
{
// TODO Auto-generated method stub
}
});
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
return convertView;
}
static class ViewHolder
{
Spinner sp;
ArrayAdapter ArrayAdapter_sp;
}
@Override
public Filter getFilter() {
// TODO Auto-generated method stub
return null;
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return 0;
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return data.length;
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return data[position];
}
}
}
适配器内容.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/lineItem"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical" >
<Spinner
android:id="@+id/spinner1"
android:layout_width="314dp"
android:layout_height="wrap_content" />
</LinearLayout>
主要的.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="fill_parent" android:layout_width="fill_parent"
>
<ListView
android:id="@+id/android:list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_marginBottom="60dip"
android:layout_marginTop="10dip"
android:cacheColorHint="#00000000"
android:drawSelectorOnTop="false" />
</RelativeLayout>
它工作正常,我希望它有用。
这是 Kotlin 中的完整过程:
微调器适配器类:
class CustomSpinnerAdapter(
context: Context,
textViewResourceId: Int,
val list: List<User>
) : ArrayAdapter<User>(
context,
textViewResourceId,
list
) {
override fun getCount() = list.size
override fun getItem(position: Int) = list[position]
override fun getItemId(position: Int) = list[position].report.toLong()
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
return (super.getDropDownView(position, convertView, parent) as TextView).apply {
text = list[position].name
}
}
override fun getDropDownView(position: Int, convertView: View?, parent: ViewGroup): View {
return (super.getDropDownView(position, convertView, parent) as TextView).apply {
text = list[position].name
}
}
}
并在您的活动/片段中使用它,如下所示:
spinner.adapter = CustomerSalesSpinnerAdapter(
context,
R.layout.cuser_spinner_item,
userList
)
**Easy & Simple Solution**
overide the below method in model class.
@NonNull
@Override
public String toString() {
return name; //whatever the value which you want to show in spinner list.
}
Add the below line to set adapter.
spinner.setAdapter(new ArrayAdapter<ModelClassName>(getContext(),R.layout.item_spinner,list));
我的自定义对象是
/**
* Created by abhinav-rathore on 08-05-2015.
*/
public class CategoryTypeResponse {
private String message;
private int status;
private Object[] object;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public Object[] getObject() {
return object;
}
public void setObject(Object[] object) {
this.object = object;
}
@Override
public String toString() {
return "ClassPojo [message = " + message + ", status = " + status + ", object = " + object + "]";
}
public static class Object {
private String name;
private String _id;
private String title;
private String desc;
private String xhdpi;
private String hdpi;
private String mdpi;
private String hint;
private String type;
private Brands[] brands;
public String getId() {
return _id;
}
public void setId(String id) {
this._id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getXhdpi() {
return xhdpi;
}
public void setXhdpi(String xhdpi) {
this.xhdpi = xhdpi;
}
public String getHdpi() {
return hdpi;
}
public void setHdpi(String hdpi) {
this.hdpi = hdpi;
}
public String getMdpi() {
return mdpi;
}
public void setMdpi(String mdpi) {
this.mdpi = mdpi;
}
public String get_id() {
return _id;
}
public void set_id(String _id) {
this._id = _id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public String getHint() {
return hint;
}
public void setHint(String hint) {
this.hint = hint;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public Brands[] getBrands() {
return brands;
}
public void setBrands(Brands[] brands) {
this.brands = brands;
}
@Override
public String toString() {
return "ClassPojo [name = " + name + "]";
}
}
public static class Brands {
private String _id;
private String name;
private String value;
private String categoryid_ref;
public String get_id() {
return _id;
}
public void set_id(String _id) {
this._id = _id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String getCategoryid_ref() {
return categoryid_ref;
}
public void setCategoryid_ref(String categoryid_ref) {
this.categoryid_ref = categoryid_ref;
}
@Override
public String toString() {
return name;
}
}
}
我还想将此对象设置为我的微调器的适配器源,而不扩展 ArrayAdapter,这样我所做的就是。
brandArray = mCategoryTypeResponse.getObject()[fragPosition].getBrands();
ArrayAdapter brandAdapter = new ArrayAdapter< CategoryTypeResponse.Brands>(getActivity(),
R.layout.item_spinner, brandArray);
现在您将能够在微调器中看到结果,诀窍是在 自定义对象 中覆盖 toString()
,因此您想在微调器中显示的任何值都只需在此方法中返回即可。
如果你不需要一个单独的类,我的意思是一个简单的适配器映射到你的对象上。这是我基于提供的 ArrayAdapter 函数的代码。
并且因为您可能需要在适配器创建后添加项目(例如数据库项目异步加载)。
简单但高效。
editCategorySpinner = view.findViewById(R.id.discovery_edit_category_spinner);
// Drop down layout style - list view with radio button
dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
// attaching data adapter to spinner, as you can see i have no data at this moment
editCategorySpinner.setAdapter(dataAdapter);
final ArrayAdapter<Category> dataAdapter = new ArrayAdapter<Category>
(getActivity(), android.R.layout.simple_spinner_item, new ArrayList<Category>(0)) {
// And the "magic" goes here
// This is for the "passive" state of the spinner
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// I created a dynamic TextView here, but you can reference your own custom layout for each spinner item
TextView label = (TextView) super.getView(position, convertView, parent);
label.setTextColor(Color.BLACK);
// Then you can get the current item using the values array (Users array) and the current position
// You can NOW reference each method you has created in your bean object (User class)
Category item = getItem(position);
label.setText(item.getName());
// And finally return your dynamic (or custom) view for each spinner item
return label;
}
// And here is when the "chooser" is popped up
// Normally is the same view, but you can customize it if you want
@Override
public View getDropDownView(int position, View convertView,
ViewGroup parent) {
TextView label = (TextView) super.getDropDownView(position, convertView, parent);
label.setTextColor(Color.BLACK);
Category item = getItem(position);
label.setText(item.getName());
return label;
}
};
然后您可以使用此代码(我无法将 Category[] 放入适配器构造函数中,因为数据是单独加载的)。
请注意,adapter.addAll(items) 通过在内部调用 notifyDataSetChanged() 刷新微调器。
categoryRepository.getAll().observe(this, new Observer<List<Category>>() {
@Override
public void onChanged(@Nullable final List<Category> items) {
dataAdapter.addAll(items);
}
});
我认为最好的解决方案是Josh Pinter 的"Simplest Solution"。
这对我有用:
//Code of the activity
//get linearLayout
LinearLayout linearLayout = (LinearLayout ) view.findViewById(R.id.linearLayoutFragment);
LinearLayout linearLayout = new LinearLayout(getActivity());
//display css
RelativeLayout.LayoutParams params2 = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
//create the spinner in a fragment activiy
Spinner spn = new Spinner(getActivity());
// create the adapter.
ArrayAdapter<ValorLista> spinner_adapter = new ArrayAdapter<ValorLista>(getActivity(), android.R.layout.simple_spinner_item, meta.getValorlistaList());
spinner_adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spn.setAdapter(spinner_adapter);
//set the default according to value
//spn.setSelection(spinnerPosition);
linearLayout.addView(spn, params2);
//Code of the class ValorLista
import java.io.Serializable;
import java.util.List;
public class ValorLista implements Serializable{
/**
*
*/
private static final long serialVersionUID = 4930195743192929192L;
private int id;
private String valor;
private List<Metadato> metadatoList;
public ValorLista() {
super();
// TODO Auto-generated constructor stub
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getValor() {
return valor;
}
public void setValor(String valor) {
this.valor = valor;
}
public List<Metadato> getMetadatoList() {
return metadatoList;
}
public void setMetadatoList(List<Metadato> metadatoList) {
this.metadatoList = metadatoList;
}
@Override
public String toString() {
return getValor();
}
}
做:
spinner.adapter = object: ArrayAdapter<Project>(
container.context,
android.R.layout.simple_spinner_dropdown_item,
state.projects
) {
override fun getDropDownView(
position: Int,
convertView: View?,
parent: ViewGroup
): View {
val label = super.getView(position, convertView, parent) as TextView
label.text = getItem(position)?.title
return label
}
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
val label = super.getView(position, convertView, parent) as TextView
label.text = getItem(position)?.title
return label
}
}
Skipped 317 frames! The application may be doing too much work on its main thread.
确认我有什么想法吗?