Привет, я новичок в разработке Android, и у меня есть вопросы о реализации кнопки onclick в viewpager2

#java #android #android-viewpager2

#java #Android #android-viewpager2

Вопрос:

В моем приложении я использовал viewpager2, где пользователь может проводить пальцем и отвечать на вопросы, нажимая кнопку «Да / нет», похожие на викторины. Я попытался установить кнопку 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>

    
 

Ответ №1:

Как убедиться, что только кнопка на текущей странице будет менять цвет при нажатии

Поскольку ViewPager2 повторно использует макеты, когда вы меняете цвет кнопки на следующей странице, цвет кнопки — это последний установленный вами цвет. Итак, в onBindViewHolder вы должны изменить цвет кнопки на значение по умолчанию :

 @Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position)  {

    …
    holder.yes.setBackgroundColor(Color.GREEN);
    holder.yes.setBackgroundColor(Color.LTGRAY);
    
    …

}
 

Если вы просто хотите изменить цвет нажатой кнопки, когда она нажата, вы можете использовать a 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>
 

Комментарии:

1. если я установлю значение по умолчанию в onBindViewHolder, когда пользователь проведет пальцем назад к главной странице, оно вернется к значению по умолчанию. Я бы хотел, чтобы цвет кнопки оставался таким, какой он есть после нажатия. Как я могу это получить?

2. Я пытался установить цвет по умолчанию в onBindViewHolder и использовать stateRestorationPolicy , но это не работает. Цвет все равно изменится на стандартный, если перейти к предыдущей странице.

Ответ №2:

Так что, наконец, я нашел ответ. На самом деле это довольно просто. Как сказал @mostafa3dmax. Я должен установить цвет по умолчанию onBindViewHolder . Чтобы цвет кнопки не сбрасывался после смены страниц, мне просто нужно установить

ViewPager2.setOffscreenPageLimit(значение int)

Как указано в документации:

Страницы в пределах предельных страниц от текущей страницы создаются и добавляются в иерархию представлений, даже если они не видны на экране. Страницы за пределами этого ограничения будут удалены из иерархии представлений, но владельцы представлений будут переработаны, как обычно, с помощью RecyclerView.