How to determine when Fragment becomes visible in ViewPager

后端 未结 26 1187
心在旅途
心在旅途 2020-11-22 00:24

Problem: Fragment onResume() in ViewPager is fired before the fragment becomes actually visible.

For example, I have 2 fragments with

相关标签:
26条回答
  • 2020-11-22 00:49

    I had the same issue. ViewPager executes other fragment life cycle events and I could not change that behavior. I wrote a simple pager using fragments and available animations. SimplePager

    0 讨论(0)
  • 2020-11-22 00:50

    Another solution posted here overriding setPrimaryItem in the pageradapter by kris larson almost worked for me. But this method is called multiple times for each setup. Also I got NPE from views, etc. in the fragment as this is not ready the first few times this method is called. With the following changes this worked for me:

    private int mCurrentPosition = -1;
    
    @Override
    public void setPrimaryItem(ViewGroup container, int position, Object object) {
        super.setPrimaryItem(container, position, object);
    
        if (position == mCurrentPosition) {
            return;
        }
    
        if (object instanceof MyWhizBangFragment) {
            MyWhizBangFragment fragment = (MyWhizBangFragment) object;
    
            if (fragment.isResumed()) {
                mCurrentPosition = position;
                fragment.doTheThingYouNeedToDoOnBecomingVisible();
            }
        }
    }
    
    0 讨论(0)
  • 2020-11-22 00:51

    Note that setUserVisibleHint(false) is not called on activity / fragment stop. You'll still need to check start/stop to properly register/unregister any listeners/etc.

    Also, you'll get setUserVisibleHint(false) if your fragment starts in a non-visible state; you don't want to unregister there since you've never registered before in that case.

    @Override
    public void onStart() {
        super.onStart();
    
        if (getUserVisibleHint()) {
            // register
        }
    }
    
    @Override
    public void onStop() {
        if (getUserVisibleHint()) {
            // unregister
        }
    
        super.onStop();
    }
    
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
    
        if (isVisibleToUser && isResumed()) {
            // register
    
            if (!mHasBeenVisible) {
                mHasBeenVisible = true;
            }
        } else if (mHasBeenVisible){
            // unregister
        }
    }
    
    0 讨论(0)
  • 2020-11-22 00:52
    package com.example.com.ui.fragment;
    
    
    import android.os.Bundle;
    import android.support.annotation.Nullable;
    import android.support.v4.app.Fragment;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    
    import com.example.com.R;
    
    public class SubscribeFragment extends Fragment {
    
        @Override
        public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
            View view = inflater.inflate(R.layout.fragment_subscribe, container, false);
            return view;
        }
    
        @Override
        public void setUserVisibleHint(boolean isVisibleToUser) {
            super.setUserVisibleHint(isVisibleToUser);
    
            if (isVisibleToUser) {
                // called here
            }
        }
    
        @Override
        public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
            super.onViewCreated(view, savedInstanceState);
        }
    }
    
    0 讨论(0)
  • 2020-11-22 00:53

    Detecting by focused view!

    This works for me

    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();
    }
    
    0 讨论(0)
  • 2020-11-22 00:54

    We have a special case with MVP where the fragment needs to notify the presenter that the view has become visible, and the presenter is injected by Dagger in fragment.onAttach().

    setUserVisibleHint() is not enough, we've detected 3 different cases that needed to be addressed (onAttach() is mentioned so that you know when the presenter is available):

    1. Fragment has just been created. The system makes the following calls:

      setUserVisibleHint() // before fragment's lifecycle calls, so presenter is null
      onAttach()
      ...
      onResume()
      
    2. Fragment already created and home button is pressed. When restoring the app to foreground, this is called:

      onResume()
      
    3. Orientation change:

      onAttach() // presenter available
      onResume()
      setUserVisibleHint()
      

    We only want the visibility hint to get to the presenter once, so this is how we do it:

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View root = inflater.inflate(R.layout.fragment_list, container, false);
        setHasOptionsMenu(true);
    
        if (savedInstanceState != null) {
            lastOrientation = savedInstanceState.getInt(STATE_LAST_ORIENTATION,
                  getResources().getConfiguration().orientation);
        } else {
            lastOrientation = getResources().getConfiguration().orientation;
        }
    
        return root;
    }
    
    @Override
    public void onResume() {
        super.onResume();
        presenter.onResume();
    
        int orientation = getResources().getConfiguration().orientation;
        if (orientation == lastOrientation) {
            if (getUserVisibleHint()) {
                presenter.onViewBecomesVisible();
            }
        }
        lastOrientation = orientation;
    }
    
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if (presenter != null && isResumed() && isVisibleToUser) {
            presenter.onViewBecomesVisible();
        }
    }
    
    @Override public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putInt(STATE_LAST_ORIENTATION, lastOrientation);
    }
    
    0 讨论(0)
提交回复
热议问题