it-swarm.com.de

Prüfen Sie, ob das Fragment aktuell sichtbar ist oder nicht

Ich weiß, es gibt viele ähnliche Fragen in StackOverflow, aber meine Frage ist etwas anders.

Ich habe eine verschachtelte Hierarchie von Fragmenten wie in der folgenden Struktur:

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

Jetzt möchte ich wissen, ob DFragment dem Benutzer angezeigt wird oder nicht?

Ich habe viele Lösungen von StackOverflow ausprobiert, konnte aber keinen Erfolg erzielen. 

Was ich versucht habe ist:

Ich habe setUserVisibleHint() ausprobiert, aber es gibt true für mehrere DFragment in der obigen Hierarchie zurück, was eine Ursache für ViewPager ist.

Ich habe auch folgende Links ausprobiert: link1 , link2 , link3 und so weiter ... aber keine wirkliche Lösung.

Warten auf Hilfe. Vielen Dank.

UPDATE

Adapterklasse

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

Sie können überprüfen, ob die View, die das Fragment aufgeblasen hat, auf dem Bildschirm des Geräts sichtbar ist:


    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() gibt true zurück, wenn ein Teil der Ansicht auf der Stammebene sichtbar ist.

19
azizbekian

Sie können overridesetUserVisibleHint() in jedem Fragment, in dem Sie prüfen möchten, ob es sichtbar ist, mit einem zusätzlichen Flag versehen. Zum Beispiel

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

Ich hatte ein ähnliches Problem. Einmal musste ich Daten vom Server nur dann in fragment laden, wenn sie sich vor dem Benutzer befanden. Ich habe es wie oben gelöst.

Ich hoffe, es wird auch Ihnen helfen.

4
Geek

versuche dies

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

        }
        else
        {       

        }
    }
4
faisal iqbal

Probieren Sie es aus ..

Die isVisible() fügt eine zusätzliche Sichtbarkeitsüberprüfung hinzu.

    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

Mit der mViewPager.getCurrentItem() -Methode können wir leicht abbilden, welches Fragment jetzt sichtbar ist. Diese Methode liefert den Wert int, anhand dessen wir das aktuelle Fragment finden können.

- Um auf diese Methode zuzugreifen und das Ergebnis zu erhalten, haben wir zwei Möglichkeiten:

  1. erstelle eine Static viewPager-Instanz in Aktivität und benutze sie, wo immer wir wollen
  2. mache wieder viewPager Instanz in Fragment (findViewById())

und mit einer der beiden oben genannten Methoden getCurrentItem() im Fragment, um herauszufinden, welches Fragment jetzt sichtbar ist.

Zum Beispiel,

  1. In MainActivity (Aktivität, die für ViewPager verwendet wird) definieren

public static ViewPager mViewPager;

  • In Fragment, MainActivity.mViewPager.getCurrentItem(), um das aktuelle Fragment abzurufen

Methode, die anzeigt, welches Fragment sichtbar ist:

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) Bei nicht statischer Verwendung

  • erhalte die viewPager Instanz im Fragment durch den folgenden Code,

viewPager=(ViewPager) view.getRootView().findViewById(R.id.container);

und dann

viewPager.getCurrentItem() um den Index abzurufen und das aktuell sichtbare Fragment gemäß der Verwendung zu finden.

3
Nitin Patel

Soweit ich es ausprobiert habe, denke ich, dass dies funktionieren wird Bitte versuchen Sie es und lassen Sie es mich wissen. Tun Sie so etwas in Ihrer Aktivität.


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

Verwenden Sie diese Klasse als Viewpager-Adapter

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

Jetzt in deinem DFragment

 boolean isVisible=false;

        @Override
        public void setMenuVisibility(boolean menuVisible) {
            super.setMenuVisibility(menuVisible);
            isVisible=menuVisible;
        }

        public boolean isFragmentVisible(){
            return isVisible;
        }

Lassen Sie mich wissen, ob es funktioniert, wenn Sie mir nicht den Grund mitteilen.

3
Reyansh Mishra

Die einfachste Sloution könnte ..__ sein. In onCreate Ihres DF fragment speichern Sie eine boolean in preferences. das heißt Key = is_fragment_visible_to_user. Und ändere es in true. Und in onStop oder onDestroy (was auch immer deine Anforderung erfüllt) ändert sich der Wert in false. Damit können Sie dies leicht überprüfen, indem Sie auf den Wert für die Einstellungen zugreifen. Bei mehreren Instanzen können Sie das Tag mit dem anderen Schlüssel speichern. 

2
Nouman Ghaffar

Als ich ein ähnliches Problem hatte, löste ich es mit dieser hackigen Methode, die unter die Haube ging

Fügen Sie in Ihren FragmentPagerAdapter (s) diese Funktion hinzu. 

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

Es ist nicht die eleganteste Lösung, aber solange es funktioniert

VORSICHT

Dies ist eine private Methode innerhalb von ViewPager , die sich jederzeit oder für jede Betriebssystemversion ändern kann.

0
insomniac

Obwohl die Vergangenheit schon so lange her ist, möchte ich mein Programm trotzdem weitergeben, da ich festgestellt habe, dass der Zustand des Fragmentes in der Tat nicht einfach ist. Basierend auf Ihrer Anfrage müssen Sie diese drei Fragen beantworten:

  • So verwenden Sie FragmentPagerAdapter oder FragmentStatePagerAdapter
  • So ermitteln Sie den sichtbaren Status von Fragment
  • Umgang mit dem verschachtelten Fragment

Zuerst habe ich einen Basisadapter definiert, der mir hilft, das Fragment in ViewPager abzurufen. Wenn die Position und der Typ Ihres Fragments in ViewPager änderbar sind, müssen Sie die Methoden public int getItemPosition(Object object) method und public Fragment getItem(int position) verwenden, um die richtige Position zu erhalten.

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

Dann definiere ich ein Basisfragment, um den sichtbaren Zustand zu behandeln. Es gibt jedoch einen kleinen Fehler: Sie müssen denselben Switch-Typ für einen Satz von Fragmenten angeben.

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

}

Übergeben Sie schließlich den untergeordneten Fragment-Status sichtbar im übergeordneten Fragment, wenn er verschachtelt ist.

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

    ...

}

Ich habe Test mit Anhängen/Abnehmen, Anzeigen/Ausblenden und drei Layer ViewPager verschachtelt. Es funktioniert gut. Vielleicht hätte ich mehr testen sollen, aber für mich war es genug.

0
Kilnn
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();
}

ursprünglicher Beitrag