Recyclerview Зміна елементів під час прокрутки


80

У мене є RecyclerView. Кожен рядок має кнопку відтворення, перегляд тексту та панель виконання. при натисканні на кнопку відтворення доводиться відтворювати аудіо з моєї sdcard і рухатись на панелі прогресу. Проблема полягає в тому, що я прокручую вниз вказівник перегляду, змінюючи панель прогресу в наступному рядку. означає, що я можу помістити 5 елементів на екран одночасно. Коли я прокручую до 6-го, 6-го рядка панель пошуку раптово змінюється.

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

Оскільки Моя відповідь допомагає багатьом людям, будь ласка, прийміть мою відповідь. Дякую
Сурендар Д

Відповіді:


238

Будь ласка, спробуйте це

  1. Якщо ви використовуєте ListView- перевизначте наведені нижче способи.

     @Override
     public int getViewTypeCount() {    
         return getCount();
     }
    
     @Override
     public int getItemViewType(int position) {    
         return position;
     }
    
  2. Якщо ви використовуєте RecyclerView- замінити лише getItemViewType()метод.

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

6
чудове рішення .. врятував мій день
Däñish Shärmà

1
найкраща відповідь брат. дійсно допомагає
Nitheesh KP

2
OMG це працює ідеально. :) Цю відповідь потрібно прийняти
Ajay Shrestha

4
Чому getItemViewTypeповертається position?? Цікаво про цю відповідь.
Jimit Patel

10
Такий підхід може вплинути на продуктивність, особливо при наявності великого списку елементів: Великою перевагою RecyclerView є те, що він повторно використовує екземпляри ViewHolder та відповідну ієрархію подання. Отже, коли прокрутки користувача та нові елементи стають видимими, замість того, щоб створювати нові подання, попередні ViewHolders, які більше не видно, переробляються та прив'язуються до нових видимих ​​елементів. Але повертаючи позицію як тип, RecyclerView оброблятиме кожен ViewHolder як неможливий для нового елемента, оскільки він має інший тип. Отже, "функція утилізації" RecyclerView в основному відключається, роблячи це
pakat

60

Додайте setHasStableIds(true);конструктор адаптера та перевизначте ці два методи в адаптері. Це також спрацювало, якщо хтось використовував RecyclerViewусередині a, ViewPagerякий також знаходиться всередині a NestedScrollView.

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

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

1
Це найкраща відповідь для мене та мого RecyclerView. Перевизначення лише "getItemViewType" видаляє деяку випадковість для мого recyclerView (лише при прокрутці вниз, переміщенні вгору по позиціях, але не працює назад). Реалізація також перевизначення "getItemId" та "setHasStableIds (true)" відмінно виконує цю роботу, як прокручуючи вниз, так і прокручуючи вгору.
Алессандро Юдіконе,

8
Але проблема присутня, коли у мене getItemViewType повертає різні види viewType, а не лише звичайну позицію. Хтось знає, як гаряче це вирішити?
RadoVidjen

Дякую, Айв цілий день боровся з подібною проблемою завдяки введенню тексту, яке могло випадково змінювати значення. Ти - рятівник.
Джефф

я завжди сюди повертаюся
Acauã Pitta

29

Як випливає з назви, подання у вікні RecyclerViewпереробляються під час прокрутки вниз. Це означає, що вам потрібно зберегти стан кожного елемента у вашій моделі підтримки, яка в цьому випадку буде a Historyitem, і відновити його у вашій onBindViewHolder.

1) Створіть позицію, max та будь-які інші змінні, необхідні для збереження стану ProgressBarвашої моделі.

2) Встановіть стан вашого ProgressBarна основі даних вашої моделі підтримки; після натискання передайте позицію товару вашим 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) Оновіть індикатор виконання, оновивши модель підтримки і повідомивши про її зміну.

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

12

Я зіткнувся з тією ж проблемою, коли намагався реалізувати reciclerview, який містить edittex та прапорець як елементи рядка. Я вирішив проблему зміни значення прокрутки, просто додавши два наступних рядки в класі адаптера.

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

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

Сподіваюся, це буде можливим рішенням. Дякую



3

Покладіть recylerViewу NestedScroll Viewсвій XMLі додайте властивістьnestedScrollingEnabled = false .

А на адаптері onBindViewHolderдодайте цей рядок

final MyViewHolder viewHolder = (MyViewHolder)holder;

Використовуйте цей viewHolderоб'єкт для переглядуsetText будь-яких подій клацання.

напр viewHolder.txtSubject.setText("Example");


Помістіть recylerView у подання NestedScroll у своєму XML та додайте властивість nestedScrollingEnabled = false. дякую, це мені допомагає :)
Sachin Solanki

2

Коли ми RecyclerViewдинамічно міняємо елементи (тобто, коли змінюємо колір тла конкретного RecyclerViewелемента), це може змінити зовнішній вигляд елементів при прокрутці через характер того, якRecyclerView повторного використання його елементів.

Однак, щоб уникнути того, що можна використовувати android.support.v4.widget.NestedScrollViewобмотану навколо RecyclerViewта дозволяючи NestedScrollViewручці прокрутку.

<android.support.v4.widget.NestedScrollView
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <android.support.v7.widget.RecyclerView
            android:id="@+id/recycler_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>

   </LinearLayout>
</android.support.v4.widget.NestedScrollView>

А потім у коді ви можете відключити вкладену прокрутку, RecyclerViewщоб згладити прокрутку, дозволивши лише NestedScrollViewобробці прокрутки.

ViewCompat.setNestedScrollingEnabled(recyclerView, false);

1

Якщо ваш reciclerview ViewHolder має більше логіки або має інший вигляд, спробуйте:

 **order_recyclerView.setItemViewCacheSize(x);**

де x - розмір списку. Вищевказане працює для мене, сподіваюся, воно працює і для вас.


це спрацювало на мене, дякую
Sujeet Kumar

0

У мене була та сама проблема, коли я обробляв багато даних, він працює з 5, оскільки відображає п’ять елементів, які видно на екрані, але це дає проб з більшою кількістю елементів. Річ у тім ..

Іноді RecyclerView і listView просто пропускають заповнення даних. Якщо функція прив'язки RecyclerView пропущена під час прокрутки, але при спробі налагодити адаптер recyclerView він буде працювати нормально, оскільки буде кожного разу викликати функцію onBind, ви також можете побачити офіційний погляд розробника Google Світ listView . Близько 20 хв -30 хв вони пояснять, що ви ніколи не можете припустити, що getView за позицією буде викликатися щоразу.

отже, я запропоную використовувати

RecyclerView DataBinder, створений satorufujiwara.

або

RecyclerView MultipleViewTypes Binder, створений yqritc.

Це інші доступні підшивки, якщо вам зручно їх обійти.

Це спосіб мати справу з типами MultipleView або якщо ви використовуєте великий обсяг даних. Ці в'яжучі можуть допомогти вам просто уважно прочитати документацію, яка це виправить, мир!


0

Чому б вам не спробувати так,

    HashMap<String, Integer> progressHashMap = new HashMap<>();

    //...
    if(!progressHashMap.containsKey(downloadpath)){
        progressHashMap.put(downloadpath, mPlayer.getCurrentPosition());
    }

    progressbar.setProgress(progressHashMap.get(downloadpath));

0

спробуйте це

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

дивіться це також


0

Цей рядок змінює прогрес на 0 при кожному прив'язуванні

myViewHolder.progressplay.setProgress(0);

Збережіть його стан десь, а потім завантажте його в цей самий рядок.


0

Перевизначте метод getItemViewType в адаптері. у котліні використання

override fun getItemViewType(position: Int): Int {
    return position
}

-2

Це очікувана поведінка recyclerView. Оскільки подання переробляється, ваші предмети можуть потрапляти у випадкові перегляди. Щоб подолати це, вам слід вказати, який предмет ви самостійно переглядаєте. Цю інформацію можна зберігати в SparseBooleanArray. що ви можете зробити, це створити SparseBooleanArray у своєму адаптері, як це

SparseBooleanArray selectedItems = new SparseBooleanArray();

щоразу, коли ваш погляд змінюється, виконайте:

selectedItems.put(viewItemIndex,true);

Тепер у вашому onBindViewHolder зробіть

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

Це основне для вирішення вашої проблеми. Ви можете налаштувати цю логіку на будь-яку подібну проблему в recyclerView.


Як встановити viewItemIndex of view
Arya

Це пункт у вашому списку адаптерів. Ви можете отримати за допомогою getAdapterPostion або stethitems.get(position)як у вашому коді.
rockfight

І все-таки я стикаюся з тим самим питанням. коли я прокручую вниз reciclerview, змінюю індикатор виконання в наступному рядку.
Arya

Це не входження в іншу частину.
Arya

ах вибачте, змініть if(selectedItems.get(position, true))на if(selectedItems.get(position, false)). Я відредагую оригінальну відповідь.
rockfight

-2

У мене була подібна проблема і я багато шукав правильної відповіді. В основному це більше дизайн подання утилізатора, який оновлює вигляд на сувої, оскільки він освіжає вигляд.

Отже, все, що вам потрібно зробити, це під час прив’язки сказати йому не оновлювати його.

Ось як повинен виглядати ваш 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);
}

1
Це перемагає всю мету використання подання "RECYCLER"
Олексій
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.