Отображение дополнительных сведений в recyclerview + fastadapter при нажатии элемента

В приложении, использующем FastAdapter и ConstraintLayout, я показываю список завершенных игр (простите за неанглийские символы на снимке экрана):

screenshot 1

Когда пользователь приложения щелкает элемент в списке (в любом месте элемента), я хотел бы отобразить представление изображения с квадратным игровым полем, а также изменить представление изображения с плюсом на минус:

screenshot 2

Для этого я уже подготовил метод:

private void toggleDetails() {
    if (mBoard.getVisibility() == View.GONE) {
        mBoard.setVisibility(View.VISIBLE);
        mDetails.setImageResource(R.drawable.minus_circle_gray);
    } else {
        mBoard.setVisibility(View.GONE);
        mDetails.setImageResource(R.drawable.plus_circle_gray);
    }
}

Однако моя проблема в том, что я не уверен, где вызывать метод.

Должен ли я добавить прослушиватель щелчков к объекту быстрого адаптера или я должен добавить его в держатель представления?

Кроме того, глядя на пример ExpandableSampleActivity, я замечаю, что есть некоторая анимация, и задаюсь вопросом, как оживить мое раскрытие представления изображения mBoard ...

Ниже мой текущий исходный код:

public class FinishedGameItem extends AbstractItem<FinishedGameItem, FinishedGameItem.ViewHolder> {
    private final static String WON = "won";
    private final static String LOST = "lost";

    public long stamp;
    public int gid;
    public int score1;
    public int score2;
    public int elo1;
    public int elo2;
    public String state1;
    public String finished;
    public String given1;
    public String given2;
    public String photo1;
    public String photo2;

    @Override
    public int getType() {
        return R.id.finished_game_item_id;
    }

    @Override
    public int getLayoutRes() {
        return R.layout.item_finished_game;
    }

    @NonNull
    @Override
    public ViewHolder getViewHolder(@NonNull View v) {
        return new ViewHolder(v);
    }

    protected static class ViewHolder extends FastAdapter.ViewHolder<FinishedGameItem> {
        private ImageView mDetails;
        private TextView mGid;
        private TextView mFinished;
        private TextView mScore1;
        private TextView mScore2;
        private TextView mGiven1;
        private TextView mGiven2;
        private TextView mElo1;
        private TextView mElo2;
        private ImageView mPhoto1;
        private ImageView mPhoto2;
        private ImageView mBoard;

        public ViewHolder(View view) {
            super(view);
            mDetails = view.findViewById(R.id.details);
            mGid = view.findViewById(R.id.gid);
            mFinished = view.findViewById(R.id.finished);
            mScore1 = view.findViewById(R.id.score1);
            mScore2 = view.findViewById(R.id.score2);
            mGiven1 = view.findViewById(R.id.given1);
            mGiven2 = view.findViewById(R.id.given2);
            mElo1 = view.findViewById(R.id.elo1);
            mElo2 = view.findViewById(R.id.elo2);
            mPhoto1 = view.findViewById(R.id.photo1);
            mPhoto2 = view.findViewById(R.id.photo2);
            mBoard = view.findViewById(R.id.board);
        }

        @Override
        public void bindView(@NonNull FinishedGameItem item, @NonNull List<Object> payloads) {
            Context ctx = mDetails.getContext();
            Resources res = mDetails.getResources();

            String result = (WON.equals(item.state1) ? "Victory" : (LOST.equals(item.state1) ? "Loss" : "Draw"));

            mDetails.setImageResource(R.drawable.plus_circle_gray);
            mBoard.setVisibility(View.GONE);

            mGid.setText(r.getString(R.string.str_game, item.gid));
            mFinished.setText(result + " / " + item.finished);
            mScore1.setText(res.getString(R.string.str_score, item.score1));
            mScore2.setText(res.getString(R.string.str_score, item.score2));
            mGiven1.setText(item.given1);
            mGiven2.setText(item.given2);
            mElo1.setText(String.valueOf(item.elo1));
            mElo2.setText(String.valueOf(item.elo2));

            if (URLUtil.isHttpsUrl(item.photo1)) {
                Picasso.with(ctx))
                        .load(item.photo1)
                        .placeholder(R.drawable.account_gray)
                        .into(mPhoto1);
            }

            if (URLUtil.isHttpsUrl(item.photo2)) {
                Picasso.with(ctx)
                        .load(item.photo2)
                        .placeholder(R.drawable.account_gray)
                        .into(mPhoto2);
            }

            Picasso.with(ctx)
                    .load("http://slova.de/words/board2.php?gid=" + item.gid)
                    .placeholder(R.drawable.checkerboard_gray)
                    .into(mBoard);
        }

        @Override
        public void unbindView(@NonNull FinishedGameItem item) {
            Context ctx = mDetails.getContext();

            Picasso.with(ctx).cancelRequest(mPhoto1);
            Picasso.with(ctx).cancelRequest(mPhoto2);
            Picasso.with(ctx).cancelRequest(mBoard);

            mDetails.setImageDrawable(null);
            mGid.setText(null);
            mFinished.setText(null);
            mScore1.setText(null);
            mScore2.setText(null);
            mGiven1.setText(null);
            mGiven2.setText(null);
            mElo1.setText(null);
            mElo2.setText(null);
            mPhoto1.setImageDrawable(null);
            mPhoto2.setImageDrawable(null);
            mBoard.setImageDrawable(null);
        }

        // WHERE TO CALL THIS METHOD AND HOW TO ANIMATE?

        private void toggleDetails() {
            if (mBoard.getVisibility() == View.GONE) {
                mBoard.setVisibility(View.VISIBLE);
                mDetails.setImageResource(R.drawable.minus_circle_gray);
            } else {
                mBoard.setVisibility(View.GONE);
                mDetails.setImageResource(R.drawable.plus_circle_gray);
            }
        }
    }
}

Я тоже задал свой вопрос в Выпуск 713 на Github

Обновлено:

Я попытался добавить логическое значение details в свою модель и использовать его в методе bindView (true означает отображение mBoard), но теперь приложение ведет себя нестабильно, отображаются неправильные данные и не сразу после нажатия -

Вот новый исходный код фрагмента:

mFastAdapter.withSelectable(true);
mFastAdapter.withOnClickListener(new OnClickListener<FinishedGameItem>() {
    @Override
    public boolean onClick(View v, @NonNull IAdapter<FinishedGameItem> adapter, @NonNull FinishedGameItem item, int position) {
        item.details = !item.details;

        // THIS METHOD IS CALLED IN DEBUGGER, BUT VIEWS ARE NOT UPDATED

        return true;
    }
});

А вот измененная модель FinishedGameItem:

public class FinishedGameItem extends AbstractItem<FinishedGameItem, FinishedGameItem.ViewHolder> {
    private final static String WON = "won";
    private final static String LOST = "lost";

    public boolean details; // TRIED TO ADD THIS BOOLEAN
    public long stamp;
    public int gid;
    public int score1;
    public int score2;
    public int elo1;
    public int elo2;
    public String state1;
    public String finished;
    public String given1;
    public String given2;
    public String photo1;
    public String photo2;

    @Override
    public int getType() {
        return R.id.finished_game_item_id;
    }

    @Override
    public int getLayoutRes() {
        return R.layout.item_finished_game;
    }

    @NonNull
    @Override
    public ViewHolder getViewHolder(@NonNull View v) {
        return new ViewHolder(v);
    }

    protected static class ViewHolder extends FastAdapter.ViewHolder<FinishedGameItem> {
        private ImageView mDetails;
        private TextView mGid;
        private TextView mFinished;
        private TextView mScore1;
        private TextView mScore2;
        private TextView mGiven1;
        private TextView mGiven2;
        private TextView mElo1;
        private TextView mElo2;
        private ImageView mPhoto1;
        private ImageView mPhoto2;
        private ImageView mBoard;

        public ViewHolder(View view) {
            super(view);
            mDetails = view.findViewById(R.id.details);
            mGid = view.findViewById(R.id.gid);
            mFinished = view.findViewById(R.id.finished);
            mScore1 = view.findViewById(R.id.score1);
            mScore2 = view.findViewById(R.id.score2);
            mGiven1 = view.findViewById(R.id.given1);
            mGiven2 = view.findViewById(R.id.given2);
            mElo1 = view.findViewById(R.id.elo1);
            mElo2 = view.findViewById(R.id.elo2);
            mPhoto1 = view.findViewById(R.id.photo1);
            mPhoto2 = view.findViewById(R.id.photo2);
            mBoard = view.findViewById(R.id.board);
        }

        @Override
        public void bindView(@NonNull FinishedGameItem item, @NonNull List<Object> payloads) {
            Context ctx = mDetails.getContext();
            Resources res = mDetails.getResources();

            String result = (WON.equals(item.state1) ? "Victory" : (LOST.equals(item.state1) ? "Loss" : "Draw"));

            mDetails.setImageResource(item.details ? R.drawable.minus_circle_gray : R.drawable.plus_circle_gray);
            mBoard.setVisibility(item.details ? View.VISIBLE : View.GONE);

            mGid.setText(res.getString(R.string.str_game, item.gid));
            mFinished.setText(result + " / " + item.finished);
            mScore1.setText(res.getString(R.string.str_score, item.score1));
            mScore2.setText(res.getString(R.string.str_score, item.score2));
            mGiven1.setText(item.given1);
            mGiven2.setText(item.given2);
            mElo1.setText(String.valueOf(item.elo1));
            mElo2.setText(String.valueOf(item.elo2));

            if (URLUtil.isHttpsUrl(item.photo1)) {
                Picasso.with(ctx)
                        .load(item.photo1)
                        .placeholder(R.drawable.account_gray)
                        .into(mPhoto1);
            }

            if (URLUtil.isHttpsUrl(item.photo2)) {
                Picasso.with(ctx)
                        .load(item.photo2)
                        .placeholder(R.drawable.account_gray)
                        .into(mPhoto2);
            }

            if (item.details) {
                Picasso.with(ctx)
                        .load("http://slova.de/words/board2.php?gid=" + item.gid)
                        .placeholder(R.drawable.checkerboard_gray)
                        .into(mBoard);
            }
        }

        @Override
        public void unbindView(@NonNull FinishedGameItem item) {
            Context ctx = mDetails.getContext();

            Picasso.with(ctx).cancelRequest(mPhoto1);
            Picasso.with(ctx).cancelRequest(mPhoto2);
            Picasso.with(ctx).cancelRequest(mBoard);

            mDetails.setImageDrawable(null);
            mGid.setText(null);
            mFinished.setText(null);
            mScore1.setText(null);
            mScore2.setText(null);
            mGiven1.setText(null);
            mGiven2.setText(null);
            mElo1.setText(null);
            mElo2.setText(null);
            mPhoto1.setImageDrawable(null);
            mPhoto2.setImageDrawable(null);
            mBoard.setImageDrawable(null);
        }
    }
}

Приложение вроде работает, но нестабильно:

screenshot 3

Это простой подход (добавьте imgeview в viewholder и просто покажите, спрячьте его), вы можете сделать это без использования быстрого адаптера. Если хотите, я могу предоставить вам код. Да, вы должны установить onItemClickListner при щелчке элемента, который вы меняете значок.

Ranjan 13.08.2018 09:22

Спасибо, но я использую функции фильтрации и поиска FastAdapter (см. Значки в правом верхнем углу)

Alexander Farber 13.08.2018 12:17
0
2
483
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Судя по вашему коду, вы могли забыть сообщить адаптеру, что ваша модель поддержки (FinishedGameItem) изменилась. Вызов notifyItemChanged(position) может помочь.

mFastAdapter.withSelectable(true);
mFastAdapter.withOnClickListener(new OnClickListener<FinishedGameItem>() {
    @Override
    public boolean onClick(View v, @NonNull IAdapter<FinishedGameItem> adapter, @NonNull FinishedGameItem item, int position) {
        item.details = !item.details;

        mFastAdapter.notifyItemChanged(position);

        return true;
    }
});

Согласен с этим ответом. Просто хотел добавить - если вам нужна анимация - самый простой способ - использовать анимацию макета - пожалуйста, обратитесь к developer.android.com/training/animation/layout для получения дополнительной информации

Mike 16.08.2018 17:51

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