studio recyclerview que para item ejemplo bottom android android-scrollview android-recyclerview

android - que - Recyclerview Cambio de elementos durante el desplazamiento



recyclerview scroll to position (11)

Tengo un RecyclerView. Cada fila tiene un botón de reproducción, vista de texto y barra de progreso. cuando hago clic en el botón de reproducción tengo que reproducir audio desde mi tarjeta SD y tengo que avanzar Barra de progreso El problema es que cuando me desplazo hacia abajo en la vista de reciclador, cambio la barra de progreso en la fila siguiente. Significa que puedo colocar 5 elementos en la pantalla a la vez. Cuando me desplazo a la sexta, sexta fila la barra de búsqueda cambia de repente.

public class ListAdapter extends RecyclerView.Adapter { private List<Historyitem> stethitems; public Context mContext; public Activity activity; public Handler mHandler; static MediaPlayer mPlayer; static Timer mTimer; public ListAdapter(Activity activity,Context mContext,List<Historyitem> stethitems) { this.stethitems = stethitems; this.mContext = mContext; this.activity = activity; } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) { View rootView = LayoutInflater. from(mContext).inflate(R.layout.stethoscopeadapteritem, null, false); RecyclerView.LayoutParams lp = new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); rootView.setLayoutParams(lp); mHandler = new Handler(); return new MyViewHolder(rootView); } @Override public void onBindViewHolder(final RecyclerView.ViewHolder viewHolder, int position) { final Historyitem dataItem = stethitems.get(position); final MyViewHolder myViewHolder = (MyViewHolder) viewHolder; myViewHolder.progressplay.setProgress(0); myViewHolder.stethdatetime.setText(dataItem.getReported_Time()); myViewHolder.stethhosname.setText(dataItem.getdiv()); if(dataItem.getPatient_Attribute().replaceAll(" ","").equals("")){ myViewHolder.stethdoctorname.setText(dataItem.getunit()); } else { myViewHolder.stethdoctorname.setText(dataItem.getPatient_Attribute()); } myViewHolder.stethstreamplay.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { FileDownload(dataItem.getmsg(), myViewHolder.progressplay); } }); } @Override public int getItemCount() { return stethitems.size(); } public class MyViewHolder extends RecyclerView.ViewHolder { final CustomTextRegular stethdatetime; final CustomTextView stethhosname; final CustomTextBold stethdoctorname; final ImageButton stethstreamplay; final NumberProgressBar progressplay; public MyViewHolder(View itemView) { super(itemView); stethdatetime = (CustomTextRegular) itemView.findViewById(R.id.stethdatetime); stethhosname = (CustomTextView) itemView.findViewById(R.id.stethhosname); stethdoctorname = (CustomTextBold) itemView.findViewById(R.id.stethdoctorname); stethstreamplay = (ImageButton) itemView.findViewById(R.id.stethstreamplay); progressplay= (NumberProgressBar) itemView.findViewById(R.id.progressplay); } } public void FileDownload(final String downloadpath, final NumberProgressBar progressplay) { new AsyncTask<NumberProgressBar, Integer, NumberProgressBar>() { NumberProgressBar progress; @Override protected void onPreExecute() { super.onPreExecute(); try { if(mPlayer!=null){ mPlayer.stop(); } }catch (Exception e){ } try { if(mTimer != null){ mTimer.purge(); mTimer.cancel(); } }catch (Exception e){ } } @Override protected NumberProgressBar doInBackground(NumberProgressBar... params) { int count; progress = progressplay; try { final List<NameValuePair> list = new ArrayList<NameValuePair>(); list.add(new BasicNameValuePair("pid",id)); URL url = new URL(Config.requestfiledownload + "?path=" + downloadpath); URLConnection connection = url.openConnection(); connection.connect(); int lenghtOfFile = connection.getContentLength(); // download the file InputStream input = new BufferedInputStream(url.openStream()); OutputStream output = new FileOutputStream(Environment.getExternalStorageDirectory() + "record.wav"); byte data[] = new byte[1024]; long total = 0; while ((count = input.read(data)) != -1) { total += count; // publishing the progress.... publishProgress((int) (total * 100 / lenghtOfFile)); output.write(data, 0, count); } output.flush(); output.close(); input.close(); } catch (Exception e) { } return progress; } @Override protected void onPostExecute(final NumberProgressBar numberProgressBar) { super.onPostExecute(numberProgressBar); try { StartMediaPlayer(numberProgressBar); } catch (Exception e){ e.printStackTrace(); } } }.execute(); } public void StartMediaPlayer(final NumberProgressBar progressbar){ Uri playuri = Uri.parse("file:///sdcard/record.wav"); mPlayer = new MediaPlayer(); mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); mPlayer.reset(); try { mPlayer.setDataSource(mContext, playuri); } catch (IllegalArgumentException e) { } catch (SecurityException e) { } catch (IllegalStateException e) { } catch (Exception e) { } try { mPlayer.prepare(); } catch (Exception e) { } mPlayer.start(); progressbar.setMax(mPlayer.getDuration()); mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { @Override public void onCompletion(MediaPlayer mp) { if(mPlayer!=null) { mPlayer.release(); progressbar.setProgress(0); } if(mTimer != null){ mTimer.purge(); mTimer.cancel(); } } }); mTimer = new Timer(); mTimer.schedule(new TimerTask() { @Override public void run() { mHandler.post(new Runnable() { @Override public void run() { progressbar.setProgress(mPlayer.getCurrentPosition()); } }); } },0,500); }}


¿Por qué no intentas así?

HashMap<String, Integer> progressHashMap = new HashMap<>(); //... if(!progressHashMap.containsKey(downloadpath)){ progressHashMap.put(downloadpath, mPlayer.getCurrentPosition()); } progressbar.setProgress(progressHashMap.get(downloadpath));


Añadir setHasStableIds(true); en el constructor de su adaptador y anule estos dos métodos en el adaptador.

@Override public long getItemId(int position) { return position; } @Override public int getItemViewType(int position) { return position; }


Como su nombre lo indica, las vistas en un RecyclerView se reciclan a medida que se desplaza hacia abajo. Esto significa que debe mantener el estado de cada elemento en su modelo de respaldo, que en este caso sería un elemento de Historyitem , y restaurarlo en su onBindViewHolder .

1) Cree la posición, el máximo y cualquier otra variable que necesite para guardar el estado de ProgressBar en su modelo.

2) Establezca el estado de su ProgressBar función de los datos en su modelo de respaldo; al hacer clic, pase la posición del elemento a sus métodos FileDownload / StartMediaPlayer .

public void onBindViewHolder(final RecyclerView.ViewHolder viewHolder, int position) { final Historyitem dataItem = stethitems.get(position); final MyViewHolder myViewHolder = (MyViewHolder) viewHolder; myViewHolder.progressplay.setMax(dataItem.getMax()); myViewHolder.progressplay.setProgress(dataItem.getPosition()); ... myViewHolder.stethstreamplay.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { FileDownload(dataItem.getmsg(), position); } });

3) Actualice la barra de progreso actualizando el modelo de respaldo y notificando que se modificó.

stethitems.get(position).setPosition(mPlayer.getCurrentPosition()); notifyItemChanged(position);


Esta línea cambia el progreso a 0 en cada enlace

myViewHolder.progressplay.setProgress(0);

Guarde su estado en algún lugar y luego cárguelo en esta misma línea.


Este es el comportamiento esperado de recyclerView. Dado que la vista se recicla, sus artículos pueden tener vistas aleatorias. Para superar esto, debe especificar qué elemento se coloca en qué tipo de vista usted mismo. Esta información se puede guardar en un SparseBooleanArray. lo que puedes hacer es crear un SparseBooleanArray en tu adaptador de esta manera

SparseBooleanArray selectedItems = new SparseBooleanArray();

cada vez que cambie su vista, haga:

selectedItems.put(viewItemIndex,true);

Ahora en tu onBindViewHolder hacer

if(selectedItems.get(position, false)){ //set progress bar of related to the view to desired position } else { //do the default }

Esto es lo básico para resolver su problema. Puede ajustar esta lógica a cualquier tipo de problema similar en recyclerView.


Me enfrenté al mismo problema mientras intentaba implementar una vista de reciclador que contiene un edittex y una casilla de verificación como elementos de fila. Resolví el problema de cambio de valor de desplazamiento simplemente agregando las siguientes dos líneas en la clase de adaptador.

@Override public long getItemId(int position) { return position; } @Override public int getItemViewType(int position) { return position; }

Espero que sea una posible solución. Gracias


Ponga recylerView en una NestedScroll View en su XML y agregue la propiedad nestedScrollingEnabled = false .

Y en su adaptador onBindViewHolder agregue esta línea

final MyViewHolder viewHolder = (MyViewHolder)holder;

Use este objeto viewHolder con sus vistas para establecer setText o haga cualquier tipo de evento de clic.

por ejemplo, viewHolder.txtSubject.setText("Example");


Por favor intente esto

  1. Si está utilizando ListView , anule los siguientes métodos.

    @Override public int getViewTypeCount() { return getCount(); } @Override public int getItemViewType(int position) { return position; }

  2. Si está utilizando RecycyclerView , anule solo el método getItemViewType() .

    @Override public int getItemViewType(int position) { return position; }


Tuve el mismo problema mientras manejaba una gran cantidad de datos, funciona con 5 porque representa los cinco elementos que son visibles en la pantalla, pero eso da problemas con más elementos. La cosa es ..

A veces, RecyclerView y listView simplemente omiten los datos de relleno. En caso de que la función de enlace RecyclerView se omita durante el desplazamiento, pero cuando intente depurar el adaptador recyclerView funcionará bien, ya que llamará a onBind cada vez, también puede ver la vista oficial del desarrollador de Google The World of listView . Alrededor de 20 min -30 min explicarán que nunca se puede suponer que se llamará a getView por posición cada vez.

entonces, sugeriré usar

RecyclerView DataBinder creado por satorufujiwara.

o

RecyclerView MultipleViewTypes Binder creado por yqritc.

Estos son otros Binders disponibles si los encuentra fáciles de solucionar.

Esta es la forma de lidiar con los tipos de vistas múltiples o si está utilizando una gran cantidad de datos. Estos aglutinantes pueden ayudarlo a leer la documentación cuidadosamente para solucionarlo, ¡paz!


Tuve el problema similar y busqué mucho la respuesta correcta. Básicamente, es más un diseño de vista de reciclador que actualiza la vista en el desplazamiento porque actualiza la vista.

Entonces, todo lo que necesita hacer es, en el momento de vinculación, decirle que no lo actualice.

Así es como debería verse su onBindViewHolder

@Override @SuppressWarnings("unchecked") public void onBindViewHolder(final BaseViewHolder holder, final int position) { holder.bind(mList.get(position)); // This is the mighty fix of the issue i was having // where recycler view was updating the items on scroll. holder.setIsRecyclable(false); }


prueba esto

@Override public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) { LinearSmoothScroller linearSmoothScroller = new LinearSmoothScroller(recyclerView.getContext()) { @Override public PointF computeScrollVectorForPosition(int targetPosition) { return LinearLayoutManager.this .computeScrollVectorForPosition(targetPosition); } }; linearSmoothScroller.setTargetPosition(position); startSmoothScroll(linearSmoothScroller); }

mira esto también