Android - 从 pageView 中删除对象会导致空白
Posted
技术标签:
【中文标题】Android - 从 pageView 中删除对象会导致空白【英文标题】:Android - removing Object from pageView results in blank space 【发布时间】:2020-10-26 16:14:28 【问题描述】:我即将编写一个应用程序来控制房子周围的一些基于 LED 的小工具。为了在一个活动上拥有多个设备,我使用了带有视图适配器的页面视图,以便能够在链接的设备之间进行选择。目前,我坚持从容器中删除视图。一旦我删除视图,它就会消失,但会在我的 ViewPager 中留下一个空白空间,如下图所示。我尝试了其他用户建议的所有内容,例如返回
POSITION_NONE
覆盖时
getItemPosition
方法。我为您提供了我的 pageViewAdapter 的代码。我希望有人可以提出解决该问题的方法。我被困在这里了。
package com.example.fabsinnenraumgestaltung;
import android.content.DialogInterface;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.cardview.widget.CardView;
import androidx.viewpager.widget.PagerAdapter;
import androidx.viewpager.widget.ViewPager;
import java.util.ArrayList;
import java.util.List;
public class CardPagerAdapter extends PagerAdapter implements CardAdapter
ViewPager viewPager;
MainActivity mainActivity;
private List<CardView> mViews;
private List<CardItem> mData;
private float mBaseElevation;
public CardPagerAdapter(MainActivity mainActivity, ViewPager viewPager)
mData = new ArrayList<>();
mViews = new ArrayList<>();
this.mainActivity = mainActivity;
this.viewPager = viewPager;
public void addCardItem(CardItem item)
mViews.add(null);
mData.add(item);
public float getBaseElevation()
return mBaseElevation;
@Override
public CardView getCardViewAt(int position)
return mViews.get(position);
@Override
public int getCount()
return mData.size();
@Override
public boolean isViewFromObject(View view, Object object)
return view == object;
@Override
public void destroyItem(ViewGroup container, int position, Object object)
container.removeView((View) object);
mData.set(position, null);
mViews.set(position, null);
notifyDataSetChanged();
@Override
public void notifyDataSetChanged()
super.notifyDataSetChanged();
@Override
public int getItemPosition(@NonNull Object object)
return super.getItemPosition(object);
@Override
public Object instantiateItem(ViewGroup container, int position)
Button deleteButton;
Button editButton;
View view = LayoutInflater.from(container.getContext())
.inflate(R.layout.device_card_layout, container, false);
deleteButton = view.findViewById(R.id.deleteButton);
editButton = view.findViewById(R.id.editButton);
deleteButton.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View view)
System.out.println("delete");
deleteCardOperation(viewPager.getCurrentItem(), container);
);
editButton.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View view)
System.out.println("edit");
int currentCard = viewPager.getCurrentItem();
);
container.addView(view);
bind(mData.get(position), view);
CardView cardView = (CardView) view.findViewById(R.id.itemCard);
if (mBaseElevation == 0)
mBaseElevation = cardView.getCardElevation();
cardView.setMaxCardElevation(mBaseElevation * MAX_ELEVATION_FACTOR);
mViews.set(position, cardView);
return view;
private void bind(CardItem item, View view)
TextView titleTextView = (TextView) view.findViewById(R.id.itemText);
TextView ipTextView = (TextView) view.findViewById(R.id.itemIPAdress);
TextView statusView = (TextView) view.findViewById(R.id.itemActiveStatus);
titleTextView.setText(item.getName());
ipTextView.setText(item.getIp());
statusView.setText(item.getStatus());
private void deleteCardOperation(int cardIndicator, ViewGroup desV)
CardItem x = mData.get(cardIndicator);
AlertDialog.Builder builder = new AlertDialog.Builder(mainActivity, android.R.style.Theme_Material_Dialog_Alert);
builder.setTitle("Confirm");
builder.setMessage("Are you sure you want to delete this device: "+ x.getName() + " ?");
builder.setPositiveButton("YES", new DialogInterface.OnClickListener()
public void onClick(DialogInterface dialog, int which)
destroyItem(desV, cardIndicator, getCardViewAt(cardIndicator));
dialog.dismiss();
);
builder.setNegativeButton("NO", new DialogInterface.OnClickListener()
@Override
public void onClick(DialogInterface dialog, int which)
// Do nothing
dialog.dismiss();
);
AlertDialog alert = builder.create();
alert.show();
private void editCard()
我真的希望你能提供帮助。谢谢。
第一次编辑:
我按照 Michiel 的建议编辑了我的代码。我现在调用 deleteCardItem() 方法从我的数据集中删除数据,如下所示。
public void deleteCardItem(int position)
mData.remove(position);
notifyDataSetChanged();
在调用 notifyDatasetChanged 后,系统接管并调用 getItemPosition()。我已经按照 Michiel 的建议编辑了这个方法。
@Override
public int getItemPosition(@NonNull Object object)
//return super.getItemPosition(object);
int position = mData.indexOf(object);
if(position == -1)
return POSITION_NONE;
else
return position;
现在的问题是,我无法将给定的“对象”与任何数据集进行比较,因为“对象”是一个视图对象,而 mData 是我的 Arraylist 又名数据集。这导致我的应用程序出现异常行为。 卡不会再消失了。显示,但数据被删除。 我将不胜感激。
【问题讨论】:
【参考方案1】:要完全销毁视图本身,您应该尝试像这样编写destroyItem
:
@Override
public void destroyItem(ViewGroup container, int position, Object object)
container.removeView((View) object);
mViews.set(position, null);
所以 View 对象被完全销毁。
并尝试在deleteCardItem
中将View设置为null
@Override
public void deleteCardItem(int position)
mData.remove(position);
mViews.set(position, null);
notifyDataSetChanged();
并且还尝试搜索视图而不是 getItemPosition
中的数据。
@Override
public int getItemPosition(@NonNull Object object)
int position = mViews.indexOf(object);
if(position == -1)
return POSITION_NONE;
else
return position;
在那之后,你就再也看不到它们了
【讨论】:
我尝试实施您的解决方案。非常感谢,这对我来说效果很好。这似乎和我想的一样。【参考方案2】:我主要看到三个问题。首先,您会看到一个空白区域,因为该项目没有被删除;相反,它被设置为空。当在destroyItem()
中调用mData.set(position, null);
时,结果数组将为[(CardItem), null, (CardView)]
。这个数组的大小还是3。解决方法:调用mData.remove(position)
。
其次,调用@Override
注解的所有函数是PagerAdapter
的职责。当您调用notifyDatasetChanged()
时,它将调用destroyItem()
。你应该改变mData
,打电话给notifyDatasetChanged()
,让PagerAdapter
做它的工作。它将删除视图本身并为您调用destroyItem()
,因此您可以进行额外的清理,例如从mView
中删除视图。
第三,如果这只是一个一次性的项目,您可以保留它。但是,如果这是一个长期项目,您可以研究 fi。 SOLID 或其他设计原则。一个例子:你的 PagerAdapter 应该做一件事,而且只做一件事。它应该只将您的数据集 mData 与您的视图连接,知道它还处理更新 mData、显示对话框等。另一个例子:你对 MainActivity 的引用可以用 Context 代替;该代码仍然可以工作,但可以在其他活动或片段中使用而无需任何额外工作。
TL;DR:
// This is called by the PagerAdapter itself
@Override
public void destroyItem(ViewGroup container, int position, Object object)
mViews.remove(position);
// Call this when the user taps yes
private void deletePage(int position)
mData.remove(position);
notifyDataSetChanged();
【讨论】:
感谢您的大力解释。它只是让我明白,destroyItem() 方法是由 notifyDatasetChanged() 调用的。我只是按照你建议的方式实现了这些东西,但这导致了 View 的一个非常奇怪的行为。我试图解释。该卡不再被删除。它仍然显示。我只是在 destroyItem() 方法上使用断点调试了整个事情,并注意到当我调用 notifyDatasetChanged() 时没有调用该方法。 我注意到另一个奇怪的行为。数据实际上被删除,但视图没有。卡片都在那里,但我无法滚动到最后一张。我认为实际上没有调用 destroyItem() 方法是否正确? 我发现,只有当 getItemPosition() 方法返回 POSITION_NONE 时,才会调用 destroyItem() 方法。如果它返回一个对象,destroyItem() 将不会被调用。问题是,这完全没有发生。我只从 getItemPosition 方法中取回对象。我现在的问题是我如何才能完全改变它。文档说,“super.getItemPosition(object)”通常会返回一个对象,或者实际上是 null。但就我而言,它似乎不起作用。你对我有什么进一步的建议可以解决这个问题吗?或者任何想法也可能是问题? 你是对的。解决方案是自己实现getItemPosition()
,例如:`int position = mData.indexOf(object);如果(位置 == -1)返回 POSITION_NONE;否则返回位置;
目前我试图弄清楚如何实施您的解决方案。如果我猜对了,我应该将数据与视图进行比较以识别缺失的内容,然后返回 -1 以删除流程中的相应视图。由于“对象”会给您一个 CardView 对象,而您无法将 mData 与之比较,因此该操作将始终返回错误结果。因为我无法将视图对象与“自定义”对象进行比较,所以此操作将失败并且 `int position = mData.indexOf(object);每张卡总是返回-1。这会导致异常。我必须先解决这个问题。以上是关于Android - 从 pageView 中删除对象会导致空白的主要内容,如果未能解决你的问题,请参考以下文章
Android - 新的 BottomNavigationBar 中的 PageView - 防止重新加载片段