嗨,我是 android dev 的新手,对 viewpager2 中按钮 onclick 的实现有疑问
Hi, im new in android dev and have questions about implementation of button onclick in viewpager2
在我的应用程序中,我使用了 viewpager2,用户可以在其中通过点击按钮 yes/no 滑动并回答问题,类似于测验。我试图设置按钮 onclicklistener,点击时当前页面上的按钮应该改变颜色(是=绿色,否=红色)。问题是当我点击按钮时,有时它会改变颜色,有时不会。如果不是,即使尚未单击,后页中的按钮也会受到影响。如何确保只有当前页面中的按钮在单击时会改变颜色?按钮 onclick 的实现在我的代码中是错误的还是什么?我检查了 logcat,没有显示错误。
这是我的 MyViewPagerAdapter.java
public class MyViewPagerAdapter extends RecyclerView.Adapter<MyViewPagerAdapter.MyViewHolder> {
Context context;
int[][] question_matrix = new int[][]{
//Visual motor
{R.string.q1,R.string.q1m},
{R.string.q2,R.string.q2m},
//Fine motor
{R.string.q3,R.string.q3m},
{R.string.q4,R.string.q4m},
{R.string.q5,R.string.q5m},
{R.string.q6,R.string.q6m},
//body posture
{R.string.q7,R.string.q7m},
{R.string.q8,R.string.q8m},
{R.string.q9,R.string.q9m},
//shoulder stability
{R.string.q10,R.string.q10m},
{R.string.q11,R.string.q11m},
{R.string.q12,R.string.q12m},
{R.string.q13,R.string.q13m},
//spatial perception
{R.string.q14,R.string.q14m},
{R.string.q15,R.string.q15m},
//cross mid-line
{R.string.q16,R.string.q16m},
{R.string.q16,R.string.q16m},
{R.string.q16,R.string.q16m},
{R.string.q16,R.string.q16m},
{R.string.q16,R.string.q16m},
{R.string.q16,R.string.q16m},
{R.string.q16,R.string.q16m},
{R.string.q16,R.string.q16m},
{R.string.q16,R.string.q16m},
{R.string.q16,R.string.q16m},
{R.string.q16,R.string.q16m},
{R.string.q16,R.string.q16m},
{R.string.q16,R.string.q16m},
{R.string.q16,R.string.q16m},
{R.string.q16,R.string.q16m},
{R.string.q16,R.string.q16m},
{R.string.q16,R.string.q16m},
{R.string.q16,R.string.q16m},
{R.string.q16,R.string.q16m},
{R.string.q16,R.string.q16m},
{R.string.q16,R.string.q16m},
{R.string.q16,R.string.q16m},
{R.string.q16,R.string.q16m},
{R.string.q16,R.string.q16m},
{R.string.q16,R.string.q16m},
{R.string.q16,R.string.q16m},
{R.string.q17,R.string.q17m},
{R.string.q18,R.string.q18m},
//visual skill
{R.string.q19,R.string.q19m},
{R.string.q20,R.string.q20m},
};
public MyViewPagerAdapter(Context context) {
this.context = context;
}
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new MyViewHolder(LayoutInflater.from(context).inflate(R.layout.item_page,parent,false));
}
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
holder.eQuestion.setText(question_matrix[position][0]);
holder.mQuestion.setText(question_matrix[position][1]);
holder.yes.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
holder.yes.setBackgroundColor(Color.GREEN);
holder.no.setBackgroundColor(Color.LTGRAY);
}
});
holder.no.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
holder.yes.setBackgroundColor(Color.LTGRAY);
holder.no.setBackgroundColor(Color.RED);
}
});
}
@Override
public int getItemCount() {
return question_matrix.length;
}
public class MyViewHolder extends RecyclerView.ViewHolder {
TextView eQuestion,mQuestion;
ConstraintLayout container;
Button yes,no;
ImageView img;
public MyViewHolder(@NonNull View itemView) {
super(itemView);
img = itemView.findViewById(R.id.image_desc);
eQuestion = itemView.findViewById(R.id.eQuestion);
mQuestion = itemView.findViewById(R.id.mQuestion);
container = itemView.findViewById(R.id.container);
yes = itemView.findViewById(R.id.yesBtn);
no = itemView.findViewById(R.id.noBtn);
}
}
}
这是我的 item_page.xml 布局:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/image_desc"
android:layout_width="300dp"
android:layout_height="200dp"
android:layout_centerHorizontal="true"
android:src="@drawable/ic_q1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.495"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.152" />
<TextView
android:id="@+id/eQuestion"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/image_desc"
android:layout_gravity="center"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:text="question"
android:textAlignment="center"
android:textColor="@color/black"
android:textSize="18sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/image_desc"
app:layout_constraintVertical_bias="0.108" />
<TextView
android:id="@+id/mQuestion"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/eQuestion"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:text="translation"
android:textAlignment="center"
android:textColor="#3A3939"
android:textSize="15sp"
android:textStyle="italic"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/eQuestion"
app:layout_constraintVertical_bias="0.061" />
<Button
android:id="@+id/noBtn"
android:layout_width="170dp"
android:layout_height="47dp"
android:layout_marginStart="16dp"
android:text="No"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.004"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/mQuestion"
app:layout_constraintVertical_bias="0.69" />
<Button
android:id="@+id/yesBtn"
android:layout_width="170dp"
android:layout_height="47dp"
android:layout_marginEnd="16dp"
android:text="Yes"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/mQuestion"
app:layout_constraintVertical_bias="0.69" />
</androidx.constraintlayout.widget.ConstraintLayout>
How to make sure only the button in current page will change color when clicked
因为当您在下一页中更改按钮的颜色时 ViewPager2 会重复使用布局,所以按钮的颜色是您设置的最后一种颜色。因此,在 onBindViewHolder
中,您必须将按钮的颜色更改为默认颜色:
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
…
holder.yes.setBackgroundColor(Color.GREEN);
holder.yes.setBackgroundColor(Color.LTGRAY);
…
}
如果您只想在点击时更改点击按钮的颜色,您可以使用 StateListDrawable
作为背景
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:color="@color/yourPressedColor" />
<item android:color="@color/yourNormalColor" />
</selector>
所以我终于找到了答案。其实很容易。就像@mostafa3dmax 说的。我必须在 onBindViewHolder
中设置默认颜色。为了按钮颜色在换页后不重置,我只需要设置
viewPager2.setOffScreenPageLimit(int value)
如文档中所述:
Pages within limit pages away from the current page are created and
added to the view hierarchy, even though they are not visible on the
screen. Pages outside this limit will be removed from the view
hierarchy, but the ViewHolders will be recycled as usual by
RecyclerView.
在我的应用程序中,我使用了 viewpager2,用户可以在其中通过点击按钮 yes/no 滑动并回答问题,类似于测验。我试图设置按钮 onclicklistener,点击时当前页面上的按钮应该改变颜色(是=绿色,否=红色)。问题是当我点击按钮时,有时它会改变颜色,有时不会。如果不是,即使尚未单击,后页中的按钮也会受到影响。如何确保只有当前页面中的按钮在单击时会改变颜色?按钮 onclick 的实现在我的代码中是错误的还是什么?我检查了 logcat,没有显示错误。
这是我的 MyViewPagerAdapter.java
public class MyViewPagerAdapter extends RecyclerView.Adapter<MyViewPagerAdapter.MyViewHolder> {
Context context;
int[][] question_matrix = new int[][]{
//Visual motor
{R.string.q1,R.string.q1m},
{R.string.q2,R.string.q2m},
//Fine motor
{R.string.q3,R.string.q3m},
{R.string.q4,R.string.q4m},
{R.string.q5,R.string.q5m},
{R.string.q6,R.string.q6m},
//body posture
{R.string.q7,R.string.q7m},
{R.string.q8,R.string.q8m},
{R.string.q9,R.string.q9m},
//shoulder stability
{R.string.q10,R.string.q10m},
{R.string.q11,R.string.q11m},
{R.string.q12,R.string.q12m},
{R.string.q13,R.string.q13m},
//spatial perception
{R.string.q14,R.string.q14m},
{R.string.q15,R.string.q15m},
//cross mid-line
{R.string.q16,R.string.q16m},
{R.string.q16,R.string.q16m},
{R.string.q16,R.string.q16m},
{R.string.q16,R.string.q16m},
{R.string.q16,R.string.q16m},
{R.string.q16,R.string.q16m},
{R.string.q16,R.string.q16m},
{R.string.q16,R.string.q16m},
{R.string.q16,R.string.q16m},
{R.string.q16,R.string.q16m},
{R.string.q16,R.string.q16m},
{R.string.q16,R.string.q16m},
{R.string.q16,R.string.q16m},
{R.string.q16,R.string.q16m},
{R.string.q16,R.string.q16m},
{R.string.q16,R.string.q16m},
{R.string.q16,R.string.q16m},
{R.string.q16,R.string.q16m},
{R.string.q16,R.string.q16m},
{R.string.q16,R.string.q16m},
{R.string.q16,R.string.q16m},
{R.string.q16,R.string.q16m},
{R.string.q16,R.string.q16m},
{R.string.q16,R.string.q16m},
{R.string.q16,R.string.q16m},
{R.string.q16,R.string.q16m},
{R.string.q17,R.string.q17m},
{R.string.q18,R.string.q18m},
//visual skill
{R.string.q19,R.string.q19m},
{R.string.q20,R.string.q20m},
};
public MyViewPagerAdapter(Context context) {
this.context = context;
}
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new MyViewHolder(LayoutInflater.from(context).inflate(R.layout.item_page,parent,false));
}
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
holder.eQuestion.setText(question_matrix[position][0]);
holder.mQuestion.setText(question_matrix[position][1]);
holder.yes.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
holder.yes.setBackgroundColor(Color.GREEN);
holder.no.setBackgroundColor(Color.LTGRAY);
}
});
holder.no.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
holder.yes.setBackgroundColor(Color.LTGRAY);
holder.no.setBackgroundColor(Color.RED);
}
});
}
@Override
public int getItemCount() {
return question_matrix.length;
}
public class MyViewHolder extends RecyclerView.ViewHolder {
TextView eQuestion,mQuestion;
ConstraintLayout container;
Button yes,no;
ImageView img;
public MyViewHolder(@NonNull View itemView) {
super(itemView);
img = itemView.findViewById(R.id.image_desc);
eQuestion = itemView.findViewById(R.id.eQuestion);
mQuestion = itemView.findViewById(R.id.mQuestion);
container = itemView.findViewById(R.id.container);
yes = itemView.findViewById(R.id.yesBtn);
no = itemView.findViewById(R.id.noBtn);
}
}
}
这是我的 item_page.xml 布局:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/image_desc"
android:layout_width="300dp"
android:layout_height="200dp"
android:layout_centerHorizontal="true"
android:src="@drawable/ic_q1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.495"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.152" />
<TextView
android:id="@+id/eQuestion"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/image_desc"
android:layout_gravity="center"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:text="question"
android:textAlignment="center"
android:textColor="@color/black"
android:textSize="18sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/image_desc"
app:layout_constraintVertical_bias="0.108" />
<TextView
android:id="@+id/mQuestion"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/eQuestion"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:text="translation"
android:textAlignment="center"
android:textColor="#3A3939"
android:textSize="15sp"
android:textStyle="italic"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/eQuestion"
app:layout_constraintVertical_bias="0.061" />
<Button
android:id="@+id/noBtn"
android:layout_width="170dp"
android:layout_height="47dp"
android:layout_marginStart="16dp"
android:text="No"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.004"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/mQuestion"
app:layout_constraintVertical_bias="0.69" />
<Button
android:id="@+id/yesBtn"
android:layout_width="170dp"
android:layout_height="47dp"
android:layout_marginEnd="16dp"
android:text="Yes"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/mQuestion"
app:layout_constraintVertical_bias="0.69" />
</androidx.constraintlayout.widget.ConstraintLayout>
How to make sure only the button in current page will change color when clicked
因为当您在下一页中更改按钮的颜色时 ViewPager2 会重复使用布局,所以按钮的颜色是您设置的最后一种颜色。因此,在 onBindViewHolder
中,您必须将按钮的颜色更改为默认颜色:
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
…
holder.yes.setBackgroundColor(Color.GREEN);
holder.yes.setBackgroundColor(Color.LTGRAY);
…
}
如果您只想在点击时更改点击按钮的颜色,您可以使用 StateListDrawable
作为背景
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:color="@color/yourPressedColor" />
<item android:color="@color/yourNormalColor" />
</selector>
所以我终于找到了答案。其实很容易。就像@mostafa3dmax 说的。我必须在 onBindViewHolder
中设置默认颜色。为了按钮颜色在换页后不重置,我只需要设置
viewPager2.setOffScreenPageLimit(int value)
如文档中所述:
Pages within limit pages away from the current page are created and added to the view hierarchy, even though they are not visible on the screen. Pages outside this limit will be removed from the view hierarchy, but the ViewHolders will be recycled as usual by RecyclerView.