Run code when user “swipes out” of viewpager fragm

2019-07-07 08:17发布

问题:

I need to detect when the user swipes in and out from one of my fragments, I tried onPause but it seems the app isn't paused when swiping to the adjacent screen (it's destroyed when moving two sereens away from it). If possible I want to do it from the fragment itself since I'm changing fragments dynamically and I some code will only be useful if a certain fragment is present.

Is it possible to do this? How can I detect the swipe "out" (if possible from the fragment itself)?


EDIT:

I tried using setUserVisibleHint on a Fragment which seems like the best way to do this, however it never gets called. I'm using API level 19, I'm not sure what's missing:

import android.app.Fragment;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;


public class Contacts extends Fragment {
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            View view = inflater.inflate(R.layout.fragment_screen_contacts, container, false);
            return view;
        }


    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        Log.d("MyFragment", "This never shows up.");
        Toast.makeText(getActivity(), "Neither does this", Toast.LENGTH_LONG).show();
    }
}

回答1:

You can use ViewPager#setOnPageChangeListener() for this.

viewPager.setOnPageChangeListener(new OnPageChangeListener() {

        ...

        @Override
        public void onPageSelected(int position) {
            // do what you want here, for example
            if (position != 3) {
                ...
            }
        }

});

Edit:

If you want the logic to be inside the Fragments themselves, here's one way to do it: add a method onFragmentExited() or something to your subclass. Put the logic in there. Then, inside the OnPageChangeListener, call that method. For example:

viewPager.setOnPageChangeListener(new OnPageChangeListener() {

     int lastPosition;
     @Override
     public void onPageSelected(int position) {
            MyInterface fragment = (MyInterface)mPagerAdapter.instantiateItem(viewPager, lastPosition);
            if (fragment != null) {
                fragment.onFragmentExited();
            }
            /* If you want to notify the fragment being focused
            fragment = (MiniApp)mPagerAdapter.instantiateItem(viewPager, position);
            if (fragment != null) {
                fragment.onFragmentEntered();
            } */
            lastPosition = position;
     }                      
});

The adapter.getFragment(position) depends whatever adapter/structure you're using to store your fragments.



回答2:

If you also are interested in more cases of the end of the lifecycle of the fragment, not only swiping it out, you could use this answer : How to determine when Fragment becomes visible in ViewPager



回答3:

As already stated and tested in the liked answers, you don't know which fragment has disappeared, but with a little of Java, you can know exactly which fragment is the new (and what position it has in your adapter. If you store the "last visible fragment position" you can compare it with the new position and determine which was the last visible before the current (the user can swipe left or right!).

The Java Secret… is to define an Interface, use your adapter's getItemAt(pos), use an OnPageChangeListener() on the ViewPager and combine all three. Also make your Fragments implement the interface so you can use the ViewPagerAdatper to get the Fragment and call (yourInterface).youHaveBeenHidden(); for example.

If you want to know when the page is being swept, you will have to use the onPageScrolled(int position, float positionOffset, int positionOffsetPixels) method of the page change listener and do your math there (bear in mind that this will be called very ofter as the user scrolls, since you get an offset in pixels, which, as you can imagine grows fast).

Update Have you tried…

public void onHiddenChanged (boolean hidden)

Added in API level 11
Called when the hidden state (as returned by isHidden() of the fragment has changed. Fragments start out not hidden; this will be called whenever the fragment changes state from that.

Parameters
hidden  True if the fragment is now hidden, false if it is not visible.

Update 2 This is how I do it:

public interface ViewPagerFragmentInterface {
    void onFragmentBecameVisible();
}

My Fragments:

public class SomeViewPagerFragment extends Fragment implements ViewPagerFragmentInterface {
      public void onFragmentBecameVisible() {
          // I AM VISIBLE!
      }
}

Then on my ViewPage onPageChangeListener()

public void onPageSelected(final int i) {
ViewPagerFragmentInterface fragment =
       (ViewPagerFragmentInterface)mPagerAdapter.instantiateItem(mViewPager, i);
    if (fragment != null) {
       fragment.onFragmentBecameVisible();
    }
}