ViewPager PagerAd CHƯƠNG không cập nhật View


597

Tôi đang sử dụng ViewPager từ thư viện tương thích. Tôi đã thành công trong việc hiển thị một số lượt xem mà tôi có thể xem qua.

Tuy nhiên, tôi đang gặp khó khăn khi tìm cách cập nhật ViewPager với một nhóm Chế độ xem mới.

Tôi đã thử tất cả mọi thứ như gọi điện mAdapter.notifyDataSetChanged(),mViewPager.invalidate() thậm chí tạo một bộ chuyển đổi hoàn toàn mới mỗi lần tôi muốn sử dụng Danh sách dữ liệu mới.

Không có gì giúp được, các bài viết vẫn không thay đổi so với dữ liệu gốc.

Cập nhật: Tôi đã thực hiện một dự án thử nghiệm nhỏ và tôi gần như có thể cập nhật các chế độ xem. Tôi sẽ dán lớp bên dưới.

Tuy nhiên, thứ không xuất hiện để cập nhật là chế độ xem thứ 2, 'B' vẫn còn, nó sẽ hiển thị 'Y' sau khi nhấn nút cập nhật.

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
Vui lòng xem stackoverflow.com/questions/12510404/ khăn để tìm lỗi tiềm ẩn với FragmentStatePagerAd CHƯƠNG.
samis

2
Xin lỗi để nạo vét này lên. Câu hỏi của bạn thực sự đã giúp tôi rất cảm ơn! Một điều tôi không nhận được là cách tham chiếu đến dữ liệu trong PagerAd CHƯƠNG được thay đổi khi bạn cập nhật nó trong Hoạt động
Ewanw 13/07/2015

Làm cho bộ điều hợp của bạn mở rộng BaseAd CHƯƠNG Tham khảo điều này: stackoverflow.com/questions/13664155/ trên

1
Rõ ràng nếu bạn đặt lại bộ điều hợp cho máy nhắn tin xem, thì nó sẽ đặt lại.
EpicPandaForce

tôi có vấn đề trong pager stackoverflow.com/questions/41217237/ từ
chris

Câu trả lời:


856

Có một số cách để đạt được điều này.

Tùy chọn đầu tiên dễ dàng hơn, nhưng không hiệu quả hơn một chút.

Ghi đè getItemPositiontrong của bạn PagerAdapternhư thế này:

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

Bằng cách này, khi bạn gọi notifyDataSetChanged(), máy nhắn tin xem sẽ xóa tất cả các chế độ xem và tải lại tất cả. Như vậy hiệu ứng tải lại thu được.

Tùy chọn thứ hai, được đề xuất bởi Alvaro Luis Bustamante (trước đây là alvarolb) , là setTag()phương pháp instantiateItem()khi khởi tạo một chế độ xem mới. Sau đó, thay vì sử dụng notifyDataSetChanged(), bạn có thể sử dụng findViewWithTag()để tìm chế độ xem bạn muốn cập nhật.

Cách tiếp cận thứ hai là rất linh hoạt và hiệu suất cao. Kudos để alvarolb cho nghiên cứu ban đầu.


4
Tốt hơn so với công việc của tôi xung quanh, dường như không có bất kỳ bên nào ảnh hưởng, cảm ơn.
C0deAttack

3
Tôi có một vấn đề tương tự. ViewPager của tôi sẽ hiển thị kết quả searc mới nhưng không mặc định trở lại mục nhập đầu tiên trong con trỏ. Có ai biết làm thế nào để thiết lập lại vị trí khi cập nhật tập dữ liệu?
mAndroid

1
@mAndroid bạn nên gửi một câu hỏi riêng với nhiều chi tiết hơn.
rui.araujo

1
trả về POSITION_NONE rõ ràng sẽ bổ sung rất nhiều sự kém hiệu quả cho ứng dụng tổng thể vì điều này khiến Android xóa chế độ xem được liên kết với vị trí được yêu cầu. Chế độ xem sau đó cần được tạo lại một lần nữa trước khi hiển thị. Giải quyết vấn đề về lượt xem không được cập nhật, nhưng có lẽ không phải là giải pháp tốt nhất cho bố cục phức tạp.
wufoo

11
Câu trả lời tốt hơn (không xóa tất cả các mục) -> stackoverflow.com/a/10852046/898056
yhpark

484

Tôi không nghĩ có bất kỳ loại lỗi nào trong PagerAdapter . Vấn đề là cách hiểu nó hoạt động hơi phức tạp. Nhìn vào các giải pháp được giải thích ở đây, có một sự hiểu lầm và do đó sử dụng kém các quan điểm tức thời theo quan điểm của tôi.

Vài ngày qua tôi đã làm việc với PagerAdapterViewPager, và tôi đã tìm thấy như sau:

Các notifyDataSetChanged()phương pháp trên PagerAdaptersẽ chỉ thông báo cho ViewPagerrằng các trang cơ bản đã thay đổi. Ví dụ: nếu bạn đã tạo / xóa các trang một cách linh hoạt (thêm hoặc xóa các mục khỏi danh sách của bạn) thì ViewPagerbạn nên xử lý việc đó. Trong trường hợp này, tôi nghĩ rằng việc ViewPagerxác định xem một chế độ xem mới có nên bị xóa hoặc khởi tạo bằng cách sử dụng getItemPosition()getCount()phương thức hay không.

Tôi nghĩ rằng ViewPager, sau khi một notifyDataSetChanged()cuộc gọi đưa ra quan điểm của trẻ và kiểm tra vị trí của chúng với getItemPosition(). Nếu đối với một khung nhìn con, phương thức này trả về POSITION_NONE, thì ViewPagerhiểu rằng khung nhìn đã bị xóa, gọi destroyItem()và loại bỏ khung nhìn này.

Theo cách này, ghi đè getItemPosition()để luôn quay lại POSITION_NONElà hoàn toàn sai nếu bạn chỉ muốn cập nhật nội dung của các trang, bởi vì các lượt xem được tạo trước đó sẽ bị hủy và những lượt xem mới sẽ được tạo mỗi khi bạn gọi notifyDatasetChanged(). Nó có vẻ không quá sai chỉ trong một vài TextViewgiây, nhưng khi bạn có các chế độ xem phức tạp, như ListViews được điền từ cơ sở dữ liệu, đây có thể là một vấn đề thực sự và lãng phí tài nguyên.

Vì vậy, có một số cách tiếp cận để thay đổi hiệu quả nội dung của chế độ xem mà không phải xóa và khởi tạo lại chế độ xem. Nó phụ thuộc vào vấn đề bạn muốn giải quyết. Cách tiếp cận của tôi là sử dụng setTag()phương thức cho bất kỳ chế độ xem tức thời nào trong instantiateItem()phương thức. Vì vậy, khi bạn muốn thay đổi dữ liệu hoặc làm mất hiệu lực chế độ xem mà bạn cần, bạn có thể gọi findViewWithTag()phương thức trên ViewPagerđể truy xuất chế độ xem được khởi tạo trước đó và sửa đổi / sử dụng nó theo ý muốn mà không phải xóa / tạo chế độ xem mới mỗi lần bạn muốn để cập nhật một số giá trị.

Ví dụ, hãy tưởng tượng rằng bạn có 100 trang với 100 TextViewgiây và bạn chỉ muốn cập nhật một giá trị theo định kỳ. Với các cách tiếp cận được giải thích trước đây, điều này có nghĩa là bạn đang xóa và khởi tạo 100 TextViewgiây trên mỗi bản cập nhật. Nó chả có nghĩa gì cả...


11
+1 - Giải pháp của bạn không chỉ hoạt động như một cơ duyên mà tôi gặp phải chính xác vấn đề bạn mô tả ở đây khi tôi phải cập nhật các trang có chứa các tab với danh sách xem, xem xét và hình ảnh. (OutOfErrorExceptions và như vậy ...) Cảm ơn bạn!
schlingel

3
@alvarolb: Xin chào, tôi thực sự không biết ý của bạn về setTagphương pháp onInstantiateItem, bạn có muốn cập nhật câu trả lời này với một số mã hóa không? Cảm ơn.
Tháp Huy

35
Nó sẽ là hoàn hảo nếu bạn viết một ví dụ.
Sami Eltamawy

13
Như ai đó nói: một ví dụ woulb được đánh giá cao!
Jey10

15
6 năm nay, không ai có thể đưa ra một ví dụ.
Oussaki

80

Thay đổi FragmentPagerAdapterthànhFragmentStatePagerAdapter .

getItemPosition()Phương thức ghi đè và trả vềPOSITION_NONE .

Cuối cùng, nó sẽ lắng nghe notifyDataSetChanged()máy nhắn tin xem.


Tôi nghĩ rằng bạn nên triển khai toàn bộ getItemPocation đúng cách và trả lại POSITION_NONE nếu không tìm thấy đoạn này.
tkhduracell

46

Câu trả lời được đưa ra bởi alvarolb chắc chắn là cách tốt nhất để làm điều đó. Dựa trên câu trả lời của anh ấy, một cách dễ dàng để thực hiện điều này là chỉ cần lưu trữ các chế độ xem đang hoạt động theo vị trí:

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

Sau đó, một lần bằng cách ghi đè notifyDataSetChangedphương thức, bạn có thể làm mới lượt xem ...

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

Bạn thực sự có thể sử dụng mã tương tự trong instantiateItemnotifyDataSetChangedđể làm mới quan điểm của bạn. Trong mã của tôi, tôi sử dụng cùng một phương pháp.


8
bạn có thể cung cấp một ví dụ bộ chuyển đổi đầy đủ? điều này có được thực hiện bằng cách sử dụng Fragment hay không?

9
<làm mới chế độ xem với dữ liệu mới> ?? ý nghĩa của nó là gì hoặc chúng ta phải thêm anh ta xem ở đây hoặc không có gì?
Akarsh M

Phương pháp này cập nhật tất cả các quan điểm. Nếu bạn chỉ muốn cập nhật một chế độ xem, thì bạn có thể viết phương thức notifyDataItemChanged của riêng bạn như thế này: public void notifyDataItemChanged (int pos) {TextView tv = (TextView) view.get (pos) .findViewById (R.id.tv); tv.setText (list.get (pos)); super.notifyDataSetChanged (); }
Kai Wang

Mã này gặp sự cố nếu kích thước máy nhắn tin mới nhỏ hơn kích thước cũ
Anton Duzenko

@AntonDuzenko đúng, xóa lượt xem khá khó.
MLProgrammer-CiM

28

Có cùng một vấn đề. Đối với tôi, nó đã hoạt động để mở rộng FragmentStatePagerAd CHƯƠNG và ghi đè các phương thức dưới đây:

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

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

}

Đây là giải pháp duy nhất làm việc cho tôi quá. Trường hợp của tôi không cập nhật đoạn, nhưng loại bỏ hoặc thêm đoạn một cách linh hoạt. Không mở rộng FragmentStatePagerAdOG, ViewPager trả về các đoạn được lưu trong bộ nhớ cache, đây là một vị trí không chính xác. Cảm ơn!
Sira Lam

Hoạt động tốt trên thư viện hỗ trợ 28.0.0
Oleksii K.

Ghi đè để làm gì? Làm cách nào để tạo một đối tượng trạng thái được liên kết với Bộ điều hợp?
Phani Rithvij

Cảm ơn cậu. Giải pháp này chỉ hoạt động
Parthi

20

Sau giờ thất vọng khi cố gắng tất cả các giải pháp trên để khắc phục vấn đề này và cũng cố gắng rất nhiều giải pháp về các vấn đề khác tương tự như này , nàynày mà tất cả FAILED với tôi để giải quyết vấn đề này và để thực hiện ViewPagerđể tiêu diệt cái cũ Fragmentvà lấp đầy pagervới Fragments mới . Tôi đã giải quyết vấn đề như sau:

1) Làm cho ViewPagerlớp mở rộng FragmentPagerAdapternhư sau:

 public class myPagerAdapter extends FragmentPagerAdapter {

2) Tạo một mục cho ViewPagercửa hàng đó titlefragmentnhư sau:

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) Tạo hàm tạo của cá thể ViewPagercủa tôi FragmentManagerđể lưu trữ nó trong của tôi classnhư sau:

private FragmentManager mFragmentManager;
private ArrayList<PagerItem> mPagerItems;

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

4) Tạo ra một phương pháp để tái thiết lập các adapterdữ liệu với các dữ liệu mới bằng cách xóa tất cả các trước fragmenttừ fragmentManagerbản thân trực tiếp để thực hiện adapterđể thiết lập mới fragmenttừ danh sách mới một lần nữa như sau:

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) Từ bộ chứa Activityhoặc Fragmentkhông khởi tạo lại bộ chuyển đổi với dữ liệu mới. Đặt dữ liệu mới thông qua phương thức setPagerItemsvới dữ liệu mới như sau:

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

Tôi hy vọng nó sẽ giúp.


@Tom vấn đề bạn gặp phải là gì?
Sami Eltamawy


9

Tôi đã có cùng một vấn đề và giải pháp của tôi đang sử dụng FragmentPagerAdaptervới phần ghi đè FragmentPagerAdapter#getItemId(int position):

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

Theo mặc định, phương thức này trả về vị trí của mục. Tôi cho rằng ViewPagerkiểm tra nếu itemIdđã được thay đổi và chỉ tạo lại trang nếu có. Nhưng phiên bản không được ghi đè sẽ trả về cùng một vị trí như itemIdngay cả khi trang thực sự khác biệt và ViewPager không xác định trang đó được thay thế một trang và cần được tạo lại.

Để sử dụng điều này, long idlà cần thiết cho mỗi trang. Thông thường nó được dự kiến ​​là duy nhất, nhưng tôi đề nghị, trong trường hợp này, nó chỉ nên khác với giá trị trước đó cho cùng một trang. Vì vậy, có thể sử dụng bộ đếm liên tục trong bộ điều hợp hoặc số nguyên ngẫu nhiên (có phân phối rộng) tại đây.

Tôi nghĩ rằng đó là cách phù hợp hơn thay vì sử dụng Thẻ quan điểm được đề cập như một giải pháp trong chủ đề này. Nhưng có lẽ không phải cho tất cả các trường hợp.


1
Nó là. Tôi đã kiểm tra rồi: chỉ POSITION_NONE là không đủ. Cảm ơn bạn đã trả lời tuyệt vời của bạn! :)
Slava

Chức năng này thậm chí không có mặt trong PagerAdapter. Lớp học này là gì?
Saket

@Saket, bạn nói đúng, lớp học làFragmentPagerAdapter
atlascoder

6

Tôi tìm thấy quyết định rất thú vị của vấn đề này. Thay vì sử dụng FragmentPagerAd CHƯƠNG , bộ nhớ lưu giữ tất cả các đoạn, chúng ta có thể sử dụng FragmentStatePagerAd Module ( android.support.v4.app.FragmentStatePagerAd CHƯƠNG ), mỗi lần chúng ta tải lại đoạn đó.

Hiện thực của cả hai bộ điều hợp là giống hệt nhau. Vì vậy, chúng ta chỉ cần thay đổi " mở rộng FragmentPagerAd CHƯƠNG " trên " mở rộng FragmentStatePagerAd CHƯƠNG "


điểm hay, nó sẽ giúp người khác giải quyết các vấn đề về bộ nhớ của viewPager liên quan đến đoạn
Ashu Kumar

Câu trả lời tuyệt vời, điều này đã giúp tôi rất nhiều.
Sergio Marani

5

Sau rất nhiều tìm kiếm cho vấn đề này, tôi đã tìm thấy một giải pháp thực sự tốt mà tôi nghĩ là cách đúng đắn để giải quyết vấn đề này. Về cơ bản, InstantiateItem chỉ được gọi khi chế độ xem được khởi tạo và không bao giờ lặp lại trừ khi chế độ xem bị hủy (đây là điều xảy ra khi bạn ghi đè chức năng getItemPocation để trả về POSITION_NONE). Thay vào đó, những gì bạn muốn làm là tiết kiệm các chế độ xem đã tạo và cập nhật chúng trong bộ điều hợp, tạo chức năng get để người khác có thể cập nhật hoặc đặt một chức năng cập nhật bộ điều hợp (yêu thích của tôi).

Vì vậy, trong MyViewPagerAd CHƯƠNG của bạn, hãy thêm một biến như:

private View updatableView;

một trong ngay lập tức của bạn:

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

vì vậy, theo cách này, bạn có thể tạo một chức năng sẽ cập nhật chế độ xem của mình:

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

Hi vọng điêu nay co ich!


Tôi nhận ra rằng tôi đã không thiết lập dữ liệu theo instantiateItemlý do tại sao quan điểm của tôi không cập nhật. Từ câu trả lời của bạn, tôi nhận ra nó. +1
Phani Rithvij

5

Hai năm rưỡi sau khi OP đặt câu hỏi cho anh, vấn đề này vẫn còn, tốt, vẫn là một vấn đề. Đó là ưu tiên rõ ràng của Google về điều này không đặc biệt cao, vì vậy thay vì tìm cách khắc phục, tôi đã tìm thấy một cách giải quyết. Bước đột phá lớn đối với tôi là tìm ra nguyên nhân thực sự của vấn đề là gì (xem câu trả lời được chấp nhận trong bài đăng này ). Một khi rõ ràng vấn đề là bất kỳ trang hoạt động nào không được làm mới đúng cách, cách giải quyết của tôi là rõ ràng:

Trong mảnh vỡ của tôi (các trang):

  • Tôi đã lấy tất cả các mã điền vào biểu mẫu trên onCreateView và đặt nó vào một hàm có tên là PopulationForm có thể được gọi từ bất cứ đâu, thay vì theo khung. Hàm này cố gắng để có được Chế độ xem hiện tại bằng cách sử dụng getView và nếu đó là null, nó sẽ trả về. Điều quan trọng là PopulateForm chỉ chứa mã hiển thị - tất cả các mã khác tạo trình nghe FocusChange và tương tự vẫn nằm trong OnCreate
  • Tạo một boolean có thể được sử dụng làm cờ biểu thị biểu mẫu phải được tải lại. Của tôi là mbReloadForm
  • Ghi đè OnResume () để gọi PopulationForm () nếu mbReloadForm được đặt.

Trong Hoạt động của tôi, nơi tôi thực hiện tải các trang:

  • Chuyển đến trang 0 trước khi thay đổi bất cứ điều gì. Tôi đang sử dụng FragmentStatePagerAd CHƯƠNG, vì vậy tôi biết rằng hai hoặc ba trang bị ảnh hưởng nhiều nhất. Thay đổi sang trang 0 đảm bảo tôi chỉ gặp sự cố ở các trang 0, 1 và 2.
  • Trước khi xóa danh sách cũ, hãy lấy kích thước của nó (). Bằng cách này, bạn biết có bao nhiêu trang bị ảnh hưởng bởi lỗi. Nếu> 3, hãy giảm xuống còn 3 - nếu bạn đang sử dụng một PagerAd CHƯƠNG khác nhau, bạn sẽ phải xem bạn phải xử lý bao nhiêu trang (có thể là tất cả?)
  • Tải lại dữ liệu và gọi trangAd CHƯƠNG.notifyDataSetChanged ()
  • Bây giờ, đối với mỗi trang bị ảnh hưởng, hãy xem trang có hoạt động hay không bằng cách sử dụng pager.getChildAt (i) - điều này sẽ cho bạn biết nếu bạn có chế độ xem. Nếu vậy, hãy gọi pager.PopulationView (). Nếu không, đặt cờ Tải lại.

Sau này, khi bạn tải lại một bộ trang thứ hai, lỗi vẫn sẽ khiến một số trang hiển thị dữ liệu cũ. Tuy nhiên, giờ đây chúng sẽ được làm mới và bạn sẽ thấy dữ liệu mới - người dùng của bạn sẽ không biết trang đã từng không chính xác vì việc làm mới này sẽ xảy ra trước khi họ nhìn thấy trang.

Hy vọng điều này sẽ giúp được ai đó!


5

Tất cả những giải pháp này đã không giúp tôi. do đó tôi tìm thấy một giải pháp hiệu quả: Bạn có thể setAdaptermọi lúc, nhưng nó không đủ. bạn nên làm những điều này trước khi thay đổi bộ chuyển đổi:

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

và sau này:

viewPager.setAdapter(adapter);

Cảm ơn! Trong trường hợp của tôi, tôi đã sử dụng ViewPagerbên trong mảnh, vì vậy thay thế slideShowPagerAdapter.getFragmentManager()bằng getChildFragmentManager(). Có lẽ getFragmentManager()sẽ giúp trong trường hợp của bạn. Tôi đã sử dụng FragmentPagerAdapter, không FragmentStatePagerAdapter. Đồng thời xem stackoverflow.com/a/25994654/2914140 để biết cách hacky.
CoolMind

5

Một cách dễ dàng hơn nhiều: sử dụng FragmentPagerAdaptervà bọc các khung nhìn phân trang của bạn lên các mảnh. Họ được cập nhật


5

Cảm ơn rui.araujo và Alvaro Luis Bustamante. Lúc đầu, tôi cố gắng sử dụng cách của rui.araujo, vì nó dễ. Nó hoạt động nhưng khi dữ liệu thay đổi, trang sẽ vẽ lại rõ ràng. Thật tệ vì vậy tôi cố gắng sử dụng cách của Alvaro Luis Bustamante. Thật hoàn hảo. Đây là mã:

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

Và khi dữ liệu thay đổi:

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

Chỉ trong trường hợp bất cứ ai đang sử dụng FragmentStatePagerAd CHƯƠNG bộ điều hợp dựa trên (sẽ cho phép ViewPager tạo các trang tối thiểu cần thiết cho mục đích hiển thị, nhiều nhất là 2 cho trường hợp của tôi), câu trả lời của @ rui.araujo về ghi đè getItemPocation trong bộ điều hợp của bạn sẽ không gây lãng phí đáng kể, nhưng nó vẫn không gây lãng phí có thể được cải thiện.

Trong mã giả:

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

Trong ViewPager, khá dễ dàng để biết vị trí quá khứ của mục, cách triển khai hoàn hảo nhất chỉ là trả về vị trí mới getItemPosition()khi dữ liệu thay đổi và ViewPager sẽ biết chúng có bị thay đổi hay không. thật đáng buồn, ViewPager đã không làm điều đó.
VinceStyling

3

Tôi đã có một vấn đề tương tự trong đó tôi có bốn trang và một trong những trang được cập nhật lượt xem trên ba trang còn lại. Tôi đã có thể cập nhật các widget (SeekBars, TextViews, v.v.) trên trang liền kề với trang hiện tại. Hai trang cuối sẽ có các widget chưa được khởi tạo khi gọi mTabsAdapter.getItem(position).

Để giải quyết vấn đề của mình, tôi đã sử dụng setSelectedPage(index)trước khi gọigetItem(position) . Điều này sẽ khởi tạo trang, cho phép tôi có thể thay đổi giá trị và widget trên mỗi trang.

Sau khi tất cả các cập nhật tôi sẽ sử dụng setSelectedPage(position)theo sau notifyDataSetChanged().

Bạn có thể thấy một chút nhấp nháy trong ListView trên trang cập nhật chính, nhưng không có gì đáng chú ý. Tôi đã không kiểm tra nó một cách xuyên suốt, nhưng nó giải quyết được vấn đề trước mắt của tôi.


Xin chào, tôi quan tâm đến mã của bạn, tôi đang đối mặt với vấn đề tương tự, tôi có thể cập nhật các đoạn liền kề nhưng đoạn hiện tại có thể nhìn thấy không được cập nhật. Tôi rất bối rối với tất cả các câu trả lời ở đây. Làm cách nào tôi có thể cập nhật lượt xem trong đoạn hiện tại được hiển thị bởi bộ điều hợp VIewPager
Pankaj Nimgade

3

Tôi chỉ đăng câu trả lời này trong trường hợp bất cứ ai khác thấy nó hữu ích. Để thực hiện chính xác điều tương tự, tôi chỉ cần lấy mã nguồn của ViewPager và PagerAd CHƯƠNG từ thư viện tương thích và biên dịch nó trong mã của tôi (Bạn cần tự sắp xếp tất cả các lỗi và tự nhập, nhưng chắc chắn có thể thực hiện được).

Sau đó, trong CustomViewPager, tạo một phương thức gọi là updateViewAt (vị trí int). Bản thân khung nhìn có thể được lấy từ ArrayList mItems được định nghĩa trong lớp ViewPager (bạn cần đặt Id cho các khung nhìn tại mục khởi tạo và so sánh id này với vị trí trong phương thức updateViewAt ()). Sau đó, bạn có thể cập nhật xem khi cần thiết.


2

Tôi đoán, tôi đã có logic của ViewPager.

Nếu tôi cần làm mới một tập hợp các trang và hiển thị chúng dựa trên tập dữ liệu mới, tôi gọi notifyDataSetChanged () . Sau đó, ViewPager thực hiện một số cuộc gọi tới getItemP vị trí () , chuyển qua đó Fragment dưới dạng Object. Đoạn này có thể từ một tập dữ liệu cũ (mà tôi muốn loại bỏ) hoặc từ một tập dữ liệu mới (mà tôi muốn hiển thị). Vì vậy, tôi ghi đè getItemP vị trí () và ở đó tôi phải xác định bằng cách nào đó nếu Fragment của tôi là từ tập dữ liệu cũ hoặc từ tập dữ liệu mới.

Trong trường hợp của tôi, tôi có bố cục 2 ngăn với danh sách các mục trên cùng ở ngăn bên trái và chế độ xem vuốt (ViewPager) ở bên phải. Vì vậy, tôi lưu trữ một liên kết đến mục hàng đầu hiện tại của tôi bên trong PagerAd CHƯƠNG của tôi và cả bên trong mỗi trang được khởi tạo. Khi mục hàng đầu được chọn trong danh sách thay đổi, tôi lưu trữ mục hàng đầu mới trong PagerAd CHƯƠNG và gọi notifyDataSetChanged () . Và trong phần ghi đè getItemP vị trí () tôi đã so sánh mục trên cùng từ bộ điều hợp của tôi với mục trên cùng từ đoạn của tôi. Và chỉ khi chúng không bằng nhau, tôi mới trả về POSITION_NONE. Sau đó, PagerAd CHƯƠNG khôi phục lại tất cả các mảnh đã trả về POSITION_NONE.

GHI CHÚ. Lưu trữ id mục hàng đầu thay vì tham chiếu có thể là một ý tưởng tốt hơn.

Đoạn mã dưới đây là một chút học thuật nhưng tôi đã điều chỉnh nó từ mã thực sự hoạt động.

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

Cảm ơn tất cả các nhà nghiên cứu trước đây!


2

Mã dưới đây làm việc cho tôi.

Tạo một lớp mở rộng lớp FragmentPagerAd CHƯƠNG như bên dưới.

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

Sau đó, bên trong mỗi Fragment bạn đã tạo, hãy tạo một phương thức updateFragment. Trong phương pháp này, bạn thay đổi những thứ bạn cần thay đổi trong đoạn. Ví dụ, trong trường hợp của tôi, Fragment0 chứa GLSurfaceView hiển thị một đối tượng 3d dựa trên đường dẫn đến tệp .ply, vì vậy bên trong phương thức updateFragment của tôi, tôi thay đổi đường dẫn đến tệp ply này.

sau đó tạo một cá thể ViewPager,

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

và một ví dụ Adpater,

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

sau đó làm điều này

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

Sau đó, bên trong lớp bạn đã khởi tạo lớp Adaptor ở trên và tạo viewPager, mỗi khi bạn muốn cập nhật một trong các đoạn của mình (trong trường hợp của chúng tôi là Fragment0), hãy sử dụng như sau:

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.

Giải pháp này dựa trên kỹ thuật được đề xuất bởi Alvaro Luis Bustamante.


1

1.Đầu tiên bạn phải đặt phương thức getItemposeition trong lớp Pagerad CHƯƠNG 2. Bạn phải đọc vị trí Chính xác của View Pager 3. sau đó gửi vị trí đó làm vị trí dữ liệu của nút cập nhật mới 4.Write onclick bên trong setonPageChange thính giả

mã chương trình đó là một chút tôi đã sửa đổi để chỉ đặt thành phần vị trí cụ thể

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

những gì làm việc cho tôi đã đi viewPager.getAdapter().notifyDataSetChanged();

và trong bộ điều hợp đặt mã của bạn để cập nhật chế độ xem bên trong getItemPositionnhư vậy

@Override
public int getItemPosition(Object object) {

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

    return super.getItemPosition(object);
}

có thể không phải là cách chính xác nhất để thực hiện nhưng nó đã hoạt động ( return POSITION_NONEthủ thuật gây ra sự cố cho tôi vì vậy không phải là một lựa chọn)


1

Bạn có thể cập nhật động tất cả các đoạn, bạn có thể thấy trong ba bước.

Trong bộ chuyển đổi của bạn:

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

Bây giờ trong hoạt động của bạn:

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) {

}}

Cuối cùng trong đoạn của bạn, một cái gì đó như thế:

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

}}

Bạn có thể xem mã hoàn chỉnh ở đây .

Cảm ơn Alvaro Luis Bustamante.


1

Luôn luôn quay trở lại POSITION_NONElà cách đơn giản nhưng hơi kém hiệu quả bởi vì điều đó gợi lên sự khởi tạo của tất cả các trang đã được khởi tạo.

Tôi đã tạo một thư viện ArrayPagerAd CHƯƠNG để thay đổi các mục trong PagerAd chương một cách linh hoạt.

Bên trong, adapter của thư viện này trở POSITION_NONEvề getItemPosiition()chỉ khi cần thiết.

Bạn có thể thay đổi các mục động như sau bằng cách sử dụng thư viện này.

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

Thư viện Thils cũng hỗ trợ các trang được tạo bởi Fragment.


1

Điều này dành cho tất cả những người như tôi, những người cần cập nhật Viewpager từ một dịch vụ (hoặc luồng nền khác) và không có đề xuất nào hoạt động: Sau một chút kiểm tra log, tôi nhận ra rằng phương thức notifyDataSetChanged () không bao giờ trả về. getItemP vị trí (đối tượng đối tượng) được gọi là tất cả kết thúc ở đó mà không cần xử lý thêm. Sau đó, tôi tìm thấy trong các tài liệu của lớp PagerAd CHƯƠNG cha (không có trong tài liệu của các lớp con), "Thay đổi tập dữ liệu phải xảy ra trên luồng chính và phải kết thúc bằng một cuộc gọi để thông báoDataSetChanged ()". Vì vậy, giải pháp làm việc trong trường hợp này là (sử dụng FragmentStatePagerAdOG và getItemP vị trí (đối tượng đối tượng) được đặt để trả về POSITION_NONE):

và sau đó gọi để thông báoDataSetChanged ():

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

1

Bạn có thể thêm chuyển đổi máy nhắn tin trên Viewpager như thế này

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

Trong đoạn mã dưới đây, tôi đã thay đổi màu xem của mình khi chạy khi cuộn pager

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

Tôi biết tôi đập muộn nhưng vẫn có thể giúp được ai đó. Tôi chỉ mở rộng câu trả lời và tôi cũng đã thêm nhận xét về nó.

tốt,

câu trả lời tự nó nói là không hiệu quả

Vì vậy, để làm cho nó được làm mới một cách bất thường khi cần bạn có thể làm điều này

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 không được thiết kế để hỗ trợ thay đổi chế độ xem động.

Tôi đã xác nhận điều này trong khi tìm kiếm một lỗi khác liên quan đến lỗi này https://issuetracker.google.com/issues/36956111 và đặc biệt là https://issuetracker.google.com/issues/36956111#comment56

Câu hỏi này hơi cũ, nhưng Google gần đây đã giải quyết vấn đề này với ViewPager2 . Nó sẽ cho phép thay thế các giải pháp thủ công (không rõ ràng và có khả năng lỗi) bằng một tiêu chuẩn. Nó cũng ngăn chặn việc tạo lại các khung nhìn không cần thiết như một số câu trả lời.

Đối với các ví dụ về ViewPager2, bạn có thể kiểm tra https://github.com/googlesamples/android-viewpager2

Nếu bạn muốn sử dụng ViewPager2, bạn sẽ cần thêm phụ thuộc sau vào tệp build.gradle của mình:

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

Sau đó, bạn có thể thay thế ViewPager trong tệp xml của mình bằng:

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

Sau đó, bạn sẽ cần thay thế ViewPager bằng ViewPager2 trong hoạt động của mình

ViewPager2 cần RecyclerView.Ad CHƯƠNG hoặc FragmentStateAd CHƯƠNG, trong trường hợp của bạn, nó có thể là RecyclerView.Ad CHƯƠNG

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

Trong trường hợp bạn đang sử dụng TabLayout, bạn có thể sử dụng TabLayoutMedoder:

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

Sau đó, bạn sẽ có thể làm mới các chế độ xem của mình bằng cách sửa đổi dữ liệu của bộ điều hợp và gọi phương thức notifyDataSetChanged



0

Tôi nghĩ rằng tôi đã thực hiện một cách đơn giản để thông báo về các thay đổi của tập dữ liệu:

Đầu tiên, thay đổi một chút cách thức hoạt động của hàm 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;
    }

đối với "updateView", hãy điền vào chế độ xem với tất cả dữ liệu bạn muốn điền (setText, setBitmapImage, ...).

xác minh rằng killView hoạt động như thế này:

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

Bây giờ, giả sử bạn cần thay đổi dữ liệu, thực hiện và sau đó gọi hàm tiếp theo trên PagerAd CHƯƠNG:

    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
}

Ví dụ: nếu bạn muốn thông báo cho tất cả các chế độ xem đang được viewPager hiển thị rằng có gì đó đã thay đổi, bạn có thể gọi:

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

Đó là nó.


0

Đối với những gì nó có giá trị, trên KitKat + dường như adapter.notifyDataSetChanged()đủ để khiến các chế độ xem mới hiển thị, miễn là bạn setOffscreenPageLimitđủ cao. Tôi có thể có được hành vi mong muốn bằng cách làm viewPager.setOffscreenPageLimit(2).


0

Tôi thực sự sử dụng notifyDataSetChanged()trên ViewPagerCirclePageIndicatorvà sau đó tôi gọi destroyDrawingCache()vào ViewPagervà nó hoạt động .. Không ai trong số các giải pháp khác làm việc cho tôi.


Câu hỏi ban đầu đã gần 2 năm tuổi, tôi chắc chắn có nhiều điểm khác biệt trong API Android bởi vì bây giờ câu trả lời ở đây có thể không phù hợp với tất cả các phiên bản API Android.
C0deAttack
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.