Связывание данных Recyclerview и onClick - PullRequest
0 голосов
/ 10 ноября 2018

Хорошо, я попробую еще раз. В прошлый раз я спрашивал о передаче данных между утилитой просмотра и элементом, и один человек помог мне с открытым элементом щелчком мыши, но я все еще не представляю, как отобразить данные о выбранном элементе в новом действии. Я хочу нажать на элемент, а затем отобразить данные этого элемента в новом действии. В этом упражнении я хочу редактировать данные. Кто-нибудь знает как это сделать? Мне нужна идея.

Адаптер RecyclerView с интерфейсом OnItemClickListener:

public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.TaskViewHolder> {

private List<MainViewModel> mTasks;
private List<Task> tasks = new ArrayList<>();
private Context context;
private EditTaskViewModel editTaskViewModel;


public RecyclerViewAdapter(List<MainViewModel> tasks, Context context, EditTaskViewModel editTaskViewModel) {
    this.mTasks = tasks;
    this.context = context;
    this.editTaskViewModel = editTaskViewModel;
}


@NonNull
@Override
public RecyclerViewAdapter.TaskViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    LayoutInflater inflater = LayoutInflater.from(parent.getContext());
    final RecyclerViewItemBinding binding = DataBindingUtil.inflate(inflater, R.layout.recycler_view_item, parent, false);

    binding.setItemClickListener(new OnItemClickListener() {
        @Override
        public void onItemClick(View view) {
            Intent intent = new Intent(view.getContext(), EditTaskActivity.class);
            intent.putExtra("id", binding.getPosition());
            view.getContext().startActivity(intent);
            Toast.makeText(view.getContext(), "ID " + binding.getPosition(), Toast.LENGTH_SHORT).show();

        }
    });
    return new TaskViewHolder(binding);
}

@Override
public void onBindViewHolder(@NonNull final RecyclerViewAdapter.TaskViewHolder holder, final int position) {
    Task currentTask = tasks.get(position);
    holder.mBinding.descriptionItem.setText(currentTask.getDescription());
    holder.mBinding.dateItem.setText(currentTask.getDate());
    holder.mBinding.timeItem.setText(currentTask.getTime());
    holder.mBinding.setPosition(position);
}

@Override
public int getItemCount() {
    return tasks.size();
}

public void setTasks(List<Task> tasks) {
    this.tasks = tasks;
    notifyDataSetChanged();
}

public Task getTaskPosition(int position) {
    return tasks.get(position);
}

public class TaskViewHolder extends RecyclerView.ViewHolder {
    private final RecyclerViewItemBinding mBinding;

    public TaskViewHolder(RecyclerViewItemBinding binding) {
        super(binding.getRoot());
        this.mBinding = binding;
    }

        public void bind (MainViewModel mainViewModel){
            mBinding.setItemView(mainViewModel);
            mBinding.executePendingBindings();
        }
    }

    public interface OnItemClickListener {
        void onItemClick(View view);
    }

Элемент XML-файл:

<layout xmlns:android="http://schemas.android.com/apk/res/android">

<data>
    <variable
        name="itemView"
        type="com.example.daniellachacz.taskmvvm.viewmodel.MainViewModel">
    </variable>

    <variable
        name="itemClickListener"
        type="com.example.daniellachacz.taskmvvm.adapter.RecyclerViewAdapter.OnItemClickListener">
    </variable>

    <variable
        name="task"
        type="com.example.daniellachacz.taskmvvm.model.Task">
    </variable>

    <variable
        name="position"
        type="int">
    </variable>

</data>

<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="120dp"
android:shadowColor="@color/colorPrimary"
android:backgroundTint="@color/cardview_shadow_end_color">

<RelativeLayout
android:layout_width="match_parent"
android:layout_height="110dp"
android:layout_marginBottom="6dp"
android:layout_marginTop="6dp"
android:layout_marginStart="6dp"
android:layout_marginEnd="6dp"
android:onClick="@{(view)-> itemClickListener.onItemClick(view)}">

<TextView
    android:id="@+id/description_item"
    android:layout_width="250dp"
    android:layout_height="96dp"
    android:layout_marginStart="5dp"
    android:layout_marginTop="9dp"
    android:layout_marginBottom="5dp"
    android:text="@{itemView.description}"
    android:textSize="18sp"
    android:textColor="#020202"
    android:focusable="true" />

<TextView
    android:id="@+id/date_item"
    android:layout_width="90dp"
    android:layout_height="40dp"
    android:layout_alignParentTop="true"
    android:layout_alignParentEnd="true"
    android:layout_marginTop="9dp"
    android:layout_marginEnd="10dp"
    android:gravity="center"
    android:text="@{itemView.date}"
    android:textColor="#020202"
    android:textSize="16sp" />

<TextView
    android:id="@+id/time_item"
    android:layout_width="90dp"
    android:layout_height="40dp"
    android:layout_alignParentBottom="true"
    android:layout_alignStart="@+id/date_item"
    android:layout_marginBottom="10dp"
    android:layout_marginEnd="10dp"
    android:gravity="center"
    android:text="@{itemView.time}"
    android:textColor="#020202"
    android:textSize="16sp" />

    </RelativeLayout>
    </android.support.v7.widget.CardView>

    </layout>

OnCreate:

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

floatingActionButton = findViewById(R.id.floating_action_button);

List<Task> tasks = new ArrayList<>();

RecyclerView recyclerView = findViewById(R.id.recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setHasFixedSize(true);

final RecyclerViewAdapter recyclerViewAdapter = new     RecyclerViewAdapter(context, tasks);
recyclerView.setAdapter(recyclerViewAdapter);

mainViewModel = ViewModelProviders.of(this).get(MainViewModel.class);
mainViewModel.getAllTasks().observe(this, recyclerViewAdapter::setTasks);

Ответы [ 3 ]

0 голосов
/ 10 ноября 2018

Вот несколько советов, которые могут оказаться полезными:

Не зависит от ViewModel s в ваших адаптерах.ViewModel s предназначены для обработки событий из представлений (фрагментов или действий) и передачи обновлений обратно представлениям через некоторый наблюдаемый механизм (чаще всего LiveData экземпляров).Ссылка на ViewModel непосредственно внутри адаптера плохая, так как он связывает их вместе.Это означает, что вам будет очень трудно повторно использовать адаптер с другим ViewModel, если это необходимо.Я знаю, что на данный момент это маловероятно, но просто поверь мне в этом.После применения изменений ваш адаптер должен выглядеть примерно так:

public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.TaskViewHolder> {

    private LayoutInflater mLayoutInflater;
    private List<Task> mTasks;

    private OnItemClickListener mOnItemClickListener;

    public RecyclerViewAdapter(@NonNull Context context, @NonNull List<Task> tasks) {
         mLayoutInflater = LayoutInflater.fromContext(context);
         mTasks = tasks;
    }

    public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
        mOnItemClickListener = onItemClickListener;
    }

    @NonNull
    @Override
    public RecyclerViewAdapter.TaskViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        final RecyclerViewItemBinding binding = DataBindingUtil.inflate(mLayoutInflater, R.layout.recycler_view_item, parent, false);
        return new TaskViewHolder(binding);
    }

    @Override
    public void onBindViewHolder(@NonNull final RecyclerViewAdapter.TaskViewHolder holder, final int position) {
        Task currentTask = tasks.get(position);
        holder.bind(currentTask, mOnItemClickListener);
    }

    @Override
    public int getItemCount() {
        return tasks.size();
    }

    public void setTasks(List<Task> tasks) {
        this.tasks = tasks;
        notifyDataSetChanged();
    }

    public Task getTaskPosition(int position) {
        return tasks.get(position);
    }

    public class TaskViewHolder extends RecyclerView.ViewHolder {
        private final RecyclerViewItemBinding mBinding;

         public TaskViewHolder(RecyclerViewItemBinding binding) {
             super(binding.getRoot());
             this.mBinding = binding;
         }

         public void bind (Task item, OnItemClickListener onItemClickListener) {
             mBinding.setItem(item);
             mBinding.executePendingBindings();
             itemView.setOnClickListener(view -> {
                 if (onItemClickListener != null) {
                     onItemClickListener.onItemClick(view, item);
                 }
             }
         }
    }

    public interface OnItemClickListener {
        void onItemClick(View view, Task item);
    }
}

Метод OnItemClickListener.onItemClick() теперь передает представление и сам элемент в качестве параметров.Это самый простой способ показать выбранный элемент тому, кто может быть заинтересован.Приемник по щелчку не устанавливается на уровне адаптера, используя setOnItemClickListener().

. Настройка OnClickListener представления элемента теперь выполняется в методе bind() TaskViewHolder.При связывании мы знаем точный элемент, который будет заполнять представление, поэтому мы можем вернуть его в OnItemClickListener.

Вы также должны упростить макет, так как есть много вещей, которыена самом деле не нужны.Это может выглядеть так:

<layout xmlns:android="http://schemas.android.com/apk/res/android">

<data>
    <variable
        name="task"
        type="com.example.daniellachacz.taskmvvm.model.Task">
    </variable>
</data>

<android.support.v7.widget.CardView
    android:layout_width="match_parent"
    android:layout_height="120dp"
    android:shadowColor="@color/colorPrimary"
    android:backgroundTint="@color/cardview_shadow_end_color">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="110dp"
        android:layout_marginBottom="6dp"
        android:layout_marginTop="6dp"
        android:layout_marginStart="6dp"
        android:layout_marginEnd="6dp">

        <TextView
            android:id="@+id/description_item"
            android:layout_width="250dp"
            android:layout_height="96dp"
            android:layout_marginStart="5dp"
            android:layout_marginTop="9dp"
            android:layout_marginBottom="5dp"
            android:text="@{item.description}"
            android:textSize="18sp"
            android:textColor="#020202"
            android:focusable="true" />

        <TextView
            android:id="@+id/date_item"
            android:layout_width="90dp"
            android:layout_height="40dp"
            android:layout_alignParentTop="true"
            android:layout_alignParentEnd="true"
            android:layout_marginTop="9dp"
            android:layout_marginEnd="10dp"
            android:gravity="center"
            android:text="@{item.date}"
            android:textColor="#020202"
            android:textSize="16sp" />

        <TextView
            android:id="@+id/time_item"
            android:layout_width="90dp"
            android:layout_height="40dp"
            android:layout_alignParentBottom="true"
            android:layout_alignStart="@+id/date_item"
            android:layout_marginBottom="10dp"
            android:layout_marginEnd="10dp"
            android:gravity="center"
            android:text="@{item.time}"
            android:textColor="#020202"
            android:textSize="16sp" />

        </RelativeLayout>
    </android.support.v7.widget.CardView>

</layout>

Единственная переменная - item, и мы привязываем ее свойства к TextView s.

Полагаю, этого должно быть достаточно, чтобы вы начали.

Просто пара других вещей, которые не имеют прямого отношения к вопросу, но важны.

  • Нулевая безопасность - вы никогда не проверяете вход при вызове setTask() в адаптере.Клиент может передать null и вызвать сбои повсюду.Вы должны попытаться предотвратить это.
  • Вызов notifyDataSetChanged() не является хорошей практикой при работе с RecyclerView.Adapter, так как это отменит все встроенные анимации RecyclerView.Лучше использовать другие notify... методы.Вы можете проверить DiffUtil в какой-то момент.
0 голосов
/ 13 мая 2019

Вот что я сделал для прослушивателя щелчков элементов в представлении рециркулятора с использованием привязки данных

КОД АДАПТЕРА

public class TC_DashboardRecViewAdapter extends RecyclerView.Adapter<TC_DashboardRecViewAdapter.ViewHolder> {
Context context;
List<String> list;
private TcDashboardItemBinding tcDashboardItemBinding;
ItemClickListener itemClickListener;

public TC_DashboardRecViewAdapter(Context context, List<String> dashboardItems, ItemClickListener itemClickListener) {
    this.context = context;
    this.list = dashboardItems;
    this.itemClickListener = itemClickListener;
}

@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    LayoutInflater inflater = LayoutInflater.from(parent.getContext());
    ViewDataBinding binding = DataBindingUtil.inflate(inflater, R.layout.tc_dashboard_item, parent, false);
    tcDashboardItemBinding = (TcDashboardItemBinding) parent.getTag();
    return new ViewHolder(binding);
}

@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        holder.bind(list.get(position), itemClickListener, position);
}

@Override
public int getItemCount() {
    return list.size();
}


class ViewHolder extends RecyclerView.ViewHolder {

    private ViewDataBinding binding;

    public ViewHolder(ViewDataBinding binding) {
        super(binding.getRoot());
        this.binding = binding;
    }

    public void bind(String s, ItemClickListener itemClickListener, int position) {
        this.binding.setVariable(BR.itemModel, s);
        this.binding.executePendingBindings();
        binding.getRoot().setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if(itemClickListener !=null){
                    itemClickListener.onItemClicked(binding.getRoot(), s, position);
                }
            }
        });
    }
}

ПУНКТ НАЖМИТЕ ИНТЕРФЕЙС:

public interface ItemClickListener {
void onItemClicked(View vh, Object item, int pos);
}

ФРАГМЕНТ / КОД ДЕЯТЕЛЬНОСТИ:

public class TC_DashboardFragment extends BaseFragment implements ItemClickListener {


public void onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

 tc_dashboardRecViewAdapter = new TC_DashboardRecViewAdapter(getContext(), getDashboardItems(), this);
    linearLayoutManager = new LinearLayoutManager(getContext());
    dashboardrecyclerview.setLayoutManager(new LinearLayoutManager(getContext()));
    binding.setAdapter(tc_dashboardRecViewAdapter);
}

@Override
public void onItemClicked(View vh, Object item, int pos) {
    Toast.makeText(mainActivity, item.toString(), Toast.LENGTH_SHORT).show();
}

Когда вы запускаете код и щелкаете по элементу представления переработчика, он показывает тост с текстом по нажатому элементу.

0 голосов
/ 10 ноября 2018

Это зависит от того, как хранятся ваши данные и доступны ли они во втором упражнении. Если у вас есть статический ArrayList ваших данных, вы можете извлечь из него данные, используя индекс, который вы передали при щелчке элемента RV. Например:

class myData{
private ArrayList<Data> myDataArray;

static ArrayList<Data> getMyDataArray(){
   return myDataArray;
}

static void setMyDataArray(array)
   myDataArray = array;
}  

Таким образом, вы заполняете свой RV с помощью getMyDataArray (), а затем настраиваете onlclick для отправки индекса, по которому щелкнули в RV, к следующему действию. В загрузке второго действия:

int myDataIndex = getIntent().getIntExtra("id",0);
Data myData = myData.getMyDataArray().get(myDataIndex);

Примечание. Данные, какими бы ни были ваши данные, могут быть строками или целыми числами или пользовательским классом / объектом с данными.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...