Как выполнить это обновление даты в моих строках RecyclerView?

В моем адаптере RecyclerView у моих строк есть TextViews, которые отображают даты. Если пользователь щелкает TextView, отображается DialogFragment, который позволяет пользователю выбрать время и дату, а затем Date передается обратно через интерфейс.

Однако я не знаю, как получить дату назад в методе onClick, который я добавил в свой TextView.

public class RecyclerViewHolder extends RecyclerView.ViewHolder {
        public TextView dateTextView;
        public RecyclerViewHolder(View itemView) {
            super(itemView);
            dateTextView = (TextView) itemView.findViewById(R.id.date_textview);

            dateTextView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    //I can call my DialogFragment here but then what?
                }
            });

2 ответа

Решение

Вы можете создать интерфейс для связи с адаптером:

public class RecyclerViewHolder extends RecyclerView.ViewHolder {

    public TextView dateTextView;
    private IAdapter adapter;

    public RecyclerViewHolder(View itemView, IAdapter adapter) {
        super(itemView);
        dateTextView = (TextView) itemView.findViewById(R.id.date_textview);
        this.adapter = adapter;

        dateTextView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                MyDialogFragment fragment = MyDialogFragment.newInstance(getAdapterPosition(), adapter);
                FragmentTransaction ft = v.getContext().getFragmentManager().beginTransaction();
                fragment.show(ft, "calendarDialog");
            }
        });
    }
}

Интерфейс, который должен реализовать адаптер:

interface IAdapter extends Serializable {
    void setDataAt(int index, Calendar date);
    void notifyItemChanged(int index);
}

Так как адаптер уже имеет notifyItemChanged метод, вам нужно будет только реализовать setDataAt метод.

Предполагая, что ваш адаптер будет содержать только даты, вот пример:

public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewHolder> implements IAdapter {

    private List<Calendar> dates = new ArrayList<>();

    public RecyclerViewAdapter(List<Calendar> dates) {
        this.dates = dates;
    }

    @Override
    public void setDataAt(int index, Calendar date) {
        dates.add(index, date);
    }

    @Override
    public RecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        LayoutInflater inflater = LayoutInflater.from(parent.getContext());
        View holderView = inflater.inflate(R.layout.view_holder, parent, false);
        return new RecyclerViewHolder(holderView, this); // notice how we pass this adapter's interface along with the view
    }

    // Include other methods (getItemCount, onBindViewHolder, etc.)
    // Adapter already has the notifyItemChanged(int index) method so no need to override it
}

Вот пример DialogFragment, который использует позицию индекса и Calendar объект:

public static class MyDialogFragment extends DialogFragment {
    private int index;
    private IAdapter adapter;


    public static MyDialogFragment newInstance(int index, IAdapter adapter) {
        MyDialogFragment f = new MyDialogFragment();

        Bundle args = new Bundle();
        args.putInt("index", index);
        args.putSerializable("adapter", adapter);
        f.setArguments(args);

        return f;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Bundle args = getArguments();
        index = args.getInt("index");
        adapter = args.getSerializable("adapter");
    }

    // Build view and set OnClickListener for setting date
}

После того, как пользователь обновит дату, вызовите следующее:

adapter.setDataAt(index, date);
adapter.notifyItemChanged(index);

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

RecyclerAdapter (предположим, что встречающийся список массивов - это модель данных):

@Override
public void onBindViewHolder(
        EncounterViewHolder holder, int position) {
    final Encounter encounter = encounters.get(position);
    holder.getDate().setText(encounter.getDate());
    holder.getDate().setTag(R.string.tag_adapter, this);
    holder.getDate().setTag(R.string.tag_position, new Integer(position));
    holder.getDate().setOnLongClickListener(new View.OnLongClickListener() {
        @Override
        public boolean onLongClick(View view) {
            showDatePickerDialog(view);
            return true;
        }
    });
}

public void showDatePickerDialog(View view) {
    DatePickerFragment datePickerFragment = new DatePickerFragment(view);
    datePickerFragment.show(((FragmentActivity) context).getSupportFragmentManager(), "datePicker");
}

public void showTimePickerDialog(View view) {
    TimePickerFragment timePickerFragment = new TimePickerFragment(view);
    timePickerFragment.show(((FragmentActivity) context).getSupportFragmentManager(), "timePicker");
}

void notifyDateTimeChanged(int position, Calendar calendar) {
    encounters.get(position).setDate(new Timestamp().get(calendar));
    notifyDataSetChanged();
}

DatePickerFragment:

public class DatePickerFragment extends DialogFragment
        implements DatePickerDialog.OnDateSetListener  {

private View view;

DatePickerFragment(View view) {
    this.view = view;
}

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    Calendar cal = Calendar.getInstance();
    int year = cal.get(Calendar.YEAR);
    int month = cal.get(Calendar.MONTH);
    int day = cal.get(Calendar.DAY_OF_MONTH);
    return new DatePickerDialog(getActivity(), this, year, month, day);
}

@Override
public void onDateSet(DatePicker view, int year, int month, int day) {
    Calendar calendar = new GregorianCalendar();
    calendar.set(year, month, day);
    (this.view).setTag(R.string.tag_calendar, calendar);
    EncounterRecyclerAdapter adapter = (EncounterRecyclerAdapter) (this.view).getTag(R.string.tag_adapter);
    adapter.showTimePickerDialog(this.view);
}
}

TimePickerFragment:

public class TimePickerFragment extends DialogFragment
        implements TimePickerDialog.OnTimeSetListener  {

private View view;

TimePickerFragment(View view)
{
    this.view = view;
}

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    Calendar cal = Calendar.getInstance();
    int hour = cal.get(Calendar.HOUR_OF_DAY);
    int minute = cal.get(Calendar.MINUTE);
    return new TimePickerDialog(getActivity(), this, hour, minute,
            DateFormat.is24HourFormat(getActivity()));
}

@Override
public void onTimeSet(TimePicker view, int hour, int minute) {
    EncounterRecyclerAdapter adapter = (EncounterRecyclerAdapter) (this.view).getTag(R.string.tag_adapter);
    int position = ((Integer) (this.view).getTag(R.string.tag_position));
    GregorianCalendar calendar = ((GregorianCalendar) (this.view).getTag(R.string.tag_calendar));
    calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH), hour, minute);
    adapter.notifyDateTimeChanged(position, calendar);
}
}

Пытаться

RecyclerView.notifyItemChanged(i);

где я - индекс элемента, который будет обновлен.

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