web-dev-qa-db-ja.com

フラグメントが現在表示されているかどうかを確認します

StackOverflowには似たような質問がたくさんありますが、私の質問は少し違います。

私は以下の構造のようなフラグメントの階層をネストしています:

_                                  Activity
                                     |
                                     |
                                 AFragment
                                     |
                                (ViewPager)
                                 |       |         
                                 |       |         
                         BFragment       BFragment  .....
                            |                       
                       (ViewPager)                       
                        |       |                         
                        |       |                         
                 CFragment     CFragment  ...
                     |
                (ViewPager)                       
                  |     |                              
                  |     |                        
           DFragment   DFragment ...
_

今、私はDFragmentがユーザーに表示されているかどうかを知りたいですか?

StackOverflowから多くのソリューションを試しましたが、成功しませんでした。

私が試したのは:

setUserVisibleHint()を試しましたが、trueの原因である上記の階層の複数のDFragmentに対してViewPagerを返します

私はこれらのリンクからも試しました: link1link2link など...しかし、実際の解決策は得られませんでした。

助けを待っています。ありがとうございました。

[〜#〜] update [〜#〜]

アダプタクラス

_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);
        }
    }
_
15
Vikash Parajuli

フラグメントが膨らんだ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を返します。

23
azizbekian

フラグが表示されているかどうかを確認する各フラグメントで、追加フラグを使用してoverridesetUserVisibleHint()できます。例として

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に読み込む必要があったのは、ユーザーの目の前にあったときだけでした。上記のように解決しました。

それがあなたにも役立つことを願っています。

4
Geek

これを試して

@Override
    public void setMenuVisibility(final boolean visible) {
        super.setMenuVisibility(visible);
        if (visible) {

        }
        else
        {       

        }
    }
4
faisal iqbal

これを試してみてください。

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) {

        }
    });
3
Darshan Miskin

mViewPager.getCurrentItem()メソッドを使用して、どのフラグメントが表示されるかを簡単にマッピングできます。このメソッドは、現在のフラグメントを見つけることができるint値の番号を提供します。

-このメソッドの結果にアクセスして取得するには、2つのオプションがあります。

  1. アクティビティでStatic viewPagerインスタンスを作成し、好きな場所で使用します
  2. 再びフラグメントにviewPagerインスタンスを作成します(findViewById()

上記の2つのメソッドgetCurrentItem()のいずれかをfragmentで使用して、現在表示されているフラグメントを見つけます。

例えば、

  1. MainActivity(ViewPagerに使用されるアクティビティ)で定義します

_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()を使用して、インデックスを取得し、使用状況に応じて現在表示されているフラグメントを見つけます。

3
Nitin Patel

私が試した限りでは、これはうまくいくと思います。試して、私に知らせてください。アクティビティでこのようなことをしてください。


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;
    }

ビューページャーアダプターとしてこのクラスを使用します

  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;
        }

理由がわからなければ、うまくいったかどうか教えてください。

3
Reyansh Mishra

最も単純なスラウションは次のとおりです。 DF fragmentonCreatebooleanpreferencesを保存します。すなわちKey = is_fragment_visible_to_user。そして、それをtrueに変更します。 onStopまたはonDestroy(要件を満たす方)の変更では、値はfalseになります。これにより、設定値にアクセスして簡単に確認できます。複数のインスタンスの場合、タグを別のキーで保存できます。

2
Nouman Ghaffar
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();
}

元の投稿

私が同様の問題を抱えていたとき、私はこのハッキーな方法を使用して解決しました

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;
    }

それは最も優雅な解決策ではありませんが、機能する限り

[〜#〜] caution [〜#〜]

これはViewPager内部のプライベートメソッドであり、いつでも、またはOSバージョンごとに変更できます。

0
insomniac

長い間過去ですが、私はまだ私のプログラムを提供したいのですが、フラグメントの目に見える状態を取得することは確かに簡単ではないことがわかったからです。リクエストに基づいて、次の3つの質問を解決する必要があります。

  • FragmentPagerAdapterまたはFragmentStatePagerAdapterの使用方法
  • フラグメントの可視状態を判断する方法
  • フラグメントがネストされている場合の処理​​方法

最初に、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;
    }
}

そのとき、私は目に見える状態を処理するためにベースフラグメントを定義します。しかし、小さな欠陥があるのは、フラグメントの1つのセットに対して同じスイッチタイプを指定する必要があるということです。

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();

}

最後に、ネストされた使用の場合、親FragmentでサブFragment表示状態を渡します。

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の3つのレイヤーをネストしたテストがあります。それはうまく動作します。おそらくもっとテストを行うべきだったかもしれませんが、私にとってはそれで十分でした。

0
Kilnn