繁体   English   中英

在活动/片段中确认警报对话框后,如何在单击时更新我的​​ RecyclerView 按钮状态?

[英]How do I update my RecyclerView button state on click after alert dialog confirmation in activity/fragment?

我有一个非常独特的情况,我在回收视图中有一个按钮,点击后(初始状态“注册”),将意图传递给片段或活动中的广播接收器,在那里它抛出一个警报对话框,有 2 个选项,是的或没有。 如果选择 no,则没有任何反应并且对话框关闭,但是如果单击 yes,它会处理我在演示器类中定义的函数(与数据相关),并且应该将我的按钮 ui 状态更新为“取消”。 反之亦然,点击取消后会返回警报,点击是将切换 ui 文本以进行注册。

现在我已经实现了如下代码。(请注意,即使 notifydatasetchanged 对我也不起作用)。 知道我做错了什么以及如何实现这一目标吗? 适配器中我的public void onBind(int position)函数中的代码:

if (repo.getIsRsvpAvailable().equals("true")) {
    rsvpButton.setVisibility(View.VISIBLE);
    for (int i = 0; i < mAllRSVPEventsList.size(); i++) {
        if (mAllRSVPEventsList.get(i).getEvent().getEventId().equals(repo.getEventId()) && mAllRSVPEventsList.get(i).getIsAttending()) {
            rsvpButton.setText("CANCEL");
            rsvpButton.setOnClickListener(v -> {
                Intent in = new Intent("main_rsvp_button_clicked");
                in.putExtra("main_rsvp_event_id", repo.getEventId());
                in.putExtra("main_rsvp_is_attending", "false");
                in.putExtra("main_rsvp_item_position", position);
                rsvpButton.getContext().sendBroadcast(in);
            });
            break;
        } else {
            rsvpButton.setText("RSVP");
            rsvpButton.setOnClickListener(v -> {
                Intent in = new Intent("main_rsvp_button_clicked");
                in.putExtra("main_rsvp_event_id", repo.getEventId());
                in.putExtra("main_rsvp_is_attending", "true");
                in.putExtra("main_rsvp_item_position", position);

                rsvpButton.getContext().sendBroadcast(in);
            });
        }
    }

}

这是我的活动中广播接收器中的相应代码:

private BroadcastReceiver mEventIdReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        try {
            String eventId = intent.getStringExtra(EVENTID_MAIN_EXTRA_TITLE);
            String isAttending = intent.getStringExtra(EVENTID_MAIN_IS_ATTENDING);
            int itemPosition = intent.getIntExtra(EVENTID_MAIN_RSVP_ITEM_POSITION, 0);


            if (isAttending.equals("true")) {
                showDialog(R.string.rsvp_title, R.string.confirm_rsvp_body, R.string.yes,
                        (dialog, which) -> {
                            mPresenter.onRSVPClick(eventId, isAttending);

                            mEventListAdapter.notifyDataSetChanged();
                            mEventRecyclerView.removeAllViews();
                            mEventRecyclerView.scrollToPosition(itemPosition);

                        }, R.string.no, null, null);
            } else {
                showDialog(R.string.rsvp_title, R.string.confirm_cancel_body, R.string.yes,
                        (dialog, which) -> {
                            mPresenter.onRSVPClick(eventId, isAttending);

                            mEventListAdapter.notifyDataSetChanged();
                            mEventRecyclerView.removeAllViews();
                            mEventRecyclerView.scrollToPosition(itemPosition);

                        }, R.string.no, null, null);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
};

请注意:mEventListAdapter 是我的适配器,我在其中使用了按钮 UI 代码,而 mEventRecyclerView 是我在片段中使用的回收器视图。

知道我错过了什么或做错了什么吗? 谢谢!

RSVPClick 方法:

@Override
public void onRSVPClick(String eventId, String isAttending) {
    getMvpView().showLoading();
    getCompositeDisposable().add(getDataManager()
            .doRSVPEventApiCall(
                    eventId,
                    getDataManager().getFirstName(),
                    getDataManager().getLastName(),
                    getDataManager().getCurrentUserEmail(),
                    isAttending
            )
            .subscribeOn(getSchedulerProvider().io())
            .observeOn(getSchedulerProvider().ui())
            .subscribe(response -> {
                if (!isViewAttached()) {
                    return;
                }
                getMvpView().hideLoading();
            }, throwable -> {
                if (!isViewAttached()) {
                    return;
                }
                getMvpView().hideLoading();
                if (throwable instanceof ANError) {
                    ANError anError = (ANError) throwable;
                    handleApiError(anError);
                }
            }));
}

您可以轻松维护一个数组,以指示RecyclerView中每个项目的按钮状态。 例如,让我们假设每个按钮有两种状态(即RSVP = 0,取消= 1)。 现在在RecyclerView适配器中声明一个数组,如下所示。

private int[] stateArray; 

在适配器的构造函数中,初始化数组,如下所示。 让我们假设您的构造函数如下所示。

public EventListAdapter(Context context, ArrayList<Event> eventList) {
    this.eventList = eventList; 
    stateArray = new int[eventList.size];
    initializeTheStateArray(eventList);
}

private void initializeTheStateArray(ArrayList<Event> eventList) {

    // Initialize the array so that we can keep track of the items which are being attended or not. 
    for (int i = 0; i < eventList.size(); i++) {
        if(event.isAttending()) stateArray[i] = 1;
        else stateArray[i] = 0;
    }
}

现在在onBindViewHolder函数中,根据stateArray的条目设置按钮的文本。 这看起来应该如下所示。

if(stateArray[position] == 1) button.setText("Cancel"); // Because this item is already registerd 
else button.setText("RSVP");

您需要在适配器中使用一些附加功能,以便可以在按钮单击或API更新中更新stateArray

public void updateButtonState(int position, boolean isAttendening) {
    if(isAttending) stateArray[position] = 1;
    else stateArray[position] = 0;
    notifyDataSetChanged(); // Call the notifyDataSetChanged here to see the affect
}

当您在API调用后更新适配器的整个列表时,不要忘记更新stateArray 我希望你有一个功能来更新你的适配器中的事件列表。 修改如下所示的功能。

public void updateEventList(ArrayList<Event> eventList) {
    this.eventList = eventList;
    stateArray = new int[eventList.size()];
    initializeTheStateArray(eventList);
}

现在,您可以在单击按钮时调用适配器的updateButtonState函数。 修改rsvpButton.setOnClickListener的按钮单击操作。

如有必要,您还可以修改onReceive函数以获取RecyclerView的预期输出。

希望此设置可以帮助您实现所需的预期行为。

最后,但并非最不重要的是,在onReceive函数中,当它对RecyclerView的项目没有影响时,您立即更新RecyclerView因为网络调用是异步的,并且需要一些时间从API获取数据。 当数据可从API调用获得时,您可以考虑从onRSVPClick方法调用updateEventList方法。

希望有所帮助!

我想也许这可能会有所帮助:

  1. onBindViewHolder()上的按钮上设置单击侦听器。
  2. 在你的点击监听器里面调用notifyItemChanged(position)
  3. 保持适配器中的某些状态以处理何时更改按钮状态的逻辑,例如,在onClick中有一个var,你可以标记为shouldChangeState = true
  4. 当再次调用onBindViewHolder()时,检查此状态并绑定,因为您通常只处理此场景并相应地更改TextView。 button.setVisibility(..)button.text = "My New Text"

在onBindViewholder里面:

 holder.myRow.setOnClickListener(v -> {
          notifyItemChanged(position) 
 }

好的,所以要在你的onBindViewHolder中处理你的持有人(在Kotlin抱歉):

创建视图持有者。

sealed class MyListViewHolder(view: View) : RecyclerView.ViewHolder(view)

class MyListItemViewHolder(view: View) : MyListViewHolder(view) {
    val name: TextView = view.my_name
    val myDetail: TextView = view.my_detail
    val myOtherDetail: TextView = view.my_other_detail
}

在创建:

 override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyListViewHolder {
        val inflater: LayoutInflater = LayoutInflater.from(parent.context)
        val view = inflater.inflate(R.layout.row_item, parent, false)
        val viewHolder = MyListItemViewHolder(view)

        with(view) {
            tag = viewHolder
        }
        return viewHolder
    }

然后在onBindViewHolder上:

  override fun onBindViewHolder(itemHolder: MyListViewHolder, position: Int) {
        val holder = itemHolder as MyListItemViewHolder
        val currentInfo = myList[position]

        // Get your data from list to bind here.

        holder.name.text = // Text
        holder.myDetail.text = // Text
        holder.myOtherDetail.text = Text

        holder.setOnClickListener {
             // Other stuff, state, actions etc.
             notifyItemChanged(position)
        }
    }

实际更改数据集后应调用notifyDatasetChanged() 正如Sudhanshu Gupta所指出的,在错误的时间调用notifyDatasetChanged() (单击对话框按钮时)。 由于适配器中的mEventListResponseListmAllRSVPEventsList是私有的,因此更改它们的唯一方法是调用addItems()addRSVPItems()方法。 显然,在单击对话框按钮时,不会调用这些方法,表示数据集未更改。 因此notifyDatasetChanged()无效。

更新可能需要几秒钟。 但无论是否更新,都可以在出现警报并单击是时将适配器中的按钮的ui更改为其他状态(例如从rsvp取消)

不,因为上述原因。

并且,当响应到达时,除了记录之外它将被丢弃。 来自Presenter类中的onRSVPClick()片段。

.subscribe(response -> {
    if (!isViewAttached()) {
        return;
    }
    Log.d("rsvptest", "basic event id:" + response);

    getMvpView().hideLoading();

}

要查看更改,您应该以mEventListResponseList方式更新适配器中的mEventListResponseListmAllRSVPEventsList ,并使用来自响应的数据调用它。 另外,不要忘记在该方法中调用notifyDatasetChanged()

所以,我能够得出一个答案而且很简单。

这是答案:

if (repo.getIsRsvpAvailable().equals("true")){
    rsvpButton.setVisibility(View.VISIBLE);
    if(mAllRSVPEventsList.size() != 0) {

        for (int i = 0; i < mAllRSVPEventsList.size(); i++) {
            if (mAllRSVPEventsList.get(i).getEvent().getEventId().equals(repo.getEventId()) && mAllRSVPEventsList.get(i).getIsAttending()) {
                rsvpButton.setText("CANCEL");
                rsvpButton.setTextColor(Color.parseColor("#647ed6"));
                mYesText.setVisibility(View.VISIBLE);
                rsvpButton.setBackgroundColor(Color.WHITE);
                GradientDrawable gd = new GradientDrawable();
                gd.setCornerRadius(2);
                gd.setGradientRadius(2);
                gd.setStroke(2, 0xFF647ed6);
                rsvpButton.setBackground(gd);
                rsvpButton.setOnClickListener(v -> {
                    Log.d("clickedbutton", "it is in" + repo.getTitle());
                    mCallback.onRSVPButtonClick(repo.getEventId(), position, "false", repo.getTitle(), rsvpButton, mAllRSVPEventsList);

                });
                break;
            }

            if (mAllRSVPEventsList.get(i).getEvent().getEventId().equals(repo.getEventId()) && !mAllRSVPEventsList.get(i).getIsAttending()) {

                rsvpButton.setText("RSVP");
                rsvpButton.setBackgroundColor(Color.parseColor("#647ed6"));
                rsvpButton.setTextColor(Color.WHITE);
                mYesText.setVisibility(View.GONE);

                rsvpButton.setOnClickListener(v -> {

                    mCallback.onRSVPButtonClick(repo.getEventId(), position, "true", repo.getTitle(), rsvpButton, mAllRSVPEventsList);

                });
                break;
            } else {
                rsvpButton.setText("RSVP");
                rsvpButton.setBackgroundColor(Color.parseColor("#647ed6"));
                rsvpButton.setTextColor(Color.WHITE);
                mYesText.setVisibility(View.GONE);
                rsvpButton.setOnClickListener(v -> {
                    mCallback.onRSVPButtonClick(repo.getEventId(), position, "true", repo.getTitle(), rsvpButton, mAllRSVPEventsList);

                });
            }


        }
    } else {
        for (int i = 0; i < mEventListResponseList.size(); i++) {
            rsvpButton.setOnClickListener(v -> {
                mCallback.onRSVPButtonClick(repo.getEventId(), position, "true", repo.getTitle(), rsvpButton, mAllRSVPEventsList);

            });
        }
    }
}

所以,基本上我必须将if循环分开,以便ui在刷新后根据条件进行更新。 每次都没有任何问题,并检查rsvp列表的大小是否为0,如果是(默认设置为rsvp,单击将其切换为UI中的取消按钮),它会将事件添加到rsvp列表所以下次我迭代时,它有交叉检查的事件。 感谢大家帮忙解决这个问题,所有回答的人都是+10! 我感谢您的帮助。

在调用notifyDatasetChanged()之前,您是否根据用户在对话框上选择的操作更新了repo对象? 看起来doRSVPEventApiCall()方法不会更新适配器可用的项目列表,因此notifyDatasetChanged()无效。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM