关联 ListView 的项目单击后显示 ViewPager 的正确方法是啥?
Posted
技术标签:
【中文标题】关联 ListView 的项目单击后显示 ViewPager 的正确方法是啥?【英文标题】:What's the correct way of displaying ViewPager after associated ListView's item click?关联 ListView 的项目单击后显示 ViewPager 的正确方法是什么? 【发布时间】:2015-11-20 21:29:17 【问题描述】:我是 android 的初学者,因此我为所犯的错误深表歉意,如果有任何建设性的批评,我将不胜感激。
我正在编写一个带有图像 ListView 的基本应用程序,当用户单击列表中的某个项目时,我想在 ViewPager 中显示该图像,用户可以在其中来回滑动以浏览整个图像列表。之后当用户按下后退按钮时,我想切换回 ListView。
我在 MainActivity 中管理业务逻辑,它将 MainActivityFragment 用于 ListView,ImageHolderFragment 用于 ViewPager。
目前的简化代码如下:
@Override
protected void onCreate(final Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mListItems = new ArrayList<>();
mListItemAdapter = new ListItemAdapter(this, R.layout.list_item, R.id.list_item_name, mListItems);
mListView = (ListView) findViewById(R.id.list_view_content);
mListView.setAdapter(mListItemAdapter);
mDeletedListItems = new ArrayList<>();
mViewPager = (ViewPager) getLayoutInflater().inflate(R.layout.image_display, null, true);
mImageAdapter = new ImageAdapter(getSupportFragmentManager(), mListItems);
mViewPager.setAdapter(mImageAdapter);
mViewPager.setOffscreenPageLimit(3);
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener()
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
mViewPager.setCurrentItem(position);
setContentView(mViewPager); // TODO: this is very wrong!
);
loadImages();
noContentText = (TextView) findViewById(R.id.no_content_text);
if (mListItems.isEmpty())
noContentText.setText(R.string.no_images);
else
mImageAdapter.notifyDataSetChanged();
虽然这在某种程度上确实有效,这意味着它可以在单击列表中的项目时显示 ViewPager,但它敲响了警钟有两件事:
我了解到,在同一个班级中第二次调用 setContentView() 几乎是一种罪过。没有人向我解释原因。 在这种情况下,后退按钮不起作用。当它被按下时,应用程序被终止而不是返回到列表视图。我相信这与第一点有关。如果我的想法完全错误,我将不胜感激任何帮助和解释,如果我的情况没有希望,我希望看到 ListView 和 ViewPager 的成功组合以及彼此之间的转换。
【问题讨论】:
【参考方案1】:您的活动已经将R.layout.activity_main
设置为内容视图,它可以正确显示列表视图 - 这就是您定义的该活动的职责。如果我们想更改屏幕上显示的内容,我们应该使用构建块(活动或片段)的不同实例来显示视图寻呼机图像。
至少可以说,想象一下,如果您想将视图更改为第三部分功能或 UI,或者第四部分...维护、扩展和测试将是一场噩梦,因为您没有将功能拆分为可管理的单位。一个视图中需要的字段与另一个视图中需要的字段混合在一起,您的类文件会随着每个视图带来其点击侦听器、回调等而变得越来越大,您还必须覆盖后退按钮以便它执行什么操作你想要 - 这不是 Android 框架旨在帮助你的方式。如果您想在不同的上下文中重用 UI 组件,同时利用框架的活动生命周期回调,该怎么办?这就是引入fragments 的原因。
在您的情况下,列表视图可以继续在您的MainActivity
和您的点击侦听器onItemClick
中运行,您可以开始一个新的活动来保存 viewPager:
Intent i = new Intent(MainActivity.this, MyLargePhotoActivityPager.class);
i.putExtra(KEY_POSITION, position);
// pass the data too
startActivityForResult(i, REQUEST_CODE);
请注意如何将位置作为 int
额外传递给此活动,以便第二个活动很好地将 viewPager 设置为用户单击的位置。我将让您了解如何构建第二个活动并将 ViewPager 放在那里。如果需要,您还可以获得返回按钮功能,前提是您的 launch modes 已相应设置。需要注意的一件事是,当您返回列表视图时,您可能希望从视图寻呼机滚动到该位置,这就是为什么您可以返回 as a result via a request code 的原因。返回的位置可以提供回列表视图。
或者,您可以使用相同的活动,但有两个片段(请参阅上面的链接)并获得相同的结果。事实上,你的一个片段可以存储列表视图,第二个片段可以是全屏DialogFragment
,它存储一个viewPager,就像一个照片库(一些细节here)。
希望这会有所帮助。
【讨论】:
这很有意义,但我正在从第一个屏幕的存储中加载图像以创建带有缩略图的列表,然后我必须在第二个活动以实际显示这些图像,或者有其他方法吗? 您不会真正重做任何工作,因为听起来您需要第二个屏幕中的原始/更大尺寸,因此您必须完全加载不同的图像。你首先是如何加载缩略图的?您可以使用 Glide 之类的东西来填充您的ImageView
,这是每个 ViewPager 插槽中布局的一部分。【参考方案2】:
我读过第二次调用 setContentView() 同班几乎是一种罪过。没有人解释我为什么。
嗯,你大概知道为什么了。
当您使用setContentView()
显示另一个“屏幕”时,您没有适当的后退堆栈。
您还保留对不再可见的视图(如mListView
)的引用,因此在您第二次setContentView()
之后有点“无用”。
还要记住方向变化或您的应用程序进入后台 - 您必须跟踪您的 Activity 所处的状态,如果您有一个 Activity 执行两件不同的事情,则要复杂得多。
您不会因为现在做的事情而被捕,但调试和保持无错误更难。
我建议为您想要做的两件不同的事情使用两个不同的活动,或者使用一个活动和两个片段,来回交换它们。
如果您坚持在一个 Activity 中包含所有内容,则需要覆盖 onBackPressed()
(当用户按下后退按钮时调用)并恢复您的 Activity 的第一个状态(再次setContentView()
,几乎从头开始) .
【讨论】:
感谢您的回答,实际上我尝试的第一件事是覆盖 onBackPressed() 方法,在这种情况下我得到了InflateException: Error inflating class fragment
。我希望仅使用片段来更改视图,但这也不起作用。你说的其他几点也有道理,我还有很多东西要学。以上是关于关联 ListView 的项目单击后显示 ViewPager 的正确方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章
单击 Xamarin.Forms 中的 ListView 项后完整显示详细信息
单击 ListView 上的删除按钮后删除 ListView 上的项目