Android 自定义列表视图适配器和数字选择器对话框片段

Android custom listview adapter and numberpicker dialogfragment

我正在尝试创建我的第一个 Android 应用程序,但我做不到我想做的。 我的想法是创建一个简单的计分器。我有一个带有列表视图的 activity。列表视图的每个项目都有一个带有名称的 TextView,两个用于添加和减去的按钮,以及一个用于分数的 TextView。

我的想法是在用户点击分数时显示一个自定义数字选择器,以 select 增加或减少一个数字。自定义数字选择器有一个使用回调方法获取数字的接口 selected.

在 activity class 中,我有一个用于列表视图的自定义适配器,以及一个用于改进功能的查看器 class。我有几个 doubts/problems:

1) 我什么时候可以为 buttons/textviews 定义监听器?目前我在 viewholder 中有监听器,但我不确定它是否是更好的解决方案,也许最好在适配器中定义它们,或者甚至为列表视图创建一个 onitemclicklistener。

2) 我可以在adapter 或viewholder 中实现numberpicker 对话框界面中定义的方法吗class?我试过了,但我得到了一个转换异常,因为内部 class 不是 activity...

3) 如果我在 activity(外部)class 中实现接口方法,我将无法修改调用数字选择器的所需文本视图...

我的两个主要问题是在何处以及如何为列表视图行中的每个视图定义侦听器以及如何获取数字选择器对话框的编号并继续执行...

谁能帮帮我?

谢谢。

要在适配器内的视图中使用侦听器,应在适配器中声明侦听器,并应为每个视图创建一个新的侦听器实例。

private static class ViewHolder {
    private CustomListener listener;
    private Button incrementBtn;
}

现在在 getView() 方法中:

holder.listener = new CustomListener(position);
holder.incrementBtn.setOnClickListener(holder.listener);

现在定义一个继承的class来实现onClick()方法:

private class CustomListener implements View.OnClickListener {
    private int position;

    protected CustomListener(int position) {
        this.position = position;
    }

    @Override
    public void onClick(View v) {
        //increment score here
        notifyDataSetChanged();
    }
}

一旦 onClick() 方法完成,视图将通过 notifyDataSetChanged() 更新为新分数。 要使用数字选择器对话框,它是相同的模式,只是在 viewholder 中定义了一个 DialogInterface.OnClickListener

当然,对不起...

package com.example.cdp.mispartidas;

imports...

public class Tanteo extends ActionBarActivity {

private String identificador;
private Partida partida;
private Backup backup;
private int indice;
private static Context context;

ListView listviewjugadores;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_tanteo);

    // Parametros
    listviewjugadores = (ListView) findViewById(R.id.jugadorestanteo);

    Tanteo.context = getApplicationContext();

    Log.i("MILOG", "Obtenemos el backup");
    backup = Backup.getMiBackup(getApplicationContext());

    // Obtenemos el numero de jugadores
    Bundle bundle = getIntent().getExtras();
    identificador = bundle.getString("idpartida");

    Log.i("MILOG", "El identificador de la partida es " + identificador);


    // Buscamos la partida
    indice = backup.getPartida(identificador);
    if (indice >= 0) {
        partida = backup.getBackup().get(indice);
        // Establecemos el adaptador
        Log.i("MILOG", "Establecemos el adaptador");
        AdaptadorTanteo adaptador = new AdaptadorTanteo(this, getTaskId(), partida.getJugadores());
        listviewjugadores.setAdapter(adaptador);
    } else {
        Toast.makeText(this, "No se ha encontrado la partida " + identificador, Toast.LENGTH_SHORT).show();
    }

}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.menu_tanteo, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();

    int numjugadores;

    switch(id){
        // Anadimos un nuevo jugador a la partida
        case R.id.addjugador:
            numjugadores = listviewjugadores.getAdapter().getCount();
            Jugador player = new Jugador();
            // Ponemos un nombre por defecto
            player.setNombre("Jugador" + String.valueOf(numjugadores + 1));
            player.setNumerojugador(numjugadores + 1);
            // Anadimos la puntuacion
            player.setPuntuacion(0);
            // Anadimos el jugador a la lista
            partida.addJugador(player);
            // Actualizamos el backup
            backup.getBackup().set(indice, partida);
            // Almacenamos
            Log.i("MILOG", "Guardamos el backup");
            backup.guardarBackup();
            // Si todo ha ido bien, acutalizamos la lista de jugadores
            ((AdaptadorTanteo) listviewjugadores.getAdapter()).notifyDataSetChanged();
            break;

        case R.id.partidasguardadas:
            // Llamamos al intent de nuestras partidas guardadas
            Intent intenthistorial = new Intent(this, Historial.class);
            startActivity(intenthistorial);
            break;

        case R.id.reiniciarpartida:
            // Ponemos todos los marcadores a 0
            // Recorremos nuestra partida
            numjugadores = partida.getJugadores().size();
            // recorremos y reiniciamos
            for(int i = 0; i < numjugadores; i++){
                partida.getJugadores().get(i).setPuntuacion(0);
            }
            // Actualizamos el backup
            backup.getBackup().set(indice, partida);
            // Almacenamos
            Log.i("MILOG", "Guardamos el backup");
            backup.guardarBackup();
            // Si todo ha ido bien, acutalizamos la lista de jugadores
            ((AdaptadorTanteo) listviewjugadores.getAdapter()).notifyDataSetChanged();
            break;

        case R.id.action_settings:
            break;
        default:
            return true;
    }


    return super.onOptionsItemSelected(item);
}

// Adaptador para el layout del listview
public class AdaptadorTanteo extends ArrayAdapter<Jugador> {

    Activity context;
    List<Jugador> jugadores;
    ViewHolder holder;

    AdaptadorTanteo(Activity context, int textViewResourceId, List<Jugador> listajugadores) {
        super(context, textViewResourceId, listajugadores);
        this.context = context;
        this.jugadores = listajugadores;
    }

    public View getView(final int position, View convertView, ViewGroup parent) {
        View item = convertView;

        // Optimizamos el rendimiento de nuestra lista
        // Si la vista no existe, la creamos
        if (item == null) {
            LayoutInflater inflater = context.getLayoutInflater();
            item = inflater.inflate(R.layout.tanteo_jugador, null);

            // Declaramos el holder pasandole nuestras vistas
            TextView nombre = (TextView) item.findViewById(R.id.nombrejugador);
            TextView puntuacion = (TextView) item.findViewById(R.id.puntos);
            ImageButton mas = (ImageButton) item.findViewById(R.id.sumar);
            ImageButton menos = (ImageButton) item.findViewById(R.id.restar);

            holder = new ViewHolder(nombre, puntuacion, mas, menos);

            // Establecemos el tag
            item.setTag(holder);
        }
        // Si la vista existe, la reusamos
        else {
            holder = (ViewHolder) item.getTag();
        }

        // Guardamos la posicion en el holder para usarlo en los listener
        holder.botonmas.setTag(position);
        holder.botonmenos.setTag(position);
        holder.puntos.setTag(position);

        // Establecemos el nombre por defecto
        holder.nombrejugador.setText(jugadores.get(position).getNombre());
        holder.puntos.setText(String.valueOf(jugadores.get(position).getPuntuacion()));

        return (item);
    }
}


class ViewHolder implements NumeroTanteoDialogFragment.NumberTanteoDialogListener{

    TextView nombrejugador;
    TextView puntos;
    ImageButton botonmas;
    ImageButton botonmenos;
    int position;

    public ViewHolder(TextView nombre, TextView puntuacion, ImageButton mas, ImageButton menos) {

        nombrejugador = nombre;
        puntos = puntuacion;
        botonmas = mas;
        botonmenos = menos;

        // Definimos los listener
        nombrejugador.setOnClickListener(miListenerLocal);
        puntos.setOnClickListener(miListenerLocal);
        botonmas.setOnClickListener(miListenerLocal);
        botonmenos.setOnClickListener(miListenerLocal);

    }

    // Creamos aqui los listener
    // Asi tenemos acceso al resto de vistas dentro de la fila
    private View.OnClickListener miListenerLocal = new View.OnClickListener() {

        @Override
        public void onClick(View v) {

            position = (Integer) v.getTag();

            // Comprobamos la vista que lo esta invocando
            switch (v.getId()) {
                case R.id.nombrejugador:

                    break;

                case R.id.puntos:
                    try {
                        // Decrementamos el tanteo
                        Log.i("MILOG", "Modificamos el tanteo");
                        // Lanzamos el dialog
                        NumeroTanteoDialogFragment fragmento = new NumeroTanteoDialogFragment();
                        Bundle bundles = new Bundle();
                        bundles.putString("titulo", getString(R.string.sumar_puntos));
                        fragmento.setArguments(bundles);
                        Log.i("MILOG", "Mostramos el dialog para elegir el numero que queremos modificar");
                        FragmentManager fragmentManager = ((Activity) context).getFragmentManager();
                        fragmento.show(fragmentManager, "Dialogo_jugadores");

                    } catch (Exception ex) {
                        Toast.makeText(Tanteo.context, "Se produjo un error al modificar el tanteo", Toast.LENGTH_SHORT).show();
                    }
                    break;

                case R.id.sumar:
                    try {
                        Log.i("MILOG", "Sumamos uno");
                        // Incrementamos el tanteo
                        int tantos = Integer.parseInt(puntos.getText().toString()) + 1;
                        puntos.setText(String.valueOf(tantos));
                        // Actualizamos el backup
                        partida.getJugadores().get(position).setPuntuacion(tantos);
                        // Actualizamos el backup
                        backup.getBackup().set(indice, partida);
                        // Almacenamos
                        Log.i("MILOG", "Guardamos el backup");
                        backup.guardarBackup();

                    } catch (Exception ex) {
                        Toast.makeText(Tanteo.context, "Se produjo un error al incrementar el tanteo", Toast.LENGTH_SHORT).show();
                    }
                    break;

                case R.id.restar:
                    try {
                        // Decrementamos el tanteo
                        Log.i("MILOG", "Restamos uno");
                        int tantos = Integer.parseInt(puntos.getText().toString()) - 1;
                        puntos.setText(String.valueOf(puntos));
                        // Actualizamos el backup
                        partida.getJugadores().get(position).setPuntuacion(tantos);
                        // Actualizamos el backup
                        backup.getBackup().set(indice, partida);
                        // Almacenamos
                        Log.i("MILOG", "Guardamos el backup");
                        backup.guardarBackup();
                    } catch (Exception ex) {
                        Toast.makeText(Tanteo.context, "Se produjo un error al decrementar el tanteo", Toast.LENGTH_SHORT).show();
                    }
                    break;

            }
        }
    };

    // Sobreescribimos el metodo del dialogo para elegir el numero
    @Override
    public void onNumberSelected(int number) {

        Log.i("MILOG", "Actualizamos los puntos con el dialog");
        int puntuacion = Integer.parseInt(puntos.getText().toString()) + number;
        // Modificamos los puntos
        puntos.setText(String.valueOf(puntuacion));

        // Actualizamos el backup
        partida.getJugadores().get(position).setPuntuacion(puntuacion);
        // Actualizamos el backup
        backup.getBackup().set(indice, partida);
        // Almacenamos
        Log.i("MILOG", "Guardamos el backup");
        backup.guardarBackup();
    }
}

}

感谢您的帮助,

我根据您的指示解决了这个问题。我按照你告诉我的那样定义了听众。我的问题之一是我在两个不同的地方更新了 viewholder 对象。我已经更改了它,还使用 ​​notifyDataSetChanged() 更新了视图。

数字选择器的解决方案是在主activity中实现回调方法,并将列表视图的位置作为参数传递以更改正确的项目。

此致。