ViewPager PagerAdapter가 View를 업데이트하지 않음


597

호환성 라이브러리에서 ViewPager를 사용하고 있습니다. 페이지를 통과 할 수있는 여러보기를 표시하는 데 성공했습니다.

그러나 새로운 View 집합으로 ViewPager를 업데이트하는 방법을 알아내는 데 어려움을 겪고 있습니다.

나는 호출과 같은 모든 종류의 것들을 시도했습니다 mAdapter.notifyDataSetChanged(), mViewPager.invalidate()심지어 새로운 어댑터 나 데이터의 새로운 목록을 사용할 때마다 생성.

아무것도 도움이되지 않았습니다. 텍스트보기는 원본 데이터와 변경되지 않습니다.

업데이트 : 약간의 테스트 프로젝트를 만들었고 뷰를 거의 업데이트 할 수있었습니다. 아래 수업을 붙여 넣을 게요.

그러나 업데이트되지 않는 것은 두 번째보기이며 'B'는 남아 있으며 업데이트 버튼을 누른 후 'Y'가 표시되어야합니다.

public class ViewPagerBugActivity extends Activity {

    private ViewPager myViewPager;
    private List<String> data;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        data = new ArrayList<String>();
        data.add("A");
        data.add("B");
        data.add("C");

        myViewPager = (ViewPager) findViewById(R.id.my_view_pager);
        myViewPager.setAdapter(new MyViewPagerAdapter(this, data));

        Button updateButton = (Button) findViewById(R.id.update_button);
        updateButton.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                updateViewPager();
            }
        });
    }

    private void updateViewPager() {
        data.clear();
        data.add("X");
        data.add("Y");
        data.add("Z");
        myViewPager.getAdapter().notifyDataSetChanged();
    }

    private class MyViewPagerAdapter extends PagerAdapter {

        private List<String> data;
        private Context ctx;

        public MyViewPagerAdapter(Context ctx, List<String> data) {
            this.ctx = ctx;
            this.data = data;
        }

        @Override
        public int getCount() {
            return data.size();
        }

        @Override
        public Object instantiateItem(View collection, int position) {
            TextView view = new TextView(ctx);
            view.setText(data.get(position));
            ((ViewPager)collection).addView(view);
            return view;
        }

        @Override
        public void destroyItem(View collection, int position, Object view) {
             ((ViewPager) collection).removeView((View) view);
        }

        @Override
        public boolean isViewFromObject(View view, Object object) {
            return view == object;
        }

        @Override
        public Parcelable saveState() {
            return null;
        }

        @Override
        public void restoreState(Parcelable arg0, ClassLoader arg1) {
        }

        @Override
        public void startUpdate(View arg0) {
        }

        @Override
        public void finishUpdate(View arg0) {
        }
    }
}

1
FragmentStatePagerAdapter의 잠재적 버그에 대해서는 stackoverflow.com/questions/12510404/… 를 참조하십시오 .
samis

2
이것을 준설해서 죄송합니다. 귀하의 질문이 정말 도움이되었습니다! 내가 얻지 못하는 한 가지는 활동에서 데이터를 업데이트 할 때 PagerAdapter의 데이터에 대한 참조가 어떻게 변경되는지입니다.
Ewanw

: 어댑터가 BaseAdapter이 참조 확장 확인 stackoverflow.com/questions/13664155/...

1
분명히 어댑터를 다시보기 호출기로 설정하면 재설정됩니다.
EpicPandaForce

답변:


856

이를 달성하는 몇 가지 방법이 있습니다.

첫 번째 옵션은 더 쉽지만 조금 더 비효율적입니다.

getItemPosition다음 PagerAdapter과 같이 재정의 하십시오 .

public int getItemPosition(Object object) {
    return POSITION_NONE;
}

이 방법 notifyDataSetChanged()으로을 호출 하면 뷰 호출기가 모든 뷰를 제거하고 다시로드합니다. 따라서 재 장전 효과가 얻어진다.

Alvaro Luis Bustamante (이전의 alvarolb)제안한 두 번째 옵션 은 새보기를 인스턴스화 할 때 사용 하는 setTag()방법입니다 instantiateItem(). 그런 다음을 사용하는 대신 업데이트 할보기를 찾는 데 notifyDataSetChanged()사용할 수 있습니다 findViewWithTag().

두 번째 방법은 매우 유연하고 성능이 뛰어납니다. 독창적 인 연구를 위해 알바 롤브에게 도움이됩니다.


4
내 해결 방법보다 낫습니다. 감사합니다.
C0deAttack

3
비슷한 문제가 있습니다. 내 viewPager에 새로운 searc 결과가 표시되지만 커서의 첫 번째 항목으로 기본 설정되지 않습니다. 누구든지 데이터 세트를 업데이트 할 때 위치를 재설정하는 방법을 알고 있습니까?
mAndroid

1
@mAndroid 자세한 내용은 별도의 질문을 제출해야합니다.
rui.araujo

1
POSITION_NONE을 반환하면 Android가 쿼리 된 위치와 관련된보기를 삭제하므로 전체 응용 프로그램에 많은 비 효율성이 추가됩니다. 그런 다음 표시하기 전에보기를 다시 작성해야합니다. 뷰가 업데이트되지 않는 문제를 해결하지만 복잡한 레이아웃에 가장 적합한 솔루션은 아닙니다.
wufoo

11
더 나은 답변 (모든 항목을 제거하지 않고)-> stackoverflow.com/a/10852046/898056
yhpark

484

에 버그가 있다고 생각하지 않습니다 PagerAdapter. 문제는 작동 방식을 이해하는 것이 약간 복잡하다는 것입니다. 여기에 설명 된 솔루션을 보면 오해가있어서 내 관점에서 인스턴스화 된 뷰를 잘못 사용합니다.

지난 몇 일 내가 함께 일하고있다 PagerAdapter그리고 ViewPager, 나는 다음을 발견 :

notifyDataSetChanged()방법 은 기본 페이지가 변경되었음을 PagerAdapter알려줍니다 ViewPager. 예를 들어 페이지를 동적으로 만들거나 삭제 한 경우 (목록에서 항목 추가 또는 제거) 해당 페이지를 처리 ViewPager해야합니다. 이 경우 및 메소드를 ViewPager사용하여 새보기를 삭제하거나 인스턴스화 해야하는지 여부를 결정 한다고 생각합니다 .getItemPosition()getCount()

나는 전화를 ViewPager한 후에 notifyDataSetChanged()아이를보고 그들의 위치를 ​​확인 한다고 생각 합니다 getItemPosition(). 아동이 방법의 반환을 볼 경우 POSITION_NONE는이 ViewPager뷰가 호출, 삭제 된 것을 이해 destroyItem()하고,이 뷰를 제거.

이런 식으로 페이지의 컨텐츠 만 업데이트하려는 경우 getItemPosition()항상 리턴하도록 재정의 하는 것은 POSITION_NONE완전히 잘못된 것입니다. 이전에 작성된보기는 소멸되고 호출 할 때마다 새보기가 작성되기 때문 notifyDatasetChanged()입니다. 몇 TextView초 동안 그렇게 잘못되지 는 않았지만 데이터베이스에서 채워진 ListViews와 같은 복잡한 뷰가있는 경우 실제 문제가 될 수 있으며 리소스 낭비가 될 수 있습니다.

따라서 뷰를 다시 제거하고 인스턴스화하지 않고도 뷰의 컨텐츠를 효율적으로 변경하는 몇 가지 방법이 있습니다. 해결하려는 문제에 따라 다릅니다. 내 접근법은 setTag()메소드의 인스턴스화 된보기에 메소드 를 사용하는 것입니다 instantiateItem(). 따라서 데이터를 변경하거나 필요한 뷰를 무효화하려는 경우의 findViewWithTag()메소드를 호출 ViewPager하여 이전에 인스턴스화 된 뷰를 검색하고 원하는 때마다 새 뷰를 삭제 / 생성 할 필요없이 원하는대로 수정 / 사용할 수 있습니다. 값을 업데이트합니다.

예를 들어 100 페이지에 100 페이지가 TextView있고 주기적으로 하나의 값만 업데이트하려고 한다고 가정하십시오 . 앞에서 설명한 접근 방식을 사용하면 TextView각 업데이트에서 100 초를 제거하고 인스턴스화하고 있음을 의미합니다 . 그것은 이해가되지 않습니다...


11
+1-귀하의 솔루션은 목록보기, 텍스트보기 및 이미지가있는 탭이 포함 된 페이지를 업데이트해야 할 때 여기에 설명 한 문제와 같은 매력처럼 작동하지 않습니다. (OutOfErrorExceptions and such ...) 감사합니다!
schlingel

3
@alvarolb : 안녕하세요, 난 정말 당신이 무슨 뜻 방법을 모르는 setTag방법에 onInstantiateItem약간의 코딩이 대답을 업데이트하는 것처럼,겠습니까 당신이? 감사.
Huy Tower

35
예제를 작성하면 완벽 할 것입니다.
Sami Eltamawy

13
누군가가 말했듯이 : 예제 woulb 감사합니다!
Jey10

15
6 년이 지난 지금 아무도 모범을 보여줄 수 없습니다.
Oussaki

80

변화 FragmentPagerAdapter에를 FragmentStatePagerAdapter.

getItemPosition()메서드를 재정의하고을 반환 POSITION_NONE합니다.

결국에는 notifyDataSetChanged()온뷰 호출기를 듣게됩니다 .


조각 전체를 찾지 못하면 전체 getItemPosition을 올바르게 구현하고 POSITION_NONE을 반환해야한다고 생각합니다.
tkhduracell

46

alvarolb 의 대답 은 확실히 최선의 방법입니다. 그의 대답을 바탕으로 이것을 구현하는 쉬운 방법은 위치별로 활성 뷰를 저장하는 것입니다.

SparseArray<View> views = new SparseArray<View>();

@Override
public Object instantiateItem(View container, int position) {
    View root = <build your view here>;
    ((ViewPager) container).addView(root);
    views.put(position, root);
    return root;
}

@Override
public void destroyItem(View collection, int position, Object o) {
    View view = (View)o;
    ((ViewPager) collection).removeView(view);
    views.remove(position);
    view = null;
}

그런 다음 notifyDataSetChanged메소드를 재정 의하여 뷰를 새로 고칠 수 있습니다 ...

@Override
public void notifyDataSetChanged() {
    int key = 0;
    for(int i = 0; i < views.size(); i++) {
       key = views.keyAt(i);
       View view = views.get(key);
       <refresh view with new data>
    }
    super.notifyDataSetChanged();
}

당신은 실제로 비슷한 코드를 사용할 수 있습니다 instantiateItemnotifyDataSetChanged보기를 새로 고침 할 수 있습니다. 내 코드에서는 정확히 같은 방법을 사용합니다.


8
전체 어댑터 예제를 제공 할 수 있습니까? 이것은 조각을 사용하여 수행됩니까?

9
<새 데이터로보기 새로 고침> ?? 우리가 여기에 추가하거나 아무것도 추가하지 않아야한다는 의미는 무엇입니까?
Akarsh M

이 방법은 모든보기를 업데이트합니다. 하나의보기 만 업데이트하려면 다음과 같이 고유 한 notifyDataItemChanged 메소드를 작성할 수 있습니다. public void notifyDataItemChanged (int pos) {TextView tv = (TextView) views.get (pos) .findViewById (R.id.tv); tv.setText (list.get (pos)); super.notifyDataSetChanged (); }
Kai Wang

새 호출기 크기가 이전 크기보다 작은 경우이 코드가 충돌합니다
Anton Duzenko

@AntonDuzenko 올바른보기를 삭제하는 것은 매우 어렵습니다.
MLProgrammer-CiM

28

같은 문제가 있었다. 나를 위해 FragmentStatePagerAdapter를 확장하고 아래 메소드를 재정의했습니다.

@Override
public Parcelable saveState() {
    return null;
}

@Override
public void restoreState(Parcelable state, ClassLoader loader) {

}

이것은 나를 위해 일한 유일한 솔루션입니다. 내 경우는 조각을 업데이트하지 않고 조각을 동적으로 제거하거나 추가합니다. FragmentStatePagerAdapter를 확장하지 않으면 ViewPager가 캐시 된 조각을 반환하며 이는 잘못된 위치입니다. 감사!
Sira Lam

지원 라이브러리 28.0.0에서 잘 작동합니다.
Oleksii K.

무엇을하기 위해 재정의? 어댑터와 연관된 상태 오브젝트를 작성하는 방법은 무엇입니까?
Phani Rithvij

고마워 친구. 이 솔루션은 효과가 있습니다
Parthi

20

좌절의 시간이 문제를 극복하기 위해 위의 모든 솔루션을 시도 또한 같은 다른 유사한 문제에 많은 솔루션을하는 동안 후 , 그리고 모두가이 문제를 해결하고 만들기 위해 나와 함께 실패하는 ViewPager기존의 파괴 Fragment와 채우기 pager로 새로운 Fragments. 다음과 같이 문제를 해결했습니다.

1) 만들기 기능 ViewPager확장에 클래스를 FragmentPagerAdapter다음과 같은 :

 public class myPagerAdapter extends FragmentPagerAdapter {

2) 에 대한 항목을 작성 ViewPager가게가 title와를 fragment다음과 같은 :

public class PagerItem {
private String mTitle;
private Fragment mFragment;


public PagerItem(String mTitle, Fragment mFragment) {
    this.mTitle = mTitle;
    this.mFragment = mFragment;
}
public String getTitle() {
    return mTitle;
}
public Fragment getFragment() {
    return mFragment;
}
public void setTitle(String mTitle) {
    this.mTitle = mTitle;
}

public void setFragment(Fragment mFragment) {
    this.mFragment = mFragment;
}

}

3) 인스턴스 생성자 를 다음과 같이 ViewPagerFragmentManager인스턴스에 저장하십시오 class.

private FragmentManager mFragmentManager;
private ArrayList<PagerItem> mPagerItems;

public MyPagerAdapter(FragmentManager fragmentManager, ArrayList<PagerItem> pagerItems) {
    super(fragmentManager);
    mFragmentManager = fragmentManager;
    mPagerItems = pagerItems;
}

4) 다음과 같이 새 목록에서 새 항목을 다시 설정 하기 위해 직접 adapter이전 항목 fragment을 모두 삭제하여 새 데이터로 데이터 를 재설정하는 방법을 작성하십시오 .fragmentManageradapterfragment

public void setPagerItems(ArrayList<PagerItem> pagerItems) {
    if (mPagerItems != null)
        for (int i = 0; i < mPagerItems.size(); i++) {
            mFragmentManager.beginTransaction().remove(mPagerItems.get(i).getFragment()).commit();
        }
    mPagerItems = pagerItems;
}

5) 컨테이너에서 Activity또는 Fragment새 데이터로 어댑터를 다시 초기화하지 마십시오. setPagerItems다음과 같이 새 데이터로 메소드 를 통해 새 데이터를 설정하십시오 .

ArrayList<PagerItem> pagerItems = new ArrayList<PagerItem>();
pagerItems.add(new PagerItem("Fragment1", new MyFragment1()));
pagerItems.add(new PagerItem("Fragment2", new MyFragment2()));

mPagerAdapter.setPagerItems(pagerItems);
mPagerAdapter.notifyDataSetChanged();

도움이 되길 바랍니다.


@Tomer 당신이 직면 한 문제는 무엇입니까?
Sami Eltamawy


9

나는 같은 문제가 있었고 내 솔루션은 다음 FragmentPagerAdapter을 재정 의하여 사용 하고 있습니다 FragmentPagerAdapter#getItemId(int position).

@Override
public long getItemId(int position) {
    return mPages.get(position).getId();
}

기본적으로이 메소드는 항목의 위치를 ​​반환합니다. 변경 ViewPager되었는지 확인하고 itemId변경된 경우에만 페이지를 다시 작성 한다고 가정합니다 . 그러나 오버라이드되지 않은 버전은itemId 페이지가 실제로 다른 경우 하며 ViewPager는 해당 페이지가 교체 된 페이지를 정의하지 않으므로 다시 작성해야합니다.

이것을 사용하려면 long id 각 페이지마다 필요합니다. 일반적으로 고유 할 것으로 예상되지만이 경우 동일한 페이지의 이전 값과 달라야한다고 제안합니다. 따라서 여기서는 연속 카운터를 어댑터 또는 임의의 정수 (넓은 분포)로 사용할 수 있습니다.

이 주제에서 솔루션으로 언급 된 관점 태그를 사용하는 것이보다 일관된 방법이라고 생각합니다. 그러나 모든 경우에 해당되는 것은 아닙니다.


1
그것은. 확인했습니다 : POSITION_NONE만으로는 충분하지 않습니다. 당신의 훌륭한 답변에 감사드립니다! :)
Slava

이 기능은에 없습니다 PagerAdapter. 이것은 어떤 수업입니까?
Saket

@Saket, 당신 말이 맞아요, 수업은FragmentPagerAdapter
atlascoder

6

이 문제에 대한 매우 흥미로운 결정을 찾았습니다. 모든 조각을 메모리에 유지 하는 FragmentPagerAdapter 를 사용하는 대신 FragmentStatePagerAdapter ( android.support.v4.app.FragmentStatePagerAdapter )를 하여 선택할 때마다 프래그먼트를 다시로드 할 수 있습니다.

두 어댑터의 구현은 동일합니다. 따라서 " extend FragmentStatePagerAdapter "에서 " extend FragmentPagerAdapter " 만 변경하면됩니다.


좋은 점, 그것은 조각과 관련된 viewPager의 메모리 문제를 해결하는 데 도움이 될 것입니다
Ashu Kumar

큰 대답, 이것은 많은 도움이되었습니다.
Sergio Marani

5

이 문제를 많이 찾은 후에는 올바른 해결책이라고 생각했습니다. 본질적으로 instantiateItem은 뷰가 인스턴스화 될 때만 호출되며 뷰가 파괴되지 않는 한 다시 호출되지 않습니다 (이것은 getItemPosition 함수를 재정 의하여 POSITION_NONE을 반환 할 때 발생합니다). 대신, 당신이하고 싶은 것은 저장 생성 보기를 하고 어댑터에서 업데이트하거나 다른 사람이 업데이트 할 수 있도록 get 함수를 생성하거나 어댑터를 업데이트하는 set 함수 (내가 좋아하는 것)를 수행하는 것이 좋습니다.

따라서 MyViewPagerAdapter에서 다음과 같은 변수를 추가하십시오.

private View updatableView;

당신의 instantiateItem에 :

 public Object instantiateItem(View collection, int position) {
        updatableView = new TextView(ctx); //My change is here
        view.setText(data.get(position));
        ((ViewPager)collection).addView(view);
        return view;
    }

따라서이 방법으로 뷰를 업데이트하는 함수를 만들 수 있습니다.

public updateText(String txt)
{
    ((TextView)updatableView).setText(txt);
}

도움이 되었기를 바랍니다!


나는 데이터를 설정하지 않았다는 것을 깨달았 기 instantiateItem때문에 내 견해가 업데이트되지 않았습니다. 당신의 대답에서 나는 그것을 깨달았습니다. +1
Phani Rithvij

5

OP가 자신의 질문을 제기 한 지 2 년 반이 지난 지금도이 문제는 여전히 문제입니다. 이것에 대한 Google의 우선 순위가 특별히 높지 않은 것은 분명합니다. 따라서 해결책을 찾기보다는 해결 방법을 찾았습니다. 나를위한 큰 돌파구는 문제의 실제 원인이 무엇인지 알아내는 것입니다 ( 이 게시물 의 허용 된 답변 참조) ). 문제가 활성 페이지가 제대로 새로 고쳐지지 않았다는 것이 명백해지면 내 해결 방법이 분명했습니다.

내 조각 (페이지)에서

  • onCreateView에서 양식을 채우는 모든 코드를 가져 와서 프레임 워크가 아닌 어디서나 호출 할 수있는 PopulateForm이라는 함수에 넣었습니다. 이 함수는 getView를 사용하여 현재 View를 가져 오려고 시도하고 null 인 경우 반환합니다. PopulateForm은 표시하는 코드 만 포함하는 것이 중요합니다. FocusChange 리스너 등을 생성하는 다른 모든 코드는 여전히 OnCreate에 있습니다.
  • 폼을 다시로드해야 함을 나타내는 플래그로 사용할 수있는 부울을 작성하십시오. 내 mbReloadForm입니다
  • mbReloadForm이 설정된 경우 OnResume ()을 재정 의하여 PopulateForm ()을 호출하십시오.

내 활동에서 페이지를로드하는 위치 :

  • 변경하기 전에 0 페이지로 이동하십시오. FragmentStatePagerAdapter를 사용하고 있으므로 2 ~ 3 페이지가 최대의 영향을 받는다는 것을 알고 있습니다. 0 페이지로 변경하면 0, 1 및 2 페이지에서만 문제가 발생합니다.
  • 이전 목록을 지우려면 size ()를 사용하십시오. 이 방법으로 버그의 영향을받는 페이지 수를 알 수 있습니다. > 3 인 경우 3으로 줄입니다. 다른 PagerAdapter를 사용하는 경우 처리해야하는 페이지 수를 확인해야합니다 (모두 가능합니까?)
  • 데이터를 다시로드하고 pageAdapter.notifyDataSetChanged ()를 호출하십시오.
  • 이제 영향을받는 각 페이지에 대해 pager.getChildAt (i)를 사용하여 페이지가 활성화되어 있는지 확인하십시오.보기가 있는지 알려줍니다. 그렇다면 pager.PopulateView ()를 호출하십시오. 그렇지 않은 경우 ReloadForm 플래그를 설정하십시오.

그 후, 두 번째 페이지 세트를 다시로드 할 때 버그로 인해 일부는 이전 데이터를 표시합니다. 그러나 이제 새로 고쳐지고 새 데이터가 표시됩니다. 사용자는 페이지를보기 전에 새로 고치기 때문에 페이지가 잘못되었음을 알 수 없습니다.

이것이 누군가를 돕기를 바랍니다!


5

이 모든 솔루션이 도움이되지 않았습니다. 따라서 나는 해결책을 찾았습니다 : 당신은 setAdapter매번 할 수 있지만 충분하지 않습니다. 어댑터를 변경하기 전에 다음을 수행해야합니다.

FragmentManager fragmentManager = slideShowPagerAdapter.getFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
List<Fragment> fragments = fragmentManager.getFragments();
for (Fragment f : fragments) {
    transaction.remove(f);
}
transaction.commit();

그리고이 후 :

viewPager.setAdapter(adapter);

감사! 필자의 경우 ViewPager내부 조각을 사용 했기 때문에로 대체 slideShowPagerAdapter.getFragmentManager()되었습니다 getChildFragmentManager(). 아마도 getFragmentManager()당신의 경우에 도움이 될 것입니다. 나는 사용 FragmentPagerAdapter하지 않았다 FragmentStatePagerAdapter. 해킹 방법에 대해서는 stackoverflow.com/a/25994654/2914140 도 참조하십시오 .
CoolMind

5

훨씬 쉬운 방법 :을 사용하고 FragmentPagerAdapter페이징 된 뷰를 조각으로 래핑하십시오. 그들은 업데이트됩니다


5

rui.araujo와 Alvaro Luis Bustamante에게 감사합니다. 처음에, 나는 rui.araujo의 방법을 사용하려고 시도합니다. 왜냐하면 쉬운 일이기 때문입니다. 작동하지만 데이터가 변경되면 페이지가 분명히 다시 그려집니다. 그것은 나쁘기 때문에 Alvaro Luis Bustamante의 방식을 사용하려고합니다. 그것은 완벽. 코드는 다음과 같습니다.

@Override
protected void onStart() {
    super.onStart();
}

private class TabPagerAdapter extends PagerAdapter {
    @Override
    public int getCount() {
        return 4;
    }

    @Override
    public boolean isViewFromObject(final View view, final Object object) {
        return view.equals(object);
    }

    @Override
    public void destroyItem(final View container, final int position, final Object object) {
        ((ViewPager) container).removeView((View) object);
    }

    @Override
    public Object instantiateItem(final ViewGroup container, final int position) {
        final View view = LayoutInflater.from(
                getBaseContext()).inflate(R.layout.activity_approval, null, false);
        container.addView(view);
        ListView listView = (ListView) view.findViewById(R.id.list_view);
        view.setTag(position);
        new ShowContentListTask(listView, position).execute();
        return view;
    }
}

그리고 데이터가 변경 될 때 :

for (int i = 0; i < 4; i++) {
    View view = contentViewPager.findViewWithTag(i);
    if (view != null) {
        ListView listView = (ListView) view.findViewById(R.id.list_view);
        new ShowContentListTask(listView, i).execute();
    }
}

4

누군가 FragmentStatePagerAdapter 기반 어댑터를 사용하는 경우 (ViewPager가 표시 목적에 필요한 최소 페이지를 만들 수 있습니다 (최대 2)), @ rui.araujo의 어댑터에서 getItemPosition을 덮어 쓰는 대답은 심각한 낭비를 일으키지 않지만 여전히 낭비입니다. 향상 될 수 있습니다.

의사 코드에서 :

public int getItemPosition(Object object) {
    YourFragment f = (YourFragment) object;
    YourData d = f.data;
    logger.info("validate item position on page index: " + d.pageNo);

    int dataObjIdx = this.dataPages.indexOf(d);

    if (dataObjIdx < 0 || dataObjIdx != d.pageNo) {
        logger.info("data changed, discard this fragment.");
        return POSITION_NONE;
    }

    return POSITION_UNCHANGED;
}

ViewPager 내에서 항목 과거 위치를 아는 것은 매우 쉬웠으며, 가장 완벽한 구현은 getItemPosition()데이터 세트가 변경되었을 때 새로운 위치를 반환하는 것입니다 .ViewPager는 변경 여부를 알 수 있습니다. 슬프게도 ViewPager는하지 않았습니다.
VinceStyling

3

비슷한 문제가있어서 4 페이지가 있고 페이지 중 하나가 다른 3 개의 뷰를 업데이트했습니다. 현재 페이지와 인접한 페이지에서 위젯 (SeekBars, TextViews 등)을 업데이트 할 수있었습니다. 를 호출 할 때 마지막 두 페이지에는 초기화되지 않은 위젯이 있습니다 mTabsAdapter.getItem(position).

내 문제를 해결하기 위해 setSelectedPage(index)전화하기 전에 사용했습니다 getItem(position). 이렇게하면 페이지가 인스턴스화되어 각 페이지의 값과 위젯을 변경할 수 있습니다.

모든 업데이트 후에 나는 setSelectedPage(position)다음을 사용할 것입니다.notifyDataSetChanged() .

기본 업데이트 페이지의 ListView에 약간의 깜박임이 있지만 눈에 띄는 것은 없습니다. 나는 그것을 철저히 테스트하지는 않았지만 즉각적인 문제를 해결합니다.


안녕, 나는 당신의 코드에 관심이 있습니다, 나는 비슷한 문제에 직면하고있다, 나는 인접한 조각들을 업데이트 할 수 있지만 보이는 현재 조각은 업데이트되지 않는다. 나는 여기에 모든 대답과 혼동됩니다. VIewPager 어댑터에 의해 표시된 현재 조각의 뷰를 업데이트하는 방법
Pankaj Nimgade

3

다른 사람이 유용하다고 생각하는 경우이 답변을 게시하고 있습니다. 똑같은 일을하기 위해 호환성 라이브러리에서 ViewPager 및 PagerAdapter의 소스 코드를 가져 와서 내 코드로 컴파일했습니다 (모든 오류를 가져 와서 가져와야하지만 확실히 수행 할 수 있습니다).

그런 다음 CustomViewPager에서 updateViewAt (int position)이라는 메소드를 작성하십시오. 뷰 자체는 ViewPager 클래스에 정의 된 ArrayList mItems에서 가져올 수 있습니다 (인스턴스화 항목에서 뷰의 ID를 설정하고이 ID를 updateViewAt () 메소드의 위치와 비교해야 함). 그런 다음 필요에 따라보기를 업데이트 할 수 있습니다.


2

ViewPager의 논리가 있다고 생각합니다.

페이지 세트를 새로 고치고 새 데이터 세트를 기반으로 페이지를 표시해야하는 경우 notifyDataSetChanged ()를 호출 합니다. 그런 다음 ViewPager는 getItemPosition () 을 여러 번 호출하여 Fragment를 Object로 전달합니다. 이 조각은 오래된 데이터 세트 (폐기하려는) 또는 새로운 데이터 세트 (표시하려는) 중 하나 일 수 있습니다. 그래서 getItemPosition ()을 재정의합니다. 하고 내 Fragment가 이전 데이터 세트 또는 새 데이터 세트인지 확인해야합니다.

필자의 경우 왼쪽 창에 상위 항목 목록이 있고 오른쪽에 스 와이프보기 (ViewPager)가있는 2 창 레이아웃이 있습니다. 따라서 현재 상단 항목에 대한 링크를 PagerAdapter 내부 및 각 인스턴스화 된 페이지 조각 안에 저장합니다. 목록에서 선택한 상위 항목이 변경되면 PagerAdapter에 새 상위 항목을 저장하고 notifyDataSetChanged ()를 호출 합니다. 그리고 재정의 된 getItemPosition () 에서 내 어댑터의 최상위 항목과 내 조각의 최상위 항목을 비교합니다. 그리고 그들이 같지 않은 경우에만 POSITION_NONE을 반환합니다. 그런 다음 PagerAdapter는 POSITION_NONE을 반환 한 모든 조각을 다시 인스턴스화합니다.

노트. 참조 대신 최상위 항목 ID를 저장하는 것이 좋습니다.

아래 코드 스 니펫은 약간 개략적이지만 실제로 작동하는 코드에서 수정했습니다.

public class SomeFragment extends Fragment {
  private TopItem topItem;
}

public class SomePagerAdapter extends FragmentStatePagerAdapter {
  private TopItem topItem;

  public void changeTopItem(TopItem newTopItem) {
    topItem = newTopItem;
    notifyDataSetChanged();
  }

  @Override
  public int getItemPosition(Object object) {
    if (((SomeFragment) object).getTopItemId() != topItem.getId()) {
      return POSITION_NONE;
    }
    return super.getItemPosition(object);
  }
}

모든 이전 연구원들에게 감사합니다!


2

아래 코드는 저에게 효과적이었습니다.

아래와 같이 FragmentPagerAdapter 클래스를 확장하는 클래스를 작성하십시오.

public class Adapter extends FragmentPagerAdapter {

private int tabCount;
private Activity mActivity;
private Map<Integer, String> mFragmentTags;
private FragmentManager mFragmentManager;
private int container_id;
private ViewGroup container;
private List<Object> object;

public Adapter(FragmentManager fm) {
    super(fm);
}

public Adapter(FragmentManager fm, int numberOfTabs , Activity mA) {
    super(fm);
    mActivity = mA;
    mFragmentManager = fm;
    object = new ArrayList<>();
    mFragmentTags = new HashMap<Integer, String>();
    this.tabCount = numberOfTabs;
}

@Override
public Fragment getItem(int position) {
    switch (position) {
        case 0:
            return Fragment0.newInstance(mActivity);
        case 1:
            return Fragment1.newInstance(mActivity);
        case 2:
            return Fragment2.newInstance(mActivity);
        default:
            return null;
    }}


@Override
public Object instantiateItem(ViewGroup container, int position) {
    Object object = super.instantiateItem(container, position);
    if (object instanceof Fragment) {
        Log.e("Already defined","Yes");
        Fragment fragment = (Fragment) object;
        String tag = fragment.getTag();
        Log.e("Fragment Tag","" + position + ", " + tag);
        mFragmentTags.put(position, tag);
    }else{
        Log.e("Already defined","No");
    }
    container_id = container.getId();
    this.container = container;
    if(position == 0){
        this.object.add(0,object);
    }else if(position == 1){
        this.object.add(1,object);
    }else if(position == 2){
        this.object.add(2,object);
    }
    return object;
}

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
    super.destroyItem(container, position, object);
    if (object instanceof Fragment) {
        Log.e("Removed" , String.valueOf(position));
    }
}

@Override
public int getItemPosition (Object object)
{   int index = 0;
    if(this.object.get(0) == object){
        index = 0;
    }else if(this.object.get(1) == object){
        index = 1;
    }else if(this.object.get(2) == object){
        index = 2;
    }else{
        index = -1;
    }
    Log.e("Index" , "..................." + String.valueOf(index));
    if (index == -1)
        return POSITION_NONE;
    else
        return index;
}

public String getFragmentTag(int pos){
    return "android:switcher:"+R.id.pager+":"+pos;
}

public void NotifyDataChange(){
    this.notifyDataSetChanged();
}

public int getcontainerId(){
    return container_id;
}

public ViewGroup getContainer(){
    return this.container;
}

public List<Object> getObject(){
    return this.object;
}

@Override
public int getCount() {
    return tabCount;
}}

그런 다음 생성 한 각 Fragment 안에 updateFragment 메서드를 만듭니다. 이 방법에서는 조각에서 변경해야 할 사항을 변경합니다. 예를 들어 Fragment0에는 .ply 파일의 경로를 기반으로 3D 객체를 표시하는 GLSurfaceView가 포함되어 있으므로 updateFragment 메서드 내 에서이 플라이 파일의 경로를 변경합니다.

그런 다음 ViewPager 인스턴스를 만들고

viewPager = (ViewPager) findViewById(R.id.pager);

Adpater 인스턴스,

adapter = new Adapter(getSupportFragmentManager(), 3, this);

그런 다음

viewPager.setAdapter(adapter);
viewPager.setOffscreenPageLimit(1);

그런 다음 클래스 내부에서 위의 어댑터 클래스를 초기화하고 viewPager를 작성했습니다. 조각 중 하나 (이 경우 Fragment0)를 업데이트 할 때마다 다음을 사용하십시오.

adapter.NotifyDataChange();

adapter.destroyItem(adapter.getContainer(), 0, adapter.getObject().get(0)); // destroys page 0 in the viewPager.

fragment0 = (Fragment0) getSupportFragmentManager().findFragmentByTag(adapter.getFragmentTag(0)); // Gets fragment instance used on page 0.

fragment0.updateFragment() method which include the updates on this fragment

adapter.instantiateItem(adapter.getContainer(), 0); // re-initialize page 0.

이 솔루션은 Alvaro Luis Bustamante가 제안한 기술을 기반으로했습니다.


1

1. 먼저 Pageradapter 클래스에서 getItemposition 메소드를 설정해야합니다. 2. View Pager의 정확한 위치를 읽어야합니다. 3. 그런 다음 해당 위치를 새 위치의 데이터 위치로 보냅니다. 4. setonPageChange 내의 클릭 리스너에서 업데이트 버튼 쓰기 경청자

그 프로그램 코드는 약간만 특정 위치 요소 만 설정하도록 수정되었습니다.

public class MyActivity extends Activity {

private ViewPager myViewPager;
private List<String> data;
public int location=0;
public Button updateButton;
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    data = new ArrayList<String>();
    data.add("A");
    data.add("B");
    data.add("C");
    data.add("D");
    data.add("E");
    data.add("F");

    myViewPager = (ViewPager) findViewById(R.id.pager);
    myViewPager.setAdapter(new MyViewPagerAdapter(this, data));

      updateButton = (Button) findViewById(R.id.update);

    myViewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
        @Override
        public void onPageScrolled(int i, float v, int i2) {
             //Toast.makeText(MyActivity.this, i+"  Is Selected  "+data.size(), Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onPageSelected( int i) {
          // here you will get the position of selected page
            final int k = i;
             updateViewPager(k);

        }

        @Override
        public void onPageScrollStateChanged(int i) {

        }
    });
}

private void updateViewPager(final int i) {  
    updateButton.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {

            Toast.makeText(MyActivity.this, i+"  Is Selected  "+data.size(), Toast.LENGTH_SHORT).show();
            data.set(i, "Replaced "+i);         
            myViewPager.getAdapter().notifyDataSetChanged();
        }
    });

}

private class MyViewPagerAdapter extends PagerAdapter {

    private List<String> data;
    private Context ctx;

    public MyViewPagerAdapter(Context ctx, List<String> data) {
        this.ctx = ctx;
        this.data = data;
    }

    @Override
    public int getCount() {
        return data.size();
    }

    @Override
    public int getItemPosition(Object object) {
        return POSITION_NONE;
    }

    @Override
    public Object instantiateItem(View collection, int position) {          

        TextView view = new TextView(ctx);
        view.setText(data.get(position));
        ((ViewPager)collection).addView(view);            
        return view;
    }

    @Override
    public void destroyItem(View collection, int position, Object view) {
         ((ViewPager) collection).removeView((View) view);
    }

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view == object;
    }

    @Override
    public Parcelable saveState() {
        return null;
    }

    @Override
    public void restoreState(Parcelable arg0, ClassLoader arg1) {
    }

    @Override
    public void startUpdate(View arg0) {
    }

    @Override
    public void finishUpdate(View arg0) {
    }
}
}

1

나를 위해 일한 것은 가고 있었다 viewPager.getAdapter().notifyDataSetChanged();

어댑터에 뷰 내부를 업데이트하는 코드를 넣어 getItemPosition과 같이

@Override
public int getItemPosition(Object object) {

    if (object instanceof YourViewInViewPagerClass) { 
        YourViewInViewPagerClass view = (YourViewInViewPagerClass)object;
        view.setData(data);
    }

    return super.getItemPosition(object);
}

가장 올바른 방법은 아니지만 작동했습니다 ( return POSITION_NONE트릭으로 인해 충돌이 발생하여 옵션 이 없었습니다 )


1

모든 조각을 동적으로 업데이트 할 수 있으며 세 단계로 볼 수 있습니다.

어댑터에서 :

public class MyPagerAdapter extends FragmentPagerAdapter {
private static int NUM_ITEMS = 3;
private Map<Integer, String> mFragmentTags;
private FragmentManager mFragmentManager;

public MyPagerAdapter(FragmentManager fragmentManager) {
    super(fragmentManager);
    mFragmentManager = fragmentManager;
    mFragmentTags = new HashMap<Integer, String>();
}

// Returns total number of pages
@Override
public int getCount() {
    return NUM_ITEMS;
}

// Returns the fragment to display for that page
@Override
public Fragment getItem(int position) {
    switch (position) {
        case 0:
            return FirstFragment.newInstance();
        case 1:
            return SecondFragment.newInstance();
        case 2:
            return ThirdFragment.newInstance();
        default:
            return null;
    }
}

// Returns the page title for the top indicator
@Override
public CharSequence getPageTitle(int position) {
    return "Page " + position;
}

@Override
public Object instantiateItem(ViewGroup container, int position) {
    Object object = super.instantiateItem(container, position);
    if (object instanceof Fragment) {
        Fragment fragment = (Fragment) object;
        String tag = fragment.getTag();
        mFragmentTags.put(position, tag);
    }
    return object;
}

public Fragment getFragment(int position) {
    Fragment fragment = null;
    String tag = mFragmentTags.get(position);
    if (tag != null) {
        fragment = mFragmentManager.findFragmentByTag(tag);
    }
    return fragment;
}}

이제 당신의 활동에서 :

public class MainActivity extends AppCompatActivity implements ViewPager.OnPageChangeListener{

MyPagerAdapter mAdapterViewPager;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    ViewPager viewPager = (ViewPager) findViewById(R.id.vpPager);
    mAdapterViewPager = new MyPagerAdapter(getSupportFragmentManager());
    viewPager.setAdapter(mAdapterViewPager);
    viewPager.addOnPageChangeListener(this);
}

@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

}

@Override
public void onPageSelected(int position) {

    Fragment fragment = mAdapterViewPager.getFragment(position);
    if (fragment != null) {
        fragment.onResume();
    }
}

@Override
public void onPageScrollStateChanged(int state) {

}}

마지막으로 조각에서 다음과 같이하십시오.

public class YourFragment extends Fragment {

// newInstance constructor for creating fragment with arguments
public static YourFragment newInstance() {

    return new YourFragment();
}

// Store instance variables based on arguments passed
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
}

// Inflate the view for the fragment based on layout XML
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    return inflater.inflate(R.layout.fragment, container, false);
}


@Override
public void onResume() {
    super.onResume();

    //to refresh your view
    refresh();

}}

당신은 여기에 완전한 코드를 볼 수 있습니다 .

감사합니다 Alvaro Luis Bustamante.


1

항상 반환하는 POSITION_NONE것은 간단하지만 비효율적 인 방법이므로 이미 인스턴스화 된 모든 페이지의 인스턴스를 생성하기 때문입니다.

라이브러리 ArrayPagerAdapter를 만들었습니다. 항목을 동적으로 변경하기 를 .

내부적으로이 라이브러리의 어댑터 POSITION_NONEgetItemPosiition() 필요할 때만 .

이 라이브러리를 사용하여 다음과 같이 항목을 동적으로 변경할 수 있습니다.

@Override
protected void onCreate(Bundle savedInstanceState) {
        /** ... **/
    adapter = new MyStatePagerAdapter(getSupportFragmentManager()
                            , new String[]{"1", "2", "3"});
    ((ViewPager)findViewById(R.id.view_pager)).setAdapter(adapter);
     adapter.add("4");
     adapter.remove(0);
}

class MyPagerAdapter extends ArrayViewPagerAdapter<String> {

    public MyPagerAdapter(String[] data) {
        super(data);
    }

    @Override
    public View getView(LayoutInflater inflater, ViewGroup container, String item, int position) {
        View v = inflater.inflate(R.layout.item_page, container, false);
        ((TextView) v.findViewById(R.id.item_txt)).setText(item);
        return v;
    }
}

Thils 라이브러리는 Fragments에서 만든 페이지도 지원합니다.


1

이것은 나와 같은 모든 사람들을위한 것이며 서비스 (또는 다른 백그라운드 스레드)에서 Viewpager를 업데이트해야하지만 제안이 전혀 작동하지 않았습니다. 약간의 로그 확인 후, notifyDataSetChanged () 메소드는 절대 반환하지 않습니다. getItemPosition (Object object)은 추가 처리없이 모든 끝에서 호출됩니다. 그런 다음 부모 PagerAdapter 클래스의 문서 (하위 클래스의 문서에는 없음)에서 "데이터 세트 변경이 기본 스레드에서 발생해야하며 notifyDataSetChanged ()에 대한 호출로 끝나야합니다." 따라서이 경우 작동하는 솔루션은 FragmentStatePagerAdapter 및 getItemPosition (Object object)을 사용하여 POSITION_NONE을 반환하도록 설정 한 것입니다.

그런 다음 notifyDataSetChanged ()에 대한 호출 :

runOnUiThread(new Runnable() {
         @Override
         public void run() {
             pager.getAdapter().notifyDataSetChanged();
         }
     });

1

Viewpager에서 다음과 같이 호출기 변환을 추가 할 수 있습니다

myPager.setPageTransformer(true, new MapPagerTransform());

아래 코드에서 호출기를 스크롤 할 때 런타임에 뷰 색상을 변경했습니다.

public class MapPagerTransform implements ViewPager.PageTransformer {


    public void transformPage(View view, float position) {
     LinearLayout  showSelectionLL=(LinearLayout)view.findViewById(R.id.showSelectionLL);

     if (position < 0) {

                showSelectionLL.setBackgroundColor(Color.WHITE);
     }else if (position >0){

                showSelectionLL.setBackgroundColor(Color.WHITE);
     }else {
                showSelectionLL.setBackgroundColor(Color.RED);
     }
   }
}

1

나는 메신저 댐을 늦게 알고 있지만 여전히 누군가를 도울 수 있습니다. 나는 단지 accetping 답변을 확장하고 그것에 대한 의견을 추가했습니다.

잘,

대답 자체는 비효율적이라고 말합니다.

필요할 때만 새로 고침하기 위해이 작업을 수행 할 수 있습니다.

private boolean refresh;

public void refreshAdapter(){
    refresh = true;
    notifyDataSetChanged();
}

@Override
public int getItemPosition(@NonNull Object object) {
    if(refresh){
        refresh = false;
        return POSITION_NONE;
    }else{
        return super.getItemPosition(object);
    }
}

1

ViewPager는 동적 뷰 변경을 지원하도록 설계되지 않았습니다.

https://issuetracker.google.com/issues/36956111 , 특히 https://issuetracker.google.com/issues/36956111#comment56 과 관련된 다른 버그를 찾는 동안 확인했습니다.

이 질문은 조금 오래되었지만 Google은 최근 ViewPager2 로이 문제를 해결했습니다 . 수제 (유지 및 버그 가능성이있는) 솔루션을 표준 솔루션으로 대체 할 수 있습니다. 또한 일부 답변과 마찬가지로 뷰를 불필요하게 다시 작성하는 것을 방지합니다.

ViewPager2 예제의 경우 https://github.com/googlesamples/android-viewpager2 를 확인할 수 있습니다

ViewPager2를 사용하려면 build.gradle 파일에 다음과 같은 종속성을 추가해야합니다.

  dependencies {
     implementation 'androidx.viewpager2:viewpager2:1.0.0-beta02'
  }

그런 다음 xml 파일의 ViewPager를 다음으로 바꿀 수 있습니다.

    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/pager"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />

그런 다음 활동에서 ViewPager를 ViewPager2로 교체해야합니다.

ViewPager2에는 RecyclerView.Adapter 또는 FragmentStateAdapter가 필요합니다.이 경우에는 RecyclerView.Adapter 일 수 있습니다.

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import java.util.ArrayList;

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {

    private Context context;
    private ArrayList<String> arrayList = new ArrayList<>();

    public MyAdapter(Context context, ArrayList<String> arrayList) {
        this.context = context;
        this.arrayList = arrayList;
    }

    @NonNull
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(context).inflate(R.layout.list_item, parent, false);
        return new MyViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
        holder.tvName.setText(arrayList.get(position));
    }

    @Override
    public int getItemCount() {
        return arrayList.size();
    }

    public class MyViewHolder extends RecyclerView.ViewHolder {
        TextView tvName;

        public MyViewHolder(@NonNull View itemView) {
            super(itemView);
            tvName = itemView.findViewById(R.id.tvName);
        }
    }
} 

TabLayout을 사용하는 경우 TabLayoutMediator를 사용할 수 있습니다.

        TabLayoutMediator tabLayoutMediator = new TabLayoutMediator(tabLayout, viewPager, true, new TabLayoutMediator.OnConfigureTabCallback() {
            @Override
            public void onConfigureTab(@NotNull TabLayout.Tab tab, int position) {
                // configure your tab here
                tab.setText(tabs.get(position).getTitle());
            }
        });

        tabLayoutMediator.attach();

그런 다음 어댑터의 데이터를 수정하고 notifyDataSetChanged 메소드를 호출하여보기를 새로 고칠 수 있습니다.



0

데이터 세트 변경 사항을 알리는 간단한 방법을 만들었다 고 생각합니다.

먼저 instantiateItem 함수가 작동하는 방식을 약간 변경하십시오.

    @Override
    public Object instantiateItem(final ViewGroup container, final int position) {
        final View rootView = mInflater.inflate(...,container, false);
        rootView.setTag(position);
        updateView(rootView, position);
        container.addView(rootView, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
        mViewPager.setObjectForPosition(rootView, position);
        return rootView;
    }

"updateView"의 경우 채우려는 모든 데이터 (setText, setBitmapImage, ...)로보기를 채우십시오.

destroyView가 다음과 같이 작동하는지 확인하십시오.

    @Override
    public void destroyItem(final ViewGroup container, final int position, final Object obj) {
        final View viewToRemove = (View) obj;
        mViewPager.removeView(viewToRemove);
    }

이제 데이터를 변경 한 다음 PagerAdapter에서 다음 함수를 호출해야한다고 가정 해 봅시다.

    public void notifyDataSetChanged(final ViewPager viewPager, final NotifyLocation fromPos,
            final NotifyLocation toPos) {
        final int offscreenPageLimit = viewPager.getOffscreenPageLimit();
        final int fromPosInt = fromPos == NotifyLocation.CENTER ? mSelectedPhotoIndex
                : fromPos == NotifyLocation.MOST_LEFT ? mSelectedPhotoIndex - offscreenPageLimit
                        : mSelectedPhotoIndex + offscreenPageLimit;
        final int toPosInt = toPos == NotifyLocation.CENTER ? mSelectedPhotoIndex
                : toPos == NotifyLocation.MOST_LEFT ? mSelectedPhotoIndex - offscreenPageLimit
                        : mSelectedPhotoIndex + offscreenPageLimit;
        if (fromPosInt <= toPosInt) {
            notifyDataSetChanged();
            for (int i = fromPosInt; i <= toPosInt; ++i) {
                final View pageView = viewPager.findViewWithTag(i);
                mPagerAdapter.updateView(pageView, i);
            }
        }
    }

public enum NotifyLocation {
    MOST_LEFT, CENTER, MOST_RIGHT
}

예를 들어, viewPager에 의해 표시되는 모든보기에 무언가 변경된 것을 알리려면 다음을 호출하십시오.

notifyDataSetChanged(mViewPager,NotifyLocation.MOST_LEFT,NotifyLocation.MOST_RIGHT);

그게 다야.


0

가치가 높은 것으로 KitKat +에서는 충분히 높은 adapter.notifyDataSetChanged()경우 새로운 견해를 표시하기에 setOffscreenPageLimit충분합니다. 를 수행하여 원하는 동작을 얻을 수 있습니다 viewPager.setOffscreenPageLimit(2).


0

실제로 사용 notifyDataSetChanged()ViewPagerCirclePageIndicator내가 부르는 이후 destroyDrawingCache()ViewPager그리고 .. 다른 솔루션 중에 나를 위해 일하지 작동합니다.


원래 질문은 거의 2 세입니다 .Android API에는 많은 차이점이 있으므로 여기에 대한 답변이 모든 버전의 Android API에 적합하지 않을 수 있습니다.
C0deAttack
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.