metodo - searchview android example listview
ListView que recicla interruptores posición de la barra de búsqueda (1)
Esbozaré una de las mejores formas de abordar esto (en mi opinión, por supuesto) al tiempo que respeto ListView''s
capacidad de reciclar de ListView''s
.
Pero primero, esto tiene que ir :
@Override
public int getViewTypeCount() {
return getCount();
}
@Override
public int getItemViewType(int position) {
return position;
}
Solución:
Subclase SeekBar
y déjelo manejar todas las actualizaciones:
Defina dos métodos que marcarán a este
SeekBar
activo e inactivo .Al marcar un
SeekBar
activo , proporcione la posición actual (progreso). Junto a, publicar elRunnable
que actualizará esteSeekBar
Al marcar un
SeekBar
inactivo , simplemente elimine las devoluciones de llamada deRunnable
yRunnable
un día
Dentro de su Adapter
, el único estado que necesita mantener es realizar un seguimiento de la canción que se está reproduciendo actualmente. Puede hacer esto ya sea rastreando la posición tal como la ve su ListView
, o manteniendo el ID
de la pista que se está reproduciendo actualmente (esto, por supuesto, solo funcionará si su modelo usa ID).
Algo como esto:
// Define `setActiveAtPosition(int position)` and `setInactive()`
// in your custom SeekBar
if (Globals.isPlaying && Globals.pos == position) {
// Define `setActiveAtPosition(int position)` in your custom SeekBar
holder.seekbar.setActiveAtPosition(Globals.mp.getCurrentPosition());
holder.seekbar.setVisibility(View.VISIBLE);
} else {
holder.seekbar.setInactiveForNow();
holder.seekbar.setVisibility(View.GONE);
}
Código solicitado:
Implementación de clase Seekbar personalizada:
public class SelfUpdatingSeekbar extends SeekBar implements SeekBar.OnSeekBarChangeListener {
private boolean mActive = false;
private Runnable mUpdateTimeProgressBar = new Runnable() {
@Override
public void run() {
if (Globals.isPlaying) {
setProgress(Globals.mp.getCurrentPosition());
postDelayed(this, 100L);
}
}
};
public SelfUpdatingSeekbar(Context context, AttributeSet attrs) {
super(context, attrs);
setOnSeekBarChangeListener(this);
}
public void setActive() {
if (!mActive) {
mActive = true;
removeCallbacks(mUpdateTimeProgressBar);
setProgress(Globals.mp.getCurrentPosition());
setVisibility(View.VISIBLE);
postDelayed(mUpdateTimeProgressBar, 100L);
}
}
public void setInactive() {
if (mActive) {
mActive = false;
removeCallbacks(mUpdateTimeProgressBar);
setVisibility(View.INVISIBLE);
}
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
removeCallbacks(mUpdateTimeProgressBar);
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
removeCallbacks(mUpdateTimeProgressBar);
Globals.mp.seekTo(getProgress());
postDelayed(mUpdateTimeProgressBar, 500);
}
}
En getView(...)
su adaptador:
if (Globals.isPlaying && Globals.pos == position) {
holder.seekbar.setActive();
} else {
holder.seekbar.setInactive();
}
No hace falta decir que necesitará usar esta implementación personalizada en su diseño xml:
<com.your.package.SelfUpdatingSeekbar
....
.... />
Tengo un problema extraño. Tengo un ListView
personalizado con BaseAdapter
. En mi diseño de fila de ListView
, tengo pocos TextView
s, Buttons
y SeekBar
. Todo funciona muy bien, no hay problemas con nada excepto con el reciclaje.
Qué sucede: todos los SeekBar
están ocultos, excepto uno que está visible. SeekBar
es visible cuando se SeekBar
MediaPlayer
en la fila. Esa parte está funcionando bien también.
Pero, cuando el usuario se desplaza hacia arriba o hacia abajo, y la fila con SeekBar
visible está fuera de la vista, se recicla, y SeekBar
se recicla y se actualiza incluso si no está visible y esa fila no se está reproduciendo (mp). Y cuando los usuarios se desplazan hacia atrás para regresar a la vista que se está reproduciendo, SeekBar
está visible, pero no se actualiza y su posición es 0. En lugar de eso, se está actualizando SeekBar
azar, pero no está visible (lo hice cuando todos los SeekBar
están visibles Sé que eso sucede)
Por supuesto que podría haber hecho la solución más idiota e inhabilitar el reciclaje de ListView, pero esto hace que la experiencia del usuario sea realmente mala y podría hacer que la aplicación se quede sin memoria, y el uso de LargeHeap
es lamentable. Entonces los siguientes métodos están fuera de cuestión.
@Override
public int getViewTypeCount() {
return getCount();
}
@Override
public int getItemViewType(int position) {
return position;
}
Mi pregunta: ¿hay alguna solución obvia para esto? ¿Cómo evito que una sola fila sea reciclada? No publicaré el código hasta que sea realmente necesario, el código es demasiado grande. En su lugar, solo publicaré partes importantes relacionadas con el problema:
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
View row = convertView;
holder = null;
if (row == null) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
row = inflater.inflate(R.layout.item, parent, false);
holder = new Ids(row);
row.setTag(holder);
} else {
holder = (Ids) row.getTag();
}
rowItemClass = (ListViewRow) getItem(position);
if (Globals.isPlaying && Globals.pos == position) {
holder.seekbar.setVisibility(View.VISIBLE);
} else {
holder.seekbar.setVisibility(View.GONE);
}
holder.seekbar.setTag(position);
final Ids finalHolder = holder;
...
OnClickListener{....
Globals.mp.start();
finalHolder.seekbar.setProgress(0);
finalHolder.seekbar.setMax(Globals.mp.getDuration());
..
updateTimeProgressBar = new Runnable() {
@Override
public void run() {
if (Globals.isPlaying) {
finalHolder.seekbar.setProgress(Globals.mp.getCurrentPosition());
int currentPosition = Globals.mp.getCurrentPosition();
handler.postDelayed(this, 100);
}
}
};
handler.postDelayed(updateTimeProgressBar, 100);
finalHolder.seekbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
handler.removeCallbacks(updateTimeProgressBar);
Globals.mp.seekTo(finalHolder.seekbar.getProgress());
int currentPosition = Globals.mp.getCurrentPosition();
handler.postDelayed(updateTimeProgressBar, 500);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
handler.removeCallbacks(updateTimeProgressBar);
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
// Intentionally left empty
}
});
}
y eso es. ¿Por qué está pasando esto? ¿Hay alguna manera de desactivar el reciclaje por una fila? ¿Sería una mala idea actualizar todas las SeekBar
en ListView
ya que solo se reproducirá 1 mp? ¿Qué tan malo es eso para el rendimiento?