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방법 fragmentVisiblefalse!? 그래서 파편이 비어있었습니다 ..! 이견있는 사람.?
Alaa AbuZarifa

28

감지하기 FragmentViewPager눈에 보이는, 꽤 있는지 해요 에만 사용이 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. SubChildContainerFragmentChildContainerFragment1 개의 수업을 혼합 할 수 있습니다 . 도움이 되길 바랍니다. 나는 완전한 답변을 나중에 게시 할 것입니다
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

에서 ViewPager2ViewPager버전에서 androidx.fragment:fragment:1.1.0당신은 사용할 수 있습니다 onPauseonResume콜백은 현재 사용자가 볼 수있는 단편 결정합니다. 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.