在我的应用程序中,我有一个带自定义布局和自定义适配器的listView。布局包含一个textView和一个numberPicker。 我希望numberPicker控制我的数据值,所以我想向其中添加setOnValueChangedListener。没有监听器,它可以正常工作-当我滚动numberPicker时,数字滚动,而当我滚动到它外面时,它滚动列表视图,如gif所示:
但是,当我将setOnValueChangedListener附加到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>
很抱歉,这有点冗长。非常感谢您的帮助,在此先感谢!