Android:如何将微调器绑定到自定义对象列表?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1625249/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Android: How to bind spinner to custom object list?
提问by Niko Gamulin
In the user interface there has to be a spinner which contains some names (the names are visible) and each name has its own ID (the IDs are not equal to display sequence). When the user selects the name from the list the variable currentID has to be changed.
在用户界面中必须有一个包含一些名称(名称可见)的微调器,每个名称都有自己的 ID(ID 不等于显示顺序)。当用户从列表中选择名称时,必须更改变量 currentID。
The application contains the ArrayList
应用程序包含 ArrayList
Where User is an object with ID and name:
其中 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.
我不知道的是如何创建一个显示用户名列表的微调器并将微调项绑定到 ID,以便在选择/更改微调项时将变量 currentID 设置为适当的值。
I would appreciate if anyone could show the solution of the described problem or provide any link useful to solve the problem.
如果有人可以展示所描述问题的解决方案或提供任何有助于解决问题的链接,我将不胜感激。
Thanks!
谢谢!
采纳答案by Bostone
You can look at this answer. You can also go with a custom adapter, but the solution below is fine for simple cases.
你可以看看这个答案。您也可以使用自定义适配器,但下面的解决方案适用于简单情况。
Here's a re-post:
这是一个重新发布:
So if you came here because you want to have both labels and values in the Spinner - here's how I did it:
因此,如果您来到这里是因为您想在 Spinner 中同时拥有标签和值 - 我是这样做的:
- Just create your
Spinner
the usual way - Define 2 equal size arrays in your
array.xml
file -- one array for labels, one array for values - Set your
Spinner
withandroid:entries="@array/labels"
When you need a value, do something like this (no, you don't have to chain it):
String selectedVal = getResources().getStringArray(R.array.values)[spinner.getSelectedItemPosition()];
- 只需
Spinner
按照通常的方式创建 - 在您的
array.xml
文件中定义 2 个相同大小的数组——一个用于标签的数组,一个用于值的数组 - 设置你
Spinner
的android:entries="@array/labels"
当您需要一个值时,请执行以下操作(不,您不必链接它):
String selectedVal = getResources().getStringArray(R.array.values)[spinner.getSelectedItemPosition()];
回答by Joaquin Alberto
I know the thread is old, but just in case...
我知道线程很旧,但以防万一......
User object:
用户对象:
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;
}
}
Custom Spinner Adapter (ArrayAdapter)
自定义微调适配器 (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;
}
}
And the implementarion:
和实现:
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) { }
});
}
}
回答by Joshua Pinter
Simplest Solution
最简单的解决方案
After scouring different solutions on SO, I found the following to be the simplest and cleanest solution for populating a Spinner
with custom Objects
. Here's the full implementation:
在 SO 上搜索不同的解决方案后,我发现以下是Spinner
使用 custom填充 a 的最简单和最干净的解决方案Objects
。这是完整的实现:
User.java
用户.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
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
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>
In Your Activity
在您的活动中
// Gets all users but replace with whatever list of users you want.
List<User> users = User.all();
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) {
}
});
回答by SpyZip
For simple solutions you can just Overwrite the "toString" in your object
对于简单的解决方案,您可以覆盖对象中的“toString”
public class User{
public int ID;
public String name;
@Override
public String toString() {
return name;
}
}
and then you can use:
然后你可以使用:
ArrayAdapter<User> dataAdapter = new ArrayAdapter<User>(mContext, android.R.layout.simple_spinner_item, listOfUsers);
This way your spinner will show only the user names.
这样您的微调器将只显示用户名。
回答by NielW
By far the simplest way that I've found:
到目前为止,我发现的最简单的方法:
@Override
public String toString() {
return this.label;
}
Now you can stick any object in your spinner, and it will display the specified label.
现在您可以在微调器中粘贴任何对象,它会显示指定的标签。
回答by Tirtharup Bhattacharyya
Just a small tweak to Joaquin Alberto's answer can solve the style issue.Just replace the getDropDownView function in the custom adapter as below,
只需对 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;
}
回答by Sonja
Works fine for me, the code needed around the getResource() thing is as follows:
对我来说很好用,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
}
});
Just need to make sure (by yourself) the values in the two arrays are aligned properly!
只需要(自己)确保两个数组中的值正确对齐!
回答by Annamaria
inspired by Joaquin Alberto, this worked for me:
受华金阿尔贝托的启发,这对我有用:
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;
}
}
回答by Alberto Ricart
Based on Joaquin Alberto (thanks) sample, but it works for any type (you should implement toString() in type, so you can format the output.
基于 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;
}
}
Also i think you can replace List by Array so you don't need to do toArray in List, but i had a List ..... :)
另外我认为你可以用数组替换列表,所以你不需要在列表中做 toArray,但我有一个列表 ..... :)
回答by Parag Ghetiya
In order to understand the trick, one has to know, how Adapters work in general and ArrayAdapter in particular.
为了理解这个技巧,你必须知道适配器一般是如何工作的,特别是 ArrayAdapter 是如何工作的。
Adapters: are objects that are able to bind data structures to widgets, then these widgets are displaying that data in a List or in a Spinner.
适配器:是能够将数据结构绑定到小部件的对象,然后这些小部件在列表或微调器中显示该数据。
So the two questions an Adapter answers are:
所以适配器回答的两个问题是:
- Which widget or composite view needs to be associated with a data structure(your class' object) for a certain index?
- How to extract the data from the data structure(your class' object) and how to set field(s) i.e
EditText
of the widget or composite view according to this data?
- 哪个小部件或复合视图需要与某个索引的数据结构(您的类的对象)相关联?
- 如何从数据结构(您的类对象)中提取数据以及如何
EditText
根据此数据设置小部件或复合视图的字段?
ArrayAdapter's answers are:
ArrayAdapter 的回答是:
- Each widget (i.e
row.xml
ORandroid.R.layout.simple_spinner_item
) for any index is the same, and is inflated from the resource whose ID was given to ArrayAdapter's constructor. - Each widget is expected to be an instance of TextView (or
descendant). The widget's
.setText()
method will be used with the string format of the item in the supporting data structure. The string format will be obtained by invoking.toString()
on the item.
- 任何索引的每个小部件(即
row.xml
ORandroid.R.layout.simple_spinner_item
)都是相同的,并且从其 ID 被赋予给 ArrayAdapter 的构造函数的资源膨胀。 - 每个小部件都应该是 TextView(或后代)的一个实例。小部件的
.setText()
方法将与支持数据结构中项目的字符串格式一起使用。字符串格式将通过调用.toString()
该项目获得。
CustomListViewDemo.java
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];
}
}
}
adaptor_content.xml
适配器内容.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>
main.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>
It works properly, I hope it is useful.
它工作正常,我希望它有用。