【发布时间】:2013-05-20 14:46:54
【问题描述】:
我正在使用支持库 v4,我的问题是,如何知道片段是否可见?以及如何更改片段中膨胀的布局的属性?提前致谢。
---编辑---
我正在使用带有 FragmentActivity 的 android 开发者教程中的片段
【问题讨论】:
我正在使用支持库 v4,我的问题是,如何知道片段是否可见?以及如何更改片段中膨胀的布局的属性?提前致谢。
---编辑---
我正在使用带有 FragmentActivity 的 android 开发者教程中的片段
【问题讨论】:
您应该能够做到以下几点:
MyFragmentClass test = (MyFragmentClass) getSupportFragmentManager().findFragmentByTag("testID");
if (test != null && test.isVisible()) {
//DO STUFF
}
else {
//Whatever
}
【讨论】:
test != null && test.isVisible(),否则当test为空时会抛出NullPointerException
if (MyFragmentClass.this.isVisible())即可。
FragmentPagerAdapter在这个片段中添加更多片段呢?
isVisible() 和 isAdded() 在创建 Fragment 后立即返回 true,甚至实际上不可见。唯一有效的解决方案是:
if (isAdded() && isVisible() && getUserVisibleHint()) {
// ... do your thing
}
这可以完成工作。期间。
注意: getUserVisibleHint() 现在已弃用。小心点。
【讨论】:
如果您想知道何时使用正在查看您应该使用的片段
yourFragment.isResumed()
而不是
yourFragment.isVisible()
首先isVisible() 已经检查了isAdded(),因此无需同时调用两者。其次,这两者都不是意味着用户实际上正在查看您的片段。只有isResumed() 确保您的片段在用户面前,并且用户可以与它进行交互,如果这就是您要查找的内容。
【讨论】:
你可以试试这个方法:
Fragment currentFragment = getFragmentManager().findFragmentById(R.id.fragment_container);
或
Fragment currentFragment = getSupportFragmentManager().findFragmentById(R.id.fragment_container);
在这个 if 中,你检查 currentFragment 是否是 YourFragment 的实例
if (currentFragment instanceof YourFragment) {
Log.v(TAG, "your Fragment is Visible");
}
【讨论】:
您可以像这样覆盖 setMenuVisibility:
@Override
public void setMenuVisibility(final boolean visible) {
if (visible) {
//Do your stuff here
}
super.setMenuVisibility(visible);
}
【讨论】:
getUserVisibleHint() 只有当片段在视图上并且可见时才为真
【讨论】:
getUserVisibleHint() 是真的
需要注意的一点是,isVisible() 返回 当前 片段的可见状态。支持库中存在一个问题,如果您有嵌套片段,并且隐藏了父片段(因此隐藏了所有子片段),子片段仍然说它是可见的。
isVisible() 是最终的,所以很遗憾不能覆盖。我的解决方法是创建一个所有片段都扩展的BaseFragment 类,然后创建一个像这样的方法:
public boolean getIsVisible()
{
if (getParentFragment() != null && getParentFragment() instanceof BaseFragment)
{
return isVisible() && ((BaseFragment) getParentFragment()).getIsVisible();
}
else
{
return isVisible();
}
}
我之所以选择isVisible() && ((BaseFragment) getParentFragment()).getIsVisible();,是因为如果隐藏了任何个父片段,我们希望返回 false。
这似乎对我有用。
【讨论】:
ArticleFragment articleFrag = (ArticleFragment)
getSupportFragmentManager().findFragmentById(R.id.article_fragment);
if (articleFrag != null && articleFrag.isVisible()) {
// Call a method in the ArticleFragment to update its content
articleFrag.updateArticleView(position);
}
见http://developer.android.com/training/basics/fragments/communicating.html
【讨论】:
如果你只有一个Fragment,试试这个
if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
//TODO: Your Code Here
}
【讨论】:
在这里补充一些我经历过的信息:
fragment.isVisible 仅在您使用 replaceFragment() 时才起作用 (true/false),否则如果您使用 addFragment(),isVisible 总是返回 true,无论该片段是否位于其他片段的后面。
【讨论】:
以上解决方案都不适合我。 然而,以下内容就像一个魅力:-
override fun setUserVisibleHint(isVisibleToUser: Boolean)
【讨论】:
万一您使用带有 ViewPager (TabLayout) 的 Fragment 布局,您可以通过 ViewPager.getCurrentItem() 方法轻松请求当前(前面的)片段。它会给你页面索引。
从页面索引到片段[类]的映射应该很容易,因为您已经在 FragmentPagerAdapter 派生的适配器中进行了映射。
int i = pager.getCurrentItem();
您可以通过
注册页面更改通知ViewPager pager = (ViewPager) findViewById(R.id.container);
pager.addOnPageChangeListener(this);
当然你必须实现接口ViewPager.OnPageChangeListener
public class MainActivity
extends AppCompatActivity
implements ViewPager.OnPageChangeListener
{
public void onPageSelected (int position)
{
// we get notified here when user scrolls/switches Fragment in ViewPager -- so
// we know which one is in front.
Toast toast = Toast.makeText(this, "current page " + String.valueOf(position), Toast.LENGTH_LONG);
toast.show();
}
public void onPageScrolled (int position, float positionOffset, int positionOffsetPixels) {
}
public void onPageScrollStateChanged (int state) {
}
}
我在这里的回答可能有点离题。但作为 Android 应用程序的新手,我正好面临这个问题,并没有在任何地方找到答案。所以制定了上述解决方案并将其发布在这里 - 也许有人觉得它有用。
编辑:您可以将此方法与片段订阅的 LiveData 结合使用。此外,如果你给 Fragments 一个页面索引作为构造函数参数,你可以在你的 Fragment 类中创建一个简单的 amIvisible() 函数。
在 MainActivity 中:
private final MutableLiveData<Integer> current_page_ld = new MutableLiveData<>();
public LiveData<Integer> getCurrentPageIdx() { return current_page_ld; }
public void onPageSelected(int position) {
current_page_ld.setValue(position);
}
public class MyPagerAdapter extends FragmentPagerAdapter
{
public Fragment getItem(int position) {
// getItem is called to instantiate the fragment for the given page: But only on first
// creation -- not on restore state !!!
// see: https://stackoverflow.com/a/35677363/3290848
switch (position) {
case 0:
return MyFragment.newInstance(0);
case 1:
return OtherFragment.newInstance(1);
case 2:
return XYFragment.newInstance(2);
}
return null;
}
}
在片段中:
public static MyFragment newInstance(int index) {
MyFragment fragment = new MyFragment();
Bundle args = new Bundle();
args.putInt("idx", index);
fragment.setArguments(args);
return fragment;
}
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mPageIndex = getArguments().getInt(ARG_PARAM1);
}
...
}
public void onAttach(Context context)
{
super.onAttach(context);
MyActivity mActivity = (MyActivity)context;
mActivity.getCurrentPageIdx().observe(this, new Observer<Integer>() {
@Override
public void onChanged(Integer data) {
if (data == mPageIndex) {
// have focus
} else {
// not in front
}
}
});
}
【讨论】:
getUserVisibleHint 现在已弃用,当另一个片段在它前面 added 时,我遇到了 isVisible 为真的问题。这会使用其视图检测片段在后台堆栈上的可见性。如果您的问题与后台堆栈上的其他片段有关,这可能会有所帮助。
用于检测屏幕上是否正在显示视图的视图扩展:(另请参阅How can you tell if a View is visible on screen in Android?)
fun View.isVisibleOnScreen(): Boolean {
if (!isShown) return false
val actualPosition = Rect().also { getGlobalVisibleRect(it) }
val screenWidth = Resources.getSystem().displayMetrics.widthPixels
val screenHeight = Resources.getSystem().displayMetrics.heightPixels
val screen = Rect(0, 0, screenWidth, screenHeight)
return Rect.intersects(actualPosition, screen)
}
然后从片段中定义一个回栈监听器,观察栈顶的片段(最后添加的那个)
fun Fragment.setOnFragmentStackVisibilityListener(onVisible: () -> Unit) {
val renderDelayMillis = 300L
parentFragmentManager.addOnBackStackChangedListener {
Handler(Looper.getMainLooper()).postDelayed({
if (isAdded) {
val topStackFragment = parentFragmentManager.fragments[parentFragmentManager.fragments.size - 1]
if (topStackFragment.view == view && isVisible && view!!.isVisibleOnScreen()) {
onVisible.invoke()
}
}
}, renderDelayMillis)
}
}
在视图准备好之前调用返回堆栈侦听器,因此需要任意小的延迟。当视图可见时调用 lambda。
【讨论】: