Android: Как привязать счетчик к списку пользовательских объектов? - PullRequest
112 голосов
/ 26 октября 2009

В пользовательском интерфейсе должен быть счетчик, содержащий несколько имен (имена видны), и каждое имя имеет свой собственный идентификатор (идентификаторы не равны последовательности отображения). Когда пользователь выбирает имя из списка, переменная currentID должна быть изменена.

Приложение содержит ArrayList

Где пользователь - это объект с идентификатором и именем:

public class User{
        public int ID;
        public String name;
    }

Чего я не знаю, так это как создать счетчик, который отображает список имен пользователей и привязывает элементы счетчика к идентификаторам, поэтому при выборе / изменении элемента счетчика переменная currentID устанавливается на соответствующее значение.

Буду признателен, если кто-нибудь покажет решение описанной проблемы или предоставит любую ссылку, полезную для решения проблемы.

Спасибо!

Ответы [ 13 ]

311 голосов
/ 14 ноября 2011

Я знаю, что ветка старая, но на всякий случай ...

Объект пользователя:

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;
    }
}

Настраиваемый адаптер Spinner (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) {  }
        });
    }
}
82 голосов
/ 16 января 2014

простейшее решение

После изучения различных решений для SO я обнаружил, что следующее является самым простым и чистым решением для заполнения Spinner пользовательским Objects. Вот полная реализация:

User.java

public class User{
    public int ID;
    public String name;

    @Override
    public String toString() {
        return this.name;            // What to display in the Spinner list.
    }
}    

Рез / макет / 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" />

Рез / макет / 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>

В вашей деятельности

// 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);



// And to get the actual User object that was selected, you can do this.
User user = (User) ( (Spinner) findViewById(R.id.user) ).getSelectedItem();
47 голосов
/ 14 апреля 2015

Для простых решений вы можете просто перезаписать "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);

Таким образом, ваш счетчик покажет только имена пользователей.

41 голосов
/ 26 октября 2009

Вы можете посмотреть на этот ответ . Вы также можете использовать специальный адаптер, но приведенное ниже решение подходит для простых случаев.

Вот повторный пост:

Так что, если вы пришли сюда, потому что хотите, чтобы в Spinner были и метки, и значения - вот как я это сделал:

  1. Просто создайте Spinner обычным способом
  2. Определите 2 массива равного размера в файле array.xml - один массив для меток, один массив для значений
  3. Установите Spinner с помощью android:entries="@array/labels"
  4. Когда вам нужно значение, сделайте что-то вроде этого (нет, вам не нужно связывать его):

      String selectedVal = getResources().getStringArray(R.array.values)[spinner.getSelectedItemPosition()];
    
8 голосов
/ 31 марта 2016

Простая настройка ответа Хоакина Альберто может решить проблему стиля. Просто замените функцию 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;
    }
6 голосов
/ 30 апреля 2010

Хорошо работает для меня, код, необходимый для 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
        }

    });

Просто нужно убедиться, что (самостоятельно) значения в двух массивах выровнены правильно!

5 голосов
/ 10 января 2016

Самый простой способ, который я нашел:

@Override
public String toString() {
    return this.label;           
}

Теперь вы можете вставить любой объект в ваш счетчик, и он будет отображать указанную метку.

5 голосов
/ 11 апреля 2013

На основе примера 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;
}
}

Также я думаю, что вы можете заменить List на Array, так что вам не нужно делать toArray в List, но у меня был List ..... :)

5 голосов
/ 26 февраля 2013

вдохновленный Хоакином Альберто, это сработало для меня:

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;
    }
}
3 голосов
/ 11 октября 2012

Чтобы понять хитрость, нужно знать, как работают адаптеры в целом и ArrayAdapter в частности.

Адаптеры: объекты, которые могут связывать структуры данных с виджетами, тогда эти виджеты отображают эти данные в Списке или в Спиннере.

Итак, два вопроса, на которые Адаптер отвечает:

  1. Какой виджет или составное представление необходимо связать со структурой данных (объектом вашего класса) для определенного индекса?
  2. Как извлечь данные из структуры данных (объекта вашего класса) и как установить поля (полей), т.е. EditText виджета или составного представления в соответствии с этими данными?

Ответы ArrayAdapter:

  • Каждый виджет (т.е. row.xml ИЛИ android.R.layout.simple_spinner_item) для любого индекса одинаков и раздувается из ресурса, идентификатор которого был передан конструктору 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];
    }

  }

}

adaptor_content.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>

Это работает правильно, я надеюсь, что это полезно.

...