[英]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
方法。
希望有所帮助!
我想也许这可能会有所帮助:
onBindViewHolder()
上的按钮上设置单击侦听器。 notifyItemChanged(position)
shouldChangeState = true
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()
(单击对话框按钮时)。 由于适配器中的mEventListResponseList
和mAllRSVPEventsList
是私有的,因此更改它们的唯一方法是调用addItems()
和addRSVPItems()
方法。 显然,在单击对话框按钮时,不会调用这些方法,表示数据集未更改。 因此notifyDatasetChanged()
无效。
更新可能需要几秒钟。 但无论是否更新,都可以在出现警报并单击是时将适配器中的按钮的ui更改为其他状态(例如从rsvp取消)
不,因为上述原因。
并且,当响应到达时,除了记录之外它将被丢弃。 来自Presenter类中的onRSVPClick()
片段。
.subscribe(response -> {
if (!isViewAttached()) {
return;
}
Log.d("rsvptest", "basic event id:" + response);
getMvpView().hideLoading();
}
要查看更改,您应该以mEventListResponseList
方式更新适配器中的mEventListResponseList
和mAllRSVPEventsList
,并使用来自响应的数据调用它。 另外,不要忘记在该方法中调用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.