ViewPager에서 프래그먼트가 표시되는 시점을 결정하는 방법


754

문제점 : 조각 onResume()에이 ViewPager단편은 실제로 표시되기 전에 소성된다.

예를 들어 ViewPagerand와 2 개의 조각이 FragmentPagerAdapter있습니다. 두 번째 조각은 승인 된 사용자 만 사용할 수 있으며 조각이 표시되면 경고 대화 상자를 사용하여 로그인하도록 사용자에게 요청해야합니다.

그러나 ViewPager두 번째 조각을 캐시하기 위해 첫 번째 조각이 표시되면 두 번째 조각이 만들어지고 사용자가 스 와이프를 시작할 때 표시됩니다.

따라서 onResume()이벤트는 표시되기 오래 전에 두 번째 조각에서 시작됩니다. 그래서 두 번째 조각이 표시되면 적절한 순간에 대화 상자를 표시 할 때 발생하는 이벤트를 찾으려고합니다.

어떻게 할 수 있습니까?


18
"ViewPager 및 FragmentPagerAdapter와 함께 2 개의 프래그먼트가 있습니다. 두 번째 프래그먼트는 인증 된 사용자 만 사용할 수 있으며 프래그먼트가 표시 될 때 로그인하는 데 사용하도록 요청해야합니다 (경고 대화 상자)." -IMHO, 끔찍한 UX입니다. 사용자가 가로로 스 와이프하여 대화 상자를 표시하면 Play 스토어에서 별 1 개 등급을 부여하게됩니다.
— CommonsWare

"로그인"버튼으로 TextView에 정보를 표시하는 것이 더 낫습니까? 그 사건에 대한 당신의 해결책은 무엇입니까?
— 4ntoine

5
"데이터가 표시되지 않으면 데이터를로드 할 필요가 없습니다." -그런 다음에 넣지 말아야합니다 ViewPager. 두 페이지 호출기에서 두 페이지는 원하는지 여부에 관계없이 즉시로드됩니다. 의 사용자 경험은 ViewPager콘텐츠가 스 와이프하자마자 얼마 후가 아니라는 것입니다. 그렇기 때문에 ViewPager사용자 경험을 보장하기 위해 보이는 것보다 먼저 페이지를 초기화합니다.
— CommonsWare

2
ViewPager 유연 충분이 아닌 것 같다 그것은 최소 setOffscreenPageLimit 1이기 때문에 캐싱을 해제 할 수 없습니다 : stackoverflow.com/questions/10073214/... . 이것에 대한 이유를 보지 못하고 예상되는 동작 (강제 캐싱의 경우)은 프래그먼트가 보일 때 프래그먼트 BUT fire 프래그먼트의 onResume ()을 만드는 것입니다.
— 4ntoine

1
조금 늦었지만 같은 문제에 직면 한 사람이라면 FragmentViewPager 라이브러리 (저는 저자입니다)를 사용해보십시오. 이 문제를 다루고 몇 가지 추가 기능을 제공합니다. 샘플은 프로젝트의 GitHub 페이지 또는이 stackoverflow answer를 확인하십시오 .
— S. Brukhanda

답변:


582

ViewPager에서 프래그먼트가 표시되는 시점을 결정하는 방법

setUserVisibleHint에서 재정 의하여 다음을 수행 할 수 있습니다 Fragment.

public class MyFragment extends Fragment {
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if (isVisibleToUser) {
        }
        else {
        }
    }
}

7
오늘의 Android 지원 라이브러리 업데이트 (rev 11) 덕분에 사용자가 볼 수있는 힌트 문제가 수정되었습니다. ViewPager에 사용자가 볼 수있는 힌트를 사용하는 것이 안전합니다.
— 오아시스 펭

58
onCreateView가 호출되기 전에 setUserVisibleHint 메소드가 호출되어 초기화를 추적하기가 어렵다는 것을 알았습니다.
— AndroidDev

11
@AndroidDev 힌트가 참으로 올 때 뷰 트리가 이미 초기화되어 있어야 할 때 일부 코드를 실행 isResumed()하려면 NPE를 피하기 위해 해당 코드 블록을 래핑하십시오 . 나를 위해 잘 일했다.
— Ravi Thapliyal

13
SDK가 기본적으로 제공 해야하는 것에 대해 너무 많은 해킹이 있다는 것은 우스운 일입니다.
— Mike6679

15
setUserVisibleHint더 이상 사용되지 않음
— SR

525

업데이트 : Android Support Library (rev 11)는 마침내 사용자가 볼 수있는 힌트 문제를 해결했습니다 . 이제 조각에 대한 지원 라이브러리를 사용하면 gorn의 답변에 설명 된대로 변경 사항을 캡처 getUserVisibleHint()하거나 안전하게 무시할 수 있습니다 setUserVisibleHint().

업데이트 1 여기에 하나의 작은 문제가 getUserVisibleHint()있습니다. 이 값은 기본적으로 true입니다.

// Hint provided by the app that this fragment is currently visible to the user.
boolean mUserVisibleHint = true;

따라서 setUserVisibleHint()호출 하기 전에 사용하려고 할 때 문제가있을 수 있습니다 . 해결 onCreate방법으로 이와 같은 방법으로 값을 설정할 수 있습니다 .

public void onCreate(@Nullable Bundle savedInstanceState) {
    setUserVisibleHint(false);

오래된 답변 :

대부분의 사용의 경우, ViewPager한 번에 한 페이지를 표시하지만, 당신이 사용하는 경우 사전 캐시 조각은 (실제로 눈에 보이지 않는) "볼 수"상태로 넣어 FragmentStatePagerAdapter에서 Android Support Library pre-r11.

나는 무시 :

public class MyFragment extends Fragment {
    @Override
    public void setMenuVisibility(final boolean visible) {
        super.setMenuVisibility(visible);
        if (visible) {
            // ...
        }
    }
   // ...
}

ViewPager에서 하나의 프래그먼트 만 실제로 메뉴 항목을 상위 활동 항목과 함께 배치 할 수 있기 때문에 프래그먼트의 초점 상태를 캡처하는 것이 가장 적합한 "가시성"상태라고 생각합니다.


73
getActivity ()를 사용하는 데주의하십시오. 처음 시작할 때 널이됩니다.
— vovkab

10
setUserVisibleHint ()는 FragmentPagerAdapter에서 항상 제대로 작동했습니다.
— louielouie

8
이 솔루션 (및 gorn 's)도 약간 뒤떨어져 있습니다. viewpager가 빠르게 스 와이프되고 여러 번 반복되는 경우이 메소드는 지연되어 호출됩니다 (조각이 더 이상 표시되지 않거나 보이지 않는 경우).
— AsafK

3
나는 점점 오전 truegetUserVisibleHint ()에 대한 onCreateOptionsMenu호출, 언제 setUserVisibleHint라고, 메뉴가 아직이 보인다 생성되지 않았습니다. 궁극적으로 보이는 조각의 메뉴 만 원할 때 메뉴가 추가 된 두 가지 옵션이 있습니다. 이와 관련하여 어떤 제안?
— cYrixmorten

13
setUserVisibleHint더 이상 사용되지 않음
— SR

143

이것은 정상적인 onResume()동작 을 복원하는 것으로 보입니다 . 홈 키를 눌러 앱을 종료 한 다음 앱을 다시 입력하면 잘 작동합니다. onResume()행에서 두 번 호출되지 않습니다.

@Override
public void setUserVisibleHint(boolean visible)
{
    super.setUserVisibleHint(visible);
    if (visible && isResumed())
    {
        //Only manually call onResume if fragment is already visible
        //Otherwise allow natural fragment lifecycle to call onResume
        onResume();
    }
}

@Override
public void onResume()
{
    super.onResume();
    if (!getUserVisibleHint())
    {
        return;
    }

    //INSERT CUSTOM CODE HERE
}

4
정확히 내가 찾던 것. 해결의 문제 setUserVisibleHint이전에 호출되는 onCreateView및 그 setUserVisibleHint응용 프로그램은 배경을 진행하고 전경 경우 호출되지 않습니다. 대박! 감사합니다!
— Alex

11
onResume을 직접 호출하는 것은 좋지 않은 생각이지만이 게시물의 질문에 대답하는 데 필요한 모든 것은 setUserVisibleHint 함수에 있습니다!
— Quentin G.

4
차라리 일반 구현할 것입니다 onVisibleToUser()방법과에서 것을 불렀다 onResume()으로부터 setUserVisibleHint(boolean)호출하는 대신 onResume()자신을 생명주기 콜백을 방해. 그렇지 않으면이 접근법이 훌륭하게 작동한다고 생각합니다. 감사합니다!
— Stephan Henningsen 2014 년

1
예, 위의 의견에 동의합니다. 일반적으로 클래스의 공개 메소드에서 공개 메소드를 호출하지 않도록하십시오. 비공개 메소드를 작성하고 두 공개 메소드에서 모두 호출하십시오.
— Johan Franzén

4
setUserVisibleHint 추천하지 않습니다!
— 하미드 레자

70

다음은 또 다른 방법입니다 onPageChangeListener.

  ViewPager pager = (ViewPager) findByViewId(R.id.viewpager);
  FragmentPagerAdapter adapter = new FragmentPageAdapter(getFragmentManager);
  pager.setAdapter(adapter);
  pager.setOnPageChangeListener(new OnPageChangeListener() {

  public void onPageSelected(int pageNumber) {
    // Just define a callback method in your fragment and call it like this! 
    adapter.getItem(pageNumber).imVisible();

  }

  public void onPageScrolled(int arg0, float arg1, int arg2) {
    // TODO Auto-generated method stub

  }

  public void onPageScrollStateChanged(int arg0) {
    // TODO Auto-generated method stub

  }
});

1
이 솔루션은 잘 작동합니다. 이것은 (v4) 프래그먼트 지원 패키지를 사용하는 구형 플랫폼을 구축하는 사람들에게 권장되는 솔루션이어야합니다.
— Frank Yin

7
FragmentStatePagerAdapter를 사용하고 getItem ()에서 새 Fragment 인스턴스를 인스턴스화하면 뷰 파서가 얻는 것이 아니라 새 프래그먼트의 상태 만 설정하기 때문에 예상 한 결과를 얻을 수 없다는 점에 주목할 가치가 있습니다.
— 벤 피어슨

1
이 솔루션은 조각이 표시 될 때 무언가를 수행하려는 경우에 좋습니다. 프래그먼트의 가시 상태를 유지하지 않습니다 (즉, 프래그먼트가 언제 보이지 않는지 알 수 없음).
— AsafK

나는 같은 유형의 문제입니다. 문제 해결을 도와주세요. 내 게시물 : stackoverflow.com/questions/23115283/…
— Jeeten Parmar

이것은 조각의 iamVisible 메소드에서 사용중인 어댑터에 대해 널 포인터 예외를 제공합니다. 조각이 보이는 경우에만 네트워크에서 수신 된 데이터를 설정하려고합니다.
— zaphod100.10

58

setUserVisibleHint()때때로 전후에 호출 onCreateView()되어 문제가 발생합니다.

이를 극복하려면 isResumed()내부 setUserVisibleHint()방법 을 확인해야합니다 . 그러나이 경우 Fragment가 재개되어 표시 될 때만setUserVisibleHint() 호출 되는 것으로 나타났습니다 .

당신이 조각이 업데이트 뭔가 싶다면 visible, 모두 여러분의 업데이트 기능을 넣어 onCreate()및 setUserVisibleHint():

@Override
public View onCreateView(...){
    ...
    myUIUpdate();
    ...        
}
  ....
@Override
public void setUserVisibleHint(boolean visible){
    super.setUserVisibleHint(visible);
    if (visible && isResumed()){
        myUIUpdate();
    }
}

업데이트 : 여전히 myUIUpdate()두 번 호출되는 것을 깨달았 습니다 . 왜냐하면 3 개의 탭이 있고이 코드가 두 번째 탭에 있으면 첫 번째 탭을 처음 열면 두 번째 탭도 표시되지 않고 myUIUpdate()호출 되기 때문에 생성 됩니다. 그런 다음 두 번째 탭으로 스 와이프하면 myUIUpdate()from if (visible && isResumed())이 호출되어 결과적 myUIUpdate()으로 1 초에 두 번 호출 될 수 있습니다.

다른 문제가 있습니다 !visible에서 setUserVisibleHint호출되는 모두 1) 단편 화면 처음으로 전환 할 때이 생성되기 전에 조각 스크린과 2), 밖으로 갈 때.

해결책:

private boolean fragmentResume=false;
private boolean fragmentVisible=false;
private boolean fragmentOnCreated=false;
...

@Override
public View onCreateView(...){
    ...
    //Initialize variables
    if (!fragmentResume && fragmentVisible){   //only when first time fragment is created
        myUIUpdate();
    }
    ...        
}

@Override
public void setUserVisibleHint(boolean visible){
    super.setUserVisibleHint(visible);
    if (visible && isResumed()){   // only at fragment screen is resumed
        fragmentResume=true;
        fragmentVisible=false;
        fragmentOnCreated=true;
        myUIUpdate();
    }else  if (visible){        // only at fragment onCreated
        fragmentResume=false;
        fragmentVisible=true;
        fragmentOnCreated=true;
    }
    else if(!visible && fragmentOnCreated){// only when you go out of fragment screen
        fragmentVisible=false;
        fragmentResume=false;
    }
}

설명:

fragmentResume, fragmentVisible: 확인합니다 myUIUpdate()에있는이 onCreateView()조각이되지 이력서 작성 및 볼 때만 호출된다. 또한 첫 번째 탭에있을 때 문제를 해결하고 두 번째 탭이 보이지 않아도 만들어집니다. 이렇게하면 해결할 때 조각 화면이 표시되는지 확인합니다 onCreate.

fragmentOnCreated: 프래그먼트가 보이지 않도록하고 프래그먼트를 처음 만들 때 호출되지 않습니다. 이제이 if 절은 조각을 쓸어 넘길 때만 호출됩니다.

업데이트 당신은이 모든 코드를 넣을 수 있습니다 BaseFragment코드를 다음과 같이 하고 재정의 방법.


1
솔루션은 한 시나리오를 제외하고는 완벽하게 작동합니다. 프래그먼트가 정상적으로 열리면 일부 버튼을 클릭하여 다른 프래그먼트로 교체 한 다음 뒤로를 클릭하여 백 스택에서 새 프래그먼트를 팝하십시오.이 경우 setUserVisibleHint전화가 걸리지 않았습니다. ! 그리고 내부 onCreateView방법 fragmentVisible은 false!? 그래서 파편이 비어있었습니다 ..! 이견있는 사람.?
— Alaa AbuZarifa

28

감지하기 Fragment에 ViewPager눈에 보이는, 꽤 있는지 해요 에만 사용이 setUserVisibleHint 충분하지 않습니다.
다음은 조각이 표시되거나 보이지 않는지 확인하는 솔루션입니다. 먼저 viewpager를 시작할 때 페이지 간을 전환하고 다른 활동 / 조각 / 배경 / 전경으로 이동하십시오`

public class BaseFragmentHelpLoadDataWhenVisible extends Fragment {
    protected boolean mIsVisibleToUser; // you can see this variable may absolutely <=> getUserVisibleHint() but it not. Currently, after many test I find that

    /**
     * This method will be called when viewpager creates fragment and when we go to this fragment background or another activity or fragment
     * NOT called when we switch between each page in ViewPager
     */
    @Override
    public void onStart() {
        super.onStart();
        if (mIsVisibleToUser) {
            onVisible();
        }
    }

    @Override
    public void onStop() {
        super.onStop();
        if (mIsVisibleToUser) {
            onInVisible();
        }
    }

    /**
     * This method will called at first time viewpager created and when we switch between each page
     * NOT called when we go to background or another activity (fragment) when we go back
     */
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        mIsVisibleToUser = isVisibleToUser;
        if (isResumed()) { // fragment have created
            if (mIsVisibleToUser) {
                onVisible();
            } else {
                onInVisible();
            }
        }
    }

    public void onVisible() {
        Toast.makeText(getActivity(), TAG + "visible", Toast.LENGTH_SHORT).show();
    }

    public void onInVisible() {
        Toast.makeText(getActivity(), TAG + "invisible", Toast.LENGTH_SHORT).show();
    }
}

설명 아래의 logcat을주의 깊게 확인하면이 솔루션이 왜 작동하는지 알 수 있다고 생각합니다.

첫 발사

Fragment1: setUserVisibleHint: isVisibleToUser=false isResumed=false
Fragment2: setUserVisibleHint: isVisibleToUser=false isResumed=false
Fragment3: setUserVisibleHint: isVisibleToUser=false isResumed=false
Fragment1: setUserVisibleHint: isVisibleToUser=true isResumed=false // AT THIS TIME isVisibleToUser=true but fragment still not created. If you do something with View here, you will receive exception
Fragment1: onCreateView
Fragment1: onStart mIsVisibleToUser=true
Fragment2: onCreateView
Fragment3: onCreateView
Fragment2: onStart mIsVisibleToUser=false
Fragment3: onStart mIsVisibleToUser=false

2 페이지로 이동

Fragment1: setUserVisibleHint: isVisibleToUser=false isResumed=true
Fragment2: setUserVisibleHint: isVisibleToUser=true isResumed=true

3 페이지로 이동

Fragment2: setUserVisibleHint: isVisibleToUser=false isResumed=true
Fragment3: setUserVisibleHint: isVisibleToUser=true isResumed=true

배경으로 이동 :

Fragment1: onStop mIsVisibleToUser=false
Fragment2: onStop mIsVisibleToUser=false
Fragment3: onStop mIsVisibleToUser=true

전경으로 이동

Fragment1: onStart mIsVisibleToUser=false
Fragment2: onStart mIsVisibleToUser=false
Fragment3: onStart mIsVisibleToUser=true

여기 DEMO 프로젝트

도움이되기를 바랍니다.


1
프래그먼트에 프래그먼트를 구성하는 다른 뷰 호출기가 있으면 작동하지 않습니다.
— Shihab Uddin

죄송합니다, 시간이 충분하지 않아서 답변을 게시 할 수 없습니다. 가능한 경우 문제에 대한 내 자식을 여기에서 참조하십시오 github.com/PhanVanLinh/AndroidViewPagerSkeleton/tree/master . SubChildContainerFragmentdetect에 사용됩니다 a fragment has another view pager which also consists fragment. SubChildContainerFragment와 ChildContainerFragment1 개의 수업을 혼합 할 수 있습니다 . 도움이 되길 바랍니다. 나는 완전한 답변을 나중에 게시 할 것입니다
— Phan Van Linh

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

2
이것이 정답입니다. android.app.Fragment와 함께 작동하며 엄청난 보너스입니다.
— RajV

setUserVisibleHint 더 이상 사용되지 않음
— ekashking

23

에서 ViewPager2와 ViewPager버전에서 androidx.fragment:fragment:1.1.0당신은 사용할 수 있습니다 onPause및 onResume콜백은 현재 사용자가 볼 수있는 단편 결정합니다. onResume조각이 표시되면 콜백이 호출되고onPause 될 때 .

ViewPager2의 경우 기본 동작이지만 이전 동작에 대해 동일한 동작을 사용할 수 있습니다. ViewPager 쉽게 있습니다.

첫 번째 ViewPager에서이 동작을 활성화하려면 FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT매개 변수를 FragmentPagerAdapter생성자의 두 번째 인수 로 전달해야합니다 .

FragmentPagerAdapter(fragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT)

노트 : setUserVisibleHint()FragmentPagerAdapter 하나의 매개 변수가있는 메소드와 생성자는 이제 Android jetpack의 새 버전의 Fragment에서 더 이상 사용되지 않습니다.


1
좋은 해결책에 감사드립니다. 나는 이것을 오랫동안 찾고 있었다. 대단한 일
— Anurag Srivastava

1
ViewPager2의 경우 BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT 옵션이 기본 동작이 아니므로 수동으로 설정해야합니다. 이 옵션을 설정할 때 솔루션이 효과적이었습니다. 감사.
— driAn

1
APR 2020 현재, 이것은 업데이트 된 솔루션이며 매력처럼 작동합니다.
— Prakash

1
@ 4ntoine이 답변을 정답으로 수락하는 것을 고려하십시오. 현재로서는 이것이 정확하고 대부분의 답변은 더 이상 사용되지 않는 setUserVisibleHint 메소드
— Jorn Rigter

16

서브 클래스 setPrimaryItem()에서 재정의 합니다 FragmentPagerAdapter. 나는이 방법을 사용하며 잘 작동합니다.

@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
    // This is what calls setMenuVisibility() on the fragments
    super.setPrimaryItem(container, position, object);

    if (object instanceof MyWhizBangFragment) {
        MyWhizBangFragment fragment = (MyWhizBangFragment) object;
        fragment.doTheThingYouNeedToDoOnBecomingVisible();
    }
}

1
이것은 거의 효과가 있었지만 NPE에 문제가 있었고 여러 번 호출되었습니다. 아래에 대안을 게시했습니다!
— Gober


처음에 개체 개체를 저장하고, 확인하고 바로 FragmentStateAdapter 같은 동일한 개체 개체와 전화까지 추적을 무시 @Gober 방법) setPrimaryItem (에서 할
— wanglugao

12

Fragment.onHiddenChanged()그것을 무시하십시오 .

public void onHiddenChanged(boolean hidden)

숨겨진 상태에서 호출 isHidden()프래그먼트 )가 변경 . 조각은 숨겨지지 않습니다. 이것은 프래그먼트가 상태에서 변경 될 때마다 호출됩니다.

매개 변수
hidden- boolean: 조각이 숨겨져 있으면 true이고, 보이지 않으면 false입니다.


3
이 방법은 현재 사용되지 않으며 더 이상 사용할 수 없습니다
— bluewhile

4
@bluewhile 더 이상 사용되지 않는 곳은 어디입니까? developer.android.com/reference/android/app/…
— Cel

1
방금 이것을 성공적으로 사용했으며 문서에서 더 이상 사용되지 않는다고 표시하지 않습니다.
— Trevor

1
@bluewhile, 4.1 (api 16)에서는 더 이상 사용되지 않습니다.
— dan

8
API 수준 19를 사용하고 있으며 더 이상 사용되지 않지만 광고 된대로 작동하지 않음을 확인할 수 있습니다. 예를 들어 조각이 다른 조각에 의해 숨겨져 있으면 onHiddenChanged가 호출되지 않습니다.

4

나는 것을 파악 onCreateOptionsMenu하고 onPrepareOptionsMenu방법 만 조각의 경우라고 정말 볼. 나는 이런 식으로 작동하는 메소드를 찾을 수 OnPageChangeListener없었지만 시도 했지만 상황에 따라 작동하지 않았습니다. 예를 들어 onCreate메소드 에서 초기화 된 변수가 필요합니다 .

따라서이 두 가지 방법을이 문제에 대한 해결 방법으로, 특히 작고 짧은 작업에 사용할 수 있습니다.

나는 이것이 더 나은 해결책이지만 최선은 아니라고 생각합니다. 나는 이것을 사용하지만 동시에 더 나은 해결책을 기다릴 것입니다.

문안 인사.


2

kris larson의 pageradapter에서 setPrimaryItem을 재정의하는 다른 솔루션 이 여기에서 거의 나를 위해 일했습니다. 그러나이 방법은 각 설정마다 여러 번 호출됩니다. 또한 이 메소드가 처음 몇 번 호출되지 않았으므로 조각의 뷰 등에서 NPE 를 얻었습니다 . 다음과 같이 변경하면 이것이 효과가 있습니다.

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

2

조각 안에 다음 코드 추가

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

     }
}

이것은 ViewPagerFragments에서만 작동합니다. 정상적인 활동의 조각에는 해당되지 않습니다.
— AndroidGuy

2

FragmentStatePagerAdapters3 개의 탭으로 작업하는 동안 동일한 문제가 발생했습니다 . 첫 번째 탭을 클릭 할 때마다 Dilaog를 표시하고 다른 탭을 클릭하면 숨겨야했습니다.

재정의 setUserVisibleHint()만해도 현재 보이는 조각을 찾는 데 도움이되지 않았습니다.

세 번째 탭에서 클릭 할 때 -----> 첫 번째 탭. 두 번째 조각과 첫 번째 조각에 대해 두 번 트리거되었습니다. 나는 그것을 isResumed () 메소드와 결합했다.

    @Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
    isVisible = isVisibleToUser;

    // Make sure that fragment is currently visible
    if (!isVisible && isResumed()) {
        // Call code when Fragment not visible
    } else if (isVisible && isResumed()) {
       // Call code when Fragment becomes visible.
    }

}

2

MVP의 경우 조각이 발표자에게 뷰가 표시되었음을 알리고 발표자가 Dagger에 삽입되었음을 알리는 특별한 경우가 있습니다. fragment.onAttach() .

setUserVisibleHint()충분하지 않습니다. 해결해야 할 3 가지 사례가 발견되었습니다 ( onAttach()발표자가 언제 발표되는지 알려줍니다).

  1. 조각이 생성되었습니다. 시스템은 다음을 호출합니다.

    setUserVisibleHint() // before fragment's lifecycle calls, so presenter is null
    onAttach()
    ...
    onResume()
  2. 조각이 이미 생성되었고 홈 버튼이 눌 렸습니다. 앱을 포 그라운드로 복원 할 때이를 다음이라고합니다.

    onResume()
  3. 오리엔테이션 변경 :

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

우리는 가시성 힌트가 발표자에게 한 번만 전달되기를 원하므로 다음과 같이하십시오.

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

2

에 의해 감지 focused view!

이것은 나를 위해 작동

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

1

사용자가 볼 수 있도록 viewpager의 조각이 화면에있을 때 타이머를 시작하려고 할 때이 문제가 발생했습니다.

타이머는 항상 사용자가 조각을보기 직전에 시작되었습니다. 그 이유는onResume()조각을보기 전에 조각 메소드가 호출되기 입니다.

내 해결책은 onResume()방법을 확인하는 것이 었습니다 . 프래그먼트 8이 현재 호출기의 뷰 호출기 일 때 특정 메소드 'foo ()'를 호출하고 싶었습니다.

@Override
public void onResume() {
    super.onResume();
    if(viewPager.getCurrentItem() == 8){
        foo();
        //Your code here. Executed when fragment is seen by user.
    }
}

도움이 되었기를 바랍니다. 이 문제가 많이 발생하는 것을 보았습니다. 이것은 내가 본 가장 간단한 해결책 인 것 같습니다. 다른 많은 사람들은 하위 API 등과 호환되지 않습니다.


1

나는 같은 문제가 있었다. ViewPager다른 조각 수명주기 이벤트를 실행하며 해당 동작을 변경할 수 없습니다. 조각과 사용 가능한 애니메이션을 사용하여 간단한 호출기를 작성했습니다. SimplePager


1

나는 이것을 사용했고 효과가 있었다!

mContext.getWindow().getDecorView().isShown() //boolean

1

나는 자식 조각으로 SectionsPagerAdapter를 지원하므로 많은 두통 후 마침내이 주제의 솔루션을 기반으로 작업 버전을 얻었습니다.

public abstract class BaseFragment extends Fragment {

    private boolean visible;
    private boolean visibilityHintChanged;

    /**
     * Called when the visibility of the fragment changed
     */
    protected void onVisibilityChanged(View view, boolean visible) {

    }

    private void triggerVisibilityChangedIfNeeded(boolean visible) {
        if (this.visible == visible || getActivity() == null || getView() == null) {
            return;
        }
        this.visible = visible;
        onVisibilityChanged(getView(), visible);
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (!visibilityHintChanged) {
            setUserVisibleHint(false);
        }
    }

    @Override
    public void onResume() {
        super.onResume();
        if (getUserVisibleHint() && !isHidden()) {
            triggerVisibilityChangedIfNeeded(true);
        }
    }

    @Override
    public void onHiddenChanged(boolean hidden) {
        super.onHiddenChanged(hidden);
        triggerVisibilityChangedIfNeeded(!hidden);
    }

    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        visibilityHintChanged = true;
        if (isVisibleToUser && isResumed() && !isHidden()) {
            triggerVisibilityChangedIfNeeded(true);
        } else if (!isVisibleToUser) {
            triggerVisibilityChangedIfNeeded(false);
        }
    }

    @Override
    public void onPause() {
        super.onPause();
        triggerVisibilityChangedIfNeeded(false);
    }

    @Override
    public void onStop() {
        super.onStop();
        triggerVisibilityChangedIfNeeded(false);
    }

    protected boolean isReallyVisible() {
        return visible;
    }
}

자식 조각을 부모 조각 세트에 추가하면 언급을 잊었습니다.
— Andoctorey

그리고 자식 프래그먼트를 추가하기 위해 getFragmentManager () 대신 getChildFragmentManager ()를 사용하는 것을 잊지 마십시오.
— Andoctorey

0

주 setUserVisibleHint(false)활동 / 조각 정지에 호출되지 않습니다. register/unregister리스너 등 을 올바르게 시작 / 중지해야합니다 .

또한 setUserVisibleHint(false)프래그먼트가 보이지 않는 상태에서 시작되면 얻을 수 있습니다. unregister이 경우에는 이전에 등록한 적이 없기 때문에 원하지 않습니다 .

@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

간단한 구현 방법은 조각으로 가기 전에 사용자가 로그인했는지 여부를 확인하는 것입니다.

MainActivity에서 onNavigationItemSelected 메소드 내에서 이와 같은 작업을 수행 할 수 있습니다 .

 case R.id.nav_profile_side:


                if (User_is_logged_in) {

                    fragmentManager.beginTransaction()
                            .replace(R.id.content_frame
                                    , new FragmentProfile())
                            .commit();
                }else {

                    ShowLoginOrRegisterDialog(fragmentManager);

                }

                break;

그러나 탐색 드로어를 사용중인 경우, ProfileFragment로 이동하지 않아도 드로어에서 선택 사항이 프로파일로 변경됩니다.

선택을 현재 선택으로 재설정하려면 아래 코드를 실행하십시오.

        navigationView.getMenu().getItem(0).setChecked(true);

-4

관련 FragmentStatePagerAdapter의 Count 메서드를 재정의하고 숨길 페이지 수를 뺀 총 수를 반환합니다.

 public class MyAdapter : Android.Support.V13.App.FragmentStatePagerAdapter
 {   
     private List<Fragment> _fragments;

     public int TrimmedPages { get; set; }

     public MyAdapter(Android.App.FragmentManager fm) : base(fm) { }

     public MyAdapter(Android.App.FragmentManager fm, List<Android.App.Fragment> fragments) : base(fm)
     {
         _fragments = fragments;

         TrimmedPages = 0;
     }

     public override int Count
     {
         //get { return _fragments.Count; }
         get { return _fragments.Count - TrimmedPages; }
     }
 }

따라서 ViewPager에 처음에 3 개의 프래그먼트가 추가되고 조건이 충족 될 때까지 처음 2 개만 표시되어야하는 경우 TrimmedPages를 1로 설정하여 페이지 수를 무시하고 처음 두 페이지 만 표시해야합니다.

이것은 마지막 페이지에는 효과적이지만 처음이나 중간에있는 페이지에는 실제로 도움이되지 않습니다 (많은 방법이 있지만).

당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.