我知道StackOverflow中有很多类似的问题,但我的问题没什么不同。
我有嵌套的Fragments层次结构,如下面的结构:
Activity
|
|
AFragment
|
(ViewPager)
| |
| |
BFragment BFragment .....
|
(ViewPager)
| |
| |
CFragment CFragment ...
|
(ViewPager)
| |
| |
DFragment DFragment ...
现在我想知道DFragment
是否向用户显示?
我尝试了很多来自StackOverflow的解决方案,但无法取得成功。
我尝试的是:
我尝试了setUserVisibleHint()
,但它在上面的层次结构中为多个true
返回了DFragment
,这是ViewPager
我也试过这些链接:link1,link2,link3等等......但没有得到实际解决方案。
等待帮助。谢谢。
更新
适配器类
class ViewPagerAdapter extends FragmentPagerAdapter {
private final List<Fragment> mFragmentList = new ArrayList<>();
private final List<String> mFragmentTitleList = new ArrayList<>();
public ViewPagerAdapter(FragmentManager manager) {
super(manager);
}
@Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
@Override
public int getCount() {
return mFragmentList.size();
}
public void addFragment(Fragment fragment, String title) {
mFragmentList.add(fragment);
mFragmentTitleList.add(title);
}
@Override
public CharSequence getPageTitle(int position) {
return mFragmentTitleList.get(position);
}
}
答案 0 :(得分:20)
您可以检查设备的屏幕上是否显示了View
充气片段:
Fragment fragment = ... // retrieve from `ViewPager`'s adapter.
View fragmentRootView = fragment.getView();
if (fragmentRootView != null && fragmentRootView.getGlobalVisibleRect(new Rect())) {
// fragment is visible
} else {
// fragment is not visible
}
如果视图的某个部分在根级别可见,则 getGlobalVisibleRect()
将返回true
。
答案 1 :(得分:4)
试试这个
@Override
public void setMenuVisibility(final boolean visible) {
super.setMenuVisibility(visible);
if (visible) {
}
else
{
}
}
答案 2 :(得分:4)
您可以在每个片段中使用override
setUserVisibleHint()
检查其是否可见并带有其他标记。例如
boolean isVisited = false;
@Override
public void setUserVisibleHint(boolean isVisibleToUser)
{
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser && !isVisited )
{
isVisited = true;
}
else if(isVisited)
{
// this fragment is already in front of user
}
}
我遇到了类似的问题。一旦我需要将数据从服务器加载到fragment
,只有当它在用户面前时。我解决了上面的问题。
希望它也会对你有帮助。
答案 3 :(得分:3)
试一试..
isVisible()
添加了额外的可见性检查层。
ViewPager viewPager=(ViewPager)findViewById(R.id.view_pager);
final Fragment[] fragments={new DFragment(),new MyFragment()}; //add all the other fragment objects present in the view pager......
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
if(fragments[position].isVisible()){
//Cool stuff to do.
}
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
答案 4 :(得分:3)
据我所知,我觉得这会有效请尝试让我知道。 在你的活动中做这样的事情。
public boolean isFragmentVisible(SwipeAdapter swipeAdapter) {
SwipeAdapter swipeAdapterA = fragmentA.getViewPagerAdapter();
BFragment bFragment = (BFragment) swipeAdapterA.getFragment(0);
if (bFragment != null) {
SwipeAdapter swipeAdapterB = bFragment.getViewPagerAdapter();
CFragment cFragment = (CFragment) swipeAdapterA.getFragment(0);
if (cFragment != null) {
SwipeAdapter swipeAdapterC = cFragment.getViewPagerAdapter();
DFragment dFragment = (DFragment) swipeAdapterA.getFragment(0);
if (dFragment != null) {
return dFragment.isFragmentVisible();
}
}
}
return false;
}
将此类用作viewpager适配器
class SwipeAdapter extends FragmentPagerAdapter {
private Map<Integer, String> mFragmentTags;
private FragmentManager mFragmentManager;
private String mPagetile[];
public SwipeAdapter(FragmentManager fm, Context context) {
super(fm);
mPagetile = context.getResources().getStringArray(R.array.pageTitle);
mFragmentManager = fm;
mFragmentTags = new HashMap<>();
}
@Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return new "Your_fragment";
default:
break;
}
return null;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
Object obj = super.instantiateItem(container, position);
if (obj instanceof Fragment) {
Fragment f = (Fragment) obj;
String tag = f.getTag();
mFragmentTags.put(position, tag);
}
return obj;
}
public Fragment getFragment(int position) {
String tag = mFragmentTags.get(position);
if (tag == null)
return null;
return mFragmentManager.findFragmentByTag(tag);
}
@Override
public CharSequence getPageTitle(int position) {
return mPagetile[position];
}
@Override
public int getCount() {
return "Number of fragments";
}
}
现在在您的DFragment中执行此操作
boolean isVisible=false;
@Override
public void setMenuVisibility(boolean menuVisible) {
super.setMenuVisibility(menuVisible);
isVisible=menuVisible;
}
public boolean isFragmentVisible(){
return isVisible;
}
如果不让我知道原因,请告诉我是否有效。
答案 5 :(得分:3)
我们可以使用mViewPager.getCurrentItem()
方法轻松映射现在可见的片段。此方法提供int
值编号,我们可以从中找到当前片段。
- 对于访问并获得此方法结果,我们有两个选项:
Static
viewPager实例,并在我们的任何地方使用
想viewPager
)findViewById()
个实例
醇>
并使用片段中的两个方法getCurrentItem()
中的一个来查找现在可见的片段。
例如,
public static ViewPager mViewPager;
MainActivity.mViewPager.getCurrentItem()
获取当前片段此外,显示哪个片段可见的方法:
public void whichIsVisible() {
String msg = "";
int curFragNo = MainActivity.mViewPager.getCurrentItem();
switch (curFragNo) {
case 0:
msg = "AFragment is visible.";
break;
case 1:
msg = "BFragment is visible.";
break;
case 2:
msg = "CFragment is visible.";
break;
case 3:
msg = "DFragment is visible.";
break;
}
Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();
}
(2)对于非静态使用,
viewPager
实例, viewPager=(ViewPager) view.getRootView().findViewById(R.id.container);
然后
viewPager.getCurrentItem()
获取索引并根据用途查找当前可见的片段。
答案 6 :(得分:2)
最简单的诽谤可能是。
在onCreate
商店的DF fragment
boolean
中preferences
。即Key = is_fragment_visible_to_user
。并将其更改为true
。
在onStop
或onDestroy
(根据您的要求填写)更改时,它的值为false
。有了这个,您可以通过访问首选项值轻松检查它。在多个实例的情况下,您可以使用另一个键存储标记。
答案 7 :(得分:0)
当我遇到类似的问题时,我通过使用这种hacky方法解决了这个问题,比如
在FragmentPagerAdapter
(s)内添加此功能。
public Fragment getActiveFragment(ViewPager container, int position) {
String name = makeFragmentName(container.getId(), position);
return fm.findFragmentByTag(name);
}
private static String makeFragmentName(int viewId, int index) {
return "android:switcher:" + viewId + ":" + index;
}
这不是最优雅的解决方案,只要它有效
<强>注意强>
这是 ViewPager 内部的私有方法,可随时更改或任何操作系统版本。
答案 8 :(得分:0)
首先,我定义了一个基础适配器帮助我在ViewPager中获取片段。如果您在ViewPager中片段的位置和类型可以更改,则必须使用public int getItemPosition(Object object) method
和public Fragment getItem(int position)
方法来获得正确的位置。
/**
* Created by Kilnn on 2017/7/12.
* A abstract FragmentStatePagerAdapter which hold the fragment reference.
*/
public abstract class SmartFragmentStatePagerAdapter extends FragmentStatePagerAdapter {
private SparseArray<WeakReference<Fragment>> registeredFragments = new SparseArray<>();
public SmartFragmentStatePagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment fragment = (Fragment) super.instantiateItem(container, position);
registeredFragments.put(position, new WeakReference<>(fragment));
return fragment;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
registeredFragments.remove(position);
super.destroyItem(container, position, object);
}
public Fragment getRegisteredFragment(int position) {
WeakReference<Fragment> reference = registeredFragments.get(position);
return reference != null ? reference.get() : null;
}
}
然后,我定义了一个基本片段来处理可见状态。但是有一个小缺陷是你必须为一组片段指定相同的开关类型。
import android.support.annotation.IntDef;
import android.support.v4.app.Fragment;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* Created by Kilnn on 2017/7/12.
* A smart fragment know itself's visible state.
*/
public abstract class SmartFragment extends Fragment {
private boolean isFragmentVisible;
@Override
public void onResume() {
super.onResume();
int switchType = getSwitchType();
if (switchType == ATTACH_DETACH) {
notifyOnFragmentVisible();
} else if (switchType == SHOW_HIDE) {
if (!isHidden()) {
notifyOnFragmentVisible();
}
} else if (switchType == VIEW_PAGER) {
//If the parent fragment exist and hidden when activity destroy,
//when the activity restore, The parent Fragment will be restore to hidden state.
//And the sub Fragment which in ViewPager is also be restored, and the onResumed() method will callback.
//And The sub Fragment's getUserVisibleHint() method will return true if it is in active position.
//So we need to judge the parent Fragment visible state.
if (getUserVisibleHint() && isParentFragmentVisible()) {
notifyOnFragmentVisible();
}
}
}
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
int switchType = getSwitchType();
if (switchType == VIEW_PAGER) {
if (isVisibleToUser) {
//If ViewPager in ViewPager , the sub ViewPager will call setUserVisibleHint before onResume
if (isResumed()) {
notifyOnFragmentVisible();
}
} else {
notifyOnFragmentInvisible();
}
}
}
@Override
public void onHiddenChanged(boolean hidden) {
super.onHiddenChanged(hidden);
int switchType = getSwitchType();
if (switchType == SHOW_HIDE) {
if (hidden) {
notifyOnFragmentInvisible();
} else {
//Just judge for safe
if (isResumed()) {
notifyOnFragmentVisible();
}
}
}
}
@Override
public void onPause() {
super.onPause();
notifyOnFragmentInvisible();
}
private boolean isParentFragmentVisible() {
Fragment parent = getParentFragment();
if (parent == null) return true;
if (parent instanceof SmartFragment) {
return ((SmartFragment) parent).isFragmentVisible();
} else {
//TODO May be can't get the correct visible state if parent Fragment is not SmartFragment
return parent.isVisible();
}
}
public boolean isFragmentVisible() {
// Don't judge the state of the parent fragment,
// because if the parent fragment visible state changes,
// you must take the initiative to change the state of the sub fragment
// return isFragmentVisible && isParentFragmentVisible();
return isFragmentVisible;
}
public void notifyOnFragmentVisible() {
if (!isFragmentVisible) {
onFragmentVisible();
isFragmentVisible = true;
}
}
public void notifyOnFragmentInvisible() {
if (isFragmentVisible) {
onFragmentInvisible();
isFragmentVisible = false;
}
}
/**
* If this method callback, the Fragment must be resumed.
*/
public void onFragmentVisible() {
}
/**
* If this method callback, the Fragment maybe is resumed or in onPause().
*/
public void onFragmentInvisible() {
}
/**
* Fragments switch with attach/detach(replace)
*/
public static final int ATTACH_DETACH = 0;
/**
* Fragments switch with show/hide
*/
public static final int SHOW_HIDE = 1;
/**
* Fragments manage by view pager
*/
public static final int VIEW_PAGER = 2;
@Retention(RetentionPolicy.SOURCE)
@IntDef({ATTACH_DETACH, SHOW_HIDE, VIEW_PAGER})
public @interface SwitchType {
}
@SwitchType
public abstract int getSwitchType();
}
最后,如果嵌套使用,请在父片段中传递子片段可见状态。
public class ParentFragment extends SmartFragment{
....
@Override
public void onFragmentVisible() {
super.onFragmentVisible();
SmartFragment fragment = (SmartFragment) mAdapter.getRegisteredFragment(mViewPager.getCurrentItem());
if (fragment != null) {
fragment.notifyOnFragmentVisible();
}
}
@Override
public void onFragmentInvisible() {
super.onFragmentInvisible();
SmartFragment fragment = (SmartFragment) mAdapter.getRegisteredFragment(mViewPager.getCurrentItem());
if (fragment != null) {
fragment.notifyOnFragmentInvisible();
}
}
...
}
我测试了附加/分离,显示/隐藏和嵌套的三层ViewPager。它工作正常。也许我应该做更多的测试,但对我来说就足够了。
答案 9 :(得分:0)
public static boolean isFragmentVisible(Fragment fragment) {
Activity activity = fragment.getActivity();
View focusedView = fragment.getView().findFocus();
return activity != null
&& focusedView != null
&& focusedView == activity.getWindow().getDecorView().findFocus();
}