Android NumberPicker внутри listView перестает прокручиваться при изменении набора данных

В моем приложении у меня есть listView с пользовательским макетом и пользовательским адаптером. Макет содержит textView и NumberPicker. Я хочу, чтобы numberPicker управлял значением моих данных, поэтому я хочу добавить к нему setOnValueChangedListener. Без прослушивателя это работает нормально - когда я прокручиваю numberPicker, прокручивают числа, и когда я прокручиваю вне его, он прокручивает представление списка, как показано в gif:

NumberPicker прокрутка в порядке

Однако, когда я присоединяю setOnValueChangedListener к NumberPicker, вещи ведут себя странно; При прокрутке через NumberPicker он застревает и вместо этого вызывает прокрутку самого макета:

NumberPicker странно прокручивается

(В gif я прокручиваю только numberPickers, однако он прокручивает listView и прекращает прокручивать numberPicker после изменения значения.)

После дальнейшего изучения выясняется, что именно notifyDataSetChanged() является причиной его возникновения, и отключение делает все нормально.

Что я думаю, так это то, что когда я прокручиваю numberPicker, слушатель запускает каждое измененное значение. Таким образом, после одного приращения он запускает и вызывает notifyDataSetChanged(), который каким-то образом сбрасывает представления и заставляет прокрутку останавливаться и переноситься в listView.

Вот весь соответствующий код:

Приложение (методы не имеют отношения к делу и используются, когда нажата одна из кнопок и создается диалоговое окно):

package com.chdev.mypianopractice;

import android.app.DialogFragment;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;

import java.util.ArrayList;

public class EditPracticeActivity extends AppCompatActivity implements ChoosePracticeStageDialogFragment.PracticeStageDialogListener {

    ArrayList<Practice.PracticeStage> practice;
    ListView listView;
    EditPracticeListViewAdapter adapter;

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

        findViewById(R.id.practiceNameEditText).clearFocus();

        practice = new ArrayList<>();

        listView = findViewById(R.id.editPracticeListView);
        listView.setAdapter(new EditPracticeListViewAdapter(this, practice));
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                ((EditPracticeListViewAdapter) parent.getAdapter()).setClickedPosition(position);
            }
        });

        adapter = (EditPracticeListViewAdapter) listView.getAdapter();
    }

    // Creates a dialog in order to add a new stage.
    public void addStage(View view) {
        DialogFragment fragment = new ChoosePracticeStageDialogFragment();
        fragment.show(getFragmentManager(), "chooseStage");
    }

    // Used by the dialog when adding new stages to the practice.
    @Override
    public void onDialogOK(Practice.PracticeType typeChosen) {
        String name = (typeChosen == null) ? "NULL" : getString(typeChosen.id);
        if (typeChosen != null) {
            practice.add(new Practice.PracticeStage(typeChosen, 30));
            adapter.notifyDataSetChanged();
        }
        System.out.println("The chosen activity: " + name);
    }
}

Пользовательский адаптер:

package com.chdev.mypianopractice;

import android.content.Context;
import android.graphics.Color;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.NumberPicker;
import android.widget.TextView;

import java.util.ArrayList;

/**
 * The adapter for the listView in EditPracticeActivity, using the custom layout.
 */

public class EditPracticeListViewAdapter extends ArrayAdapter<Practice.PracticeStage> {

    // Used for selecting items.
    private int lastClickedStage;

    public EditPracticeListViewAdapter(@NonNull Context context, ArrayList<Practice.PracticeStage> stages) {
        super(context, R.layout.practice_stage_row, stages);
        lastClickedStage = 0;
    }

    @NonNull
    @Override
    public View getView(final int position, @Nullable View convertView, @NonNull ViewGroup parent) {
        View rowView = convertView;
        if (rowView == null) {
            LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            rowView = inflater.inflate(R.layout.practice_stage_row, parent, false);
        }
        Practice.PracticeStage stage = getItem(position);

        TextView text = rowView.findViewById(R.id.practiceStageNameTextView);
        text.setText(stage.type.id);

        NumberPicker picker = rowView.findViewById(R.id.practiceStageNumberPicker);
        picker.setMinValue(0);
        picker.setMaxValue(60*60);
        picker.setValue(stage.time);

        picker.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
            @Override
            public void onValueChange(NumberPicker numberPicker, int oldVal, int newVal) {
                getItem(position).time = newVal;
                notifyDataSetChanged();
            }
        });

        rowView.setBackgroundColor(position == lastClickedStage ? Color.LTGRAY : Color.WHITE);

        return rowView;
    }

    // Used for selecting items.
    public void setClickedPosition(int position) {
        lastClickedStage = position;
        notifyDataSetChanged();
    }
}

Макет деятельности:

    <TextView
        android:id="@+id/textView4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="8dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="32dp"
        android:text="@string/edit_practice_title"
        android:textAlignment="center"
        android:textSize="36sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <EditText
        android:id="@+id/practiceNameEditText"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginEnd="8dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:ems="10"
        android:inputType="textPersonName"
        android:text="@string/new_practice_default_text"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView4" />

    <ListView
        android:id="@+id/editPracticeListView"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_marginBottom="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        app:layout_constraintBottom_toTopOf="@+id/button3"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/practiceNameEditText" />

    <Button
        android:id="@+id/button3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="24dp"
        android:layout_marginStart="32dp"
        android:onClick="addStage"
        android:text="@string/add_practice_stage_edit"
        app:layout_constraintBottom_toTopOf="@+id/button5"
        app:layout_constraintEnd_toStartOf="@+id/button4"
        app:layout_constraintStart_toStartOf="parent" />

    <Button
        android:id="@+id/button4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="32dp"
        android:text="@string/remove_practice_stage_edit"
        app:layout_constraintBaseline_toBaselineOf="@+id/button3"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/button3" />

    <Button
        android:id="@+id/button5"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="8dp"
        android:layout_marginStart="24dp"
        android:text="@string/save_practice_edit"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent" />

    <Button
        android:id="@+id/button10"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="24dp"
        android:text="@string/quit_practice_edit"
        app:layout_constraintBaseline_toBaselineOf="@+id/button5"
        app:layout_constraintEnd_toEndOf="parent" />
</android.support.constraint.ConstraintLayout>

Пользовательский макет, используемый в listView:

    <TextView
        android:id="@+id/practiceStageNameTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="8dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:textSize="24sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <NumberPicker
        android:id="@+id/practiceStageNumberPicker"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginTop="8dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>

Извините, это немного длинно. Буду очень признателен за вашу помощь, заранее спасибо!

0 ответов

Другие вопросы по тегам