অ্যান্ড্রয়েডের ভিউপ্যাজার থেকে টুকরা পাতা সরান


138

আমি ভিউপ্যাজারের থেকে টুকরোগুলিকে গতিশীলভাবে যুক্ত এবং মুছে ফেলার চেষ্টা করছি, কোনও সমস্যা ছাড়াই কাজ যুক্ত করছি, তবে অপসারণ প্রত্যাশার মতো কাজ করে না।

আমি যখনই বর্তমান আইটেমটি সরাতে চাইছি, সর্বশেষটি মুছে ফেলা হবে।

আমি অ্যাডাপ্টারের getItemPosition পদ্ধতিতে একটি ফ্রেগমেন্টস্টেটপেজারএডাপ্টার ব্যবহার করার বা POSITION_NONE ফেরত দেওয়ার চেষ্টাও করেছি।

আমি কি ভুল করছি?

এখানে একটি প্রাথমিক উদাহরণ:

MainActivity.java

public class MainActivity extends FragmentActivity implements TextProvider {

    private Button mAdd;
    private Button mRemove;
    private ViewPager mPager;

    private MyPagerAdapter mAdapter;

    private ArrayList<String> mEntries = new ArrayList<String>();

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

        mEntries.add("pos 1");
        mEntries.add("pos 2");
        mEntries.add("pos 3");
        mEntries.add("pos 4");
        mEntries.add("pos 5");

        mAdd = (Button) findViewById(R.id.add);
        mRemove = (Button) findViewById(R.id.remove);
        mPager = (ViewPager) findViewById(R.id.pager);

        mAdd.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view) {
                addNewItem();
            }
        });

        mRemove.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view) {
                removeCurrentItem();
            }
        });

        mAdapter = new MyPagerAdapter(this.getSupportFragmentManager(), this);

        mPager.setAdapter(mAdapter);

    }

    private void addNewItem() {
        mEntries.add("new item");
        mAdapter.notifyDataSetChanged();
    }

    private void removeCurrentItem() {
        int position = mPager.getCurrentItem();
        mEntries.remove(position);
        mAdapter.notifyDataSetChanged();
    }

    @Override
    public String getTextForPosition(int position) {
        return mEntries.get(position);
    }
    @Override
    public int getCount() {
        return mEntries.size();
    }


    private class MyPagerAdapter extends FragmentPagerAdapter {

        private TextProvider mProvider;

        public MyPagerAdapter(FragmentManager fm, TextProvider provider) {
            super(fm);
            this.mProvider = provider;
        }

        @Override
        public Fragment getItem(int position) {
            return MyFragment.newInstance(mProvider.getTextForPosition(position));
        }

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

    }

}

TextProvider.java

public interface TextProvider {
    public String getTextForPosition(int position);
    public int getCount();
}

MyFragment.java

public class MyFragment extends Fragment {

    private String mText;

    public static MyFragment newInstance(String text) {
        MyFragment f = new MyFragment(text);
        return f;
    }

    public MyFragment() {
    }

    public MyFragment(String text) {
        this.mText = text;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {

        View root = inflater.inflate(R.layout.fragment, container, false);

        ((TextView) root.findViewById(R.id.position)).setText(mText);

        return root;
    }

}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <Button
        android:id="@+id/add"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="add new item" />

    <Button
        android:id="@+id/remove"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="remove current item" />

    <android.support.v4.view.ViewPager
        android:id="@+id/pager"
        android:layout_width="match_parent"
        android:layout_height="0dip"
        android:layout_weight="1" />

</LinearLayout>

fragment.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/position"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:textSize="35sp" />

</LinearLayout>

2
উত্স কোডের জন্য +1
উইজেড

এটিতে কি ডিফল্ট কনস্ট্রাক্টর ব্যবহার করা সঠিক MyFragment.java?
কোডকিলার

উত্তর:


95

লুথের সমাধানগুলি আমার পক্ষে কাজ করার জন্য যথেষ্ট ছিল না, কারণ বিদ্যমান খণ্ডগুলি ধ্বংস হচ্ছে না। এই উত্তরটি দ্বারা অনুপ্রাণিত হয়ে , আমি দেখতে পেয়েছি যে সমাধান যখনই কোনও খণ্ডের প্রত্যাশিত অবস্থানে পরিবর্তন এসেছে তখনই একটি নতুন অনন্য আইডি দেওয়ার getItemId(int position)পদ্ধতিটি ওভাররাইড করা FragmentPagerAdapter

সোর্স কোড:

private class MyPagerAdapter extends FragmentPagerAdapter {

    private TextProvider mProvider;
    private long baseId = 0;

    public MyPagerAdapter(FragmentManager fm, TextProvider provider) {
        super(fm);
        this.mProvider = provider;
    }

    @Override
    public Fragment getItem(int position) {
        return MyFragment.newInstance(mProvider.getTextForPosition(position));
    }

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


    //this is called when notifyDataSetChanged() is called
    @Override
    public int getItemPosition(Object object) {
        // refresh all fragments when data set changed
        return PagerAdapter.POSITION_NONE;
    }


    @Override
    public long getItemId(int position) {
        // give an ID different from position when position has been changed
        return baseId + position;
    }

    /**
     * Notify that the position of a fragment has been changed.
     * Create a new ID for each position to force recreation of the fragment
     * @param n number of items which have been changed
     */
    public void notifyChangeInPosition(int n) {
        // shift the ID returned by getItemId outside the range of all previous fragments
        baseId += getCount() + n;
    }
}

এখন, উদাহরণস্বরূপ, যদি আপনি একটি একক ট্যাব মুছে notifyChangeInPosition(1)ফেলেন বা অর্ডারে কিছু পরিবর্তন করেন, কল করার আগে আপনার কল করা উচিত notifyDataSetChanged(), যা নিশ্চিত করবে যে সমস্ত খণ্ড পুনরায় তৈরি হবে।

কেন এই সমাধান কাজ করে

ওভাররাইডিং আইটেম পজিশন ():

যখন notifyDataSetChanged()ডাকা হয়, অ্যাডাপ্টারের সাথে এটি সংযুক্ত notifyChanged()পদ্ধতিটির কল করে ViewPagerViewPagerতারপর চেক মান অ্যাডাপ্টারের এর দ্বারা ফিরে getItemPosition()প্রতিটি আইটেমের জন্য, সেগুলি যা রিটার্ন সরানোর POSITION_NONE(দেখুন সোর্স কোড ) এবং তারপর repopulating।

GetItemId () ওভাররাইডিং:

অ্যাডাপ্টারটি পুরানো টুকরোটি পুনরায় লোপ করা থেকে পুনরায় লোড করা থেকে রোধ করা প্রয়োজন ViewPager। আপনি ইনস্ট্যান্টিয়েট আইটেম () এর উত্স কোডটি দেখে এটি কেন সহজে কাজ করে তা বুঝতে পারবেন FragmentPagerAdapter

    final long itemId = getItemId(position);

    // Do we already have this fragment?
    String name = makeFragmentName(container.getId(), itemId);
    Fragment fragment = mFragmentManager.findFragmentByTag(name);
    if (fragment != null) {
        if (DEBUG) Log.v(TAG, "Attaching item #" + itemId + ": f=" + fragment);
        mCurTransaction.attach(fragment);
    } else {
        fragment = getItem(position);
        if (DEBUG) Log.v(TAG, "Adding item #" + itemId + ": f=" + fragment);
        mCurTransaction.add(container.getId(), fragment,
                makeFragmentName(container.getId(), itemId));
    }

যেমন আপনি দেখতে পাচ্ছেন, কেবল তখনই getItem()পদ্ধতিটি কল করা হয় যদি খণ্ড ব্যবস্থাপক একই আইডির সাথে কোনও বিদ্যমান টুকরা খুঁজে না পান। আমার কাছে এটি একটি বাগের মতো মনে হয়েছে যে পুরানো টুকরোটি notifyDataSetChanged()ডাকা হওয়ার পরেও সংযুক্ত রয়েছে , তবে এর জন্য ডকুমেন্টেশনে ViewPagerস্পষ্টভাবে বলা আছে:

নোট করুন এই শ্রেণিটি বর্তমানে প্রাথমিক নকশা এবং বিকাশের অধীনে রয়েছে। এপিআই সম্ভবত সামঞ্জস্য লাইব্রেরির পরবর্তী আপডেটগুলিতে পরিবর্তিত হবে, যখন অ্যাপ্লিকেশনগুলির উত্স কোডে নতুন সংস্করণের বিপরীতে সংকলন করা হবে তার পরিবর্তনের প্রয়োজন।

সুতরাং আশা করা যায় যে এখানে প্রদত্ত কাজটি সমর্থন লাইব্রেরির ভবিষ্যতের সংস্করণে প্রয়োজনীয় হবে না।


1
এই উত্তরের জন্য অনেক ধন্যবাদ! এটি ফ্র্যাগমেন্টস্টেটপেজারএডাপ্টার ব্যবহার না করেই এই সমস্যাটি সমাধান করার চেষ্টা করছে। দুর্দান্ত ব্যাখ্যাও। আপনি খণ্ডে ফিরে এসে ট্রিগার করার জন্য getItem পাওয়ার কোনও উপায় খুঁজে পেয়েছেন? সাফল্য ছাড়াই আমি আপনার চতুর নোটিফাইটি ডেটাসেট চেঞ্জড () বিভিন্ন স্থানে (অর্থাত্ স্টপ) ব্যবহার করার চেষ্টা করেছি
u2tall

আমি আপনার প্রশ্নটি সত্যই বুঝতে পারি না ... দয়া করে এটি বের করতে না পারলে সোর্স কোড সহ একটি নতুন প্রশ্ন পোস্ট করুন।
টিম

1
২০১ 2016, এই কাজটি এখনও করা দরকার notifyDataSetChanged()
সাবিন সেবাস্তিয়ান

কি দারুন! আশ্চর্যজনক ব্যাখ্যা। আমার একটি বেশ জটিল ভিউপেজার ছিল যেখানে আমি আইটেমগুলি সক্রিয়ভাবে সরাতে এবং সন্নিবেশ করিয়েছিলাম এবং এই সমস্ত কিছু না বুঝে এটি কাজ করতে পেতাম না।
রুপস

পুরাতন খণ্ডটি প্রতিস্থাপনের জন্য এখনও এই কাজের প্রয়োজন need ধূর.
কোপিকাওকাও

291

ভিউপ্যাজার উপরের কোডটি সহ আপনার টুকরোগুলি সরিয়ে ফেলবে না কারণ এটি মেমরিতে বেশ কয়েকটি ভিউ (বা আপনার ক্ষেত্রে খণ্ডগুলি) লোড করে। দৃশ্যমান দৃশ্যের পাশাপাশি এটি দৃশ্যমানের উভয় দিকের ভিউ লোড করে। এটি ভিউ থেকে দেখার জন্য মসৃণ স্ক্রোলিং সরবরাহ করে যা ভিউপ্যাজারকে এত দুর্দান্ত করে তোলে।

আপনি যে প্রভাবটি চান তা অর্জন করতে আপনার কয়েকটি জিনিস করা দরকার।

  1. ফ্র্যাগমেন্টপেজারএডাপ্টারকে একটি ফ্র্যাগমেন্টস্টেটপেজারএডাপ্টারে পরিবর্তন করুন। এর কারণ হ'ল ফ্রেগমেন্টপেজারএডাপ্টার মেমরিতে লোড করে এমন সমস্ত দর্শন চিরতরে রাখবে। যেখানে ফ্রেগমেন্টস্টেটপেজার অ্যাডাপ্টার বর্তমান এবং অনুসরণযোগ্য দৃষ্টিভঙ্গির বাইরে চলে এমন মতামতকে নিষ্পত্তি করে।

  2. অ্যাডাপ্টার পদ্ধতি getItemPosition ওভাররাইড করুন (নীচে দেখানো হয়েছে)। আমরা যখন mAdapter.notifyDataSetChanged();ভিউপগার কল করি তখন অবস্থানের ক্ষেত্রে কী পরিবর্তন হয়েছে তা নির্ধারণ করতে অ্যাডাপ্টারের জিজ্ঞাসাবাদ করে। আমরা এই পদ্ধতিটি ব্যবহার করে বলি যে সমস্ত কিছু পরিবর্তিত হয়েছে তাই আপনার সমস্ত দৃশ্যের অবস্থান পুনরায় প্রসেস করুন।

এবং এখানে কোড ...

private class MyPagerAdapter extends FragmentStatePagerAdapter {

    //... your existing code

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

}

1
ঠিক আছে, এটি এই সমস্যাটির পক্ষে সবচেয়ে সহজ কাজ বলে মনে হচ্ছে। যদিও বাগের প্রতিবেদনগুলি সম্পর্কে এখানে বেশ কয়েকটি অন্যান্য আলোচনা করা হয়েছে: কোড. google.com/p/android/issues/detail?id=19110 এবং এখানে: code.google.com/p/android/issues/detail?id= 19001
সাবিন সেবাস্তিয়ান

@ লাউথ: আমি ফ্রেগমেন্টস্টেটপেজার অ্যাডাপ্টার (যেমন গুগল রেফ পৃষ্ঠায় উদাহরণস্বরূপ: ডেভেলপার.অ্যান্ড্রয়েড / রেফারেন্স / অ্যান্ড্রয়েড / সাউপপোর্ট / ভি 4/ ভিউ / ভি) থেকে বর্ধিত হিসাবে ট্যাবসএডাপ্টারের সাথে ভিউপ্যাজারটি ব্যবহার করছি । আমার ফলোআপ প্রশ্নটি: আপনি প্রথম স্থানে একটি ট্যাবটি কীভাবে মুছবেন? ধন্যবাদ।
gcl1

4
@ লাউল যখন আমরা বিজ্ঞপ্তি ডেটাসেট চেঞ্জড () কে ডাকি তখন ভিউজারটি নতুন টুকরো তৈরি করে, তবে পুরানোগুলি এখনও স্মৃতিতে রয়েছে। আর আমার সমস্যা হ'ল; তারা তাদের onditions আইটেমসিলিটেড ইভেন্টের জন্য একটি কল পায়। কীভাবে আমি পুরানো টুকরোগুলি থেকে মুক্তি পেতে পারি?
syloc

1
আপনাকে ধন্যবাদ, কেবলমাত্র ফ্র্যাগমেন্ট পেজারএডাপ্টারকে একটি ফ্র্যাগমেন্টস্টেটপেজার অ্যাডাপ্টারের পরিবর্তে আমার সমস্যার সমাধান করেছে। এর পরে আমি কেবল ভিউপ্যাজারের সমস্ত ভিউগুলি () সরিয়ে ফেলা করেছি এবং টুকরোগুলি আবার গতিশীলভাবে পুনরায় লোড করব।
মিশাল

17
প্রদত্ত দর্শন / টুকরা / অবজেক্টটি এখনও বিদ্যমান এবং বৈধ কিনা সত্যই দেখার পরিবর্তে আপনি কেন সর্বদা POSITION_NONE ফিরিয়ে দিচ্ছেন? এই পদ্ধতিটির প্রশ্নের উত্তর দেওয়ার কথা "হেই, আমি কি এটি আবার ব্যবহার করতে পারি?" - এবং সর্বদা "না!" শুধু মানে সব কিছুর বিনোদন! এটি অনেক ক্ষেত্রে অপ্রয়োজনীয়।
জোর্ডিড

14

পেজার থেকে খণ্ড পৃষ্ঠা সরাতে আমার কার্যকরী সমাধান

public class MyFragmentAdapter extends FragmentStatePagerAdapter {

    private ArrayList<ItemFragment> pages;

    public MyFragmentAdapter(FragmentManager fragmentManager, ArrayList<ItemFragment> pages) {
        super(fragmentManager);
        this.pages = pages;
    }

    @Override
    public Fragment getItem(int index) {
        return pages.get(index);
    }

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

    @Override
    public int getItemPosition(Object object) {
        int index = pages.indexOf (object);

        if (index == -1)
            return POSITION_NONE;
        else
            return index;
    }
}

এবং যখন আমাকে সূচী অনুসারে কিছু পৃষ্ঠা সরিয়ে ফেলতে হবে তখন আমি এটি করি

pages.remove(position); // ArrayList<ItemFragment>
adapter.notifyDataSetChanged(); // MyFragmentAdapter

এখানে এটি আমার অ্যাডাপ্টার সূচনা

MyFragmentAdapter adapter = new MyFragmentAdapter(getSupportFragmentManager(), pages);
viewPager.setAdapter(adapter);

আপনি কি টুকরা যোগ করার জন্য কোড শেয়ার করবেন?
ভিভিবি

তবে যুক্ত করার সময় দু'বার / তিনবার সোয়াইপ করার পরে ধীর প্রতিফলিত হয়
ভিভিবি

আপনি যদি আইটেমগুলি অপসারণ না করে থাকেন তবে এটি কেবল আইটেমটি ফিরিয়ে দেয়, আরও কিছুই নয় ... আপনি ভিএম বা বাস্তব ডিভাইসে পরীক্ষা করছেন?
ভাসিল ভালচেভ

অন্যান্য সমাধানের চেষ্টা করুন, উত্তরগুলি আরও বেশি ভোট দেয়। সোয়েপগুলিতে আরও ভাল পারফরম্যান্সের জন্য দেখুন পেজারের খুব নগদ অর্থ ব্যবস্থা রয়েছে, সুতরাং এই হ্যাকগুলি মূল ভিউ পেজারের দ্বারা পরিচালনা করা হয় না ...
ভাসিল ভালচেভ

11

খণ্ডটি ইতিমধ্যে মুছে ফেলা উচিত তবে বিষয়টি ভিউপেজার সেভ স্টেট

চেষ্টা

myViewPager.setSaveFromParentEnabled(false);

কিছুই কাজ না করেই এই সমস্যার সমাধান!

চিয়ার্স!


2

আমি android.support.v4.app.FragmentPagerAdpaterনামকৃত একটি কাস্টম শ্রেণিতে সোর্স কোডটি অনুলিপি করার ধারণা পেয়েছিলাম CustumFragmentPagerAdapter। এটি আমাকে পরিবর্তিত করার সুযোগ দিয়েছে instantiateItem(...)যাতে প্রতিবার যখন এটি বলা হয়, এটি getItem()পদ্ধতিতে প্রাপ্ত নতুন খণ্ড যুক্ত করার আগে এটি বর্তমানে সংযুক্ত খণ্ডটিকে সরিয়ে / নষ্ট করে দেয় ।

কেবল instantiateItem(...)নিম্নলিখিত পদ্ধতিতে কেবল পরিবর্তন করুন :

@Override
public Object instantiateItem(ViewGroup container, int position) {
    if (mCurTransaction == null) {
        mCurTransaction = mFragmentManager.beginTransaction();
    }
    final long itemId = getItemId(position);

    // Do we already have this fragment?
    String name = makeFragmentName(container.getId(), itemId);
    Fragment fragment = mFragmentManager.findFragmentByTag(name);

    // remove / destroy current fragment
    if (fragment != null) {
        mCurTransaction.remove(fragment);
    }

    // get new fragment and add it
    fragment = getItem(position);
    mCurTransaction.add(container.getId(), fragment,    makeFragmentName(container.getId(), itemId));

    if (fragment != mCurrentPrimaryItem) {
        fragment.setMenuVisibility(false);
        fragment.setUserVisibleHint(false);
    }

    return fragment;
}

1

আপনি উভয়ের জন্য আরও ভাল একত্রিত করতে পারেন:

private class MyPagerAdapter extends FragmentStatePagerAdapter {

    //... your existing code

    @Override
    public int getItemPosition(Object object){

      if(Any_Reason_You_WantTo_Update_Positions) //this includes deleting or adding pages
 return PagerAdapter.POSITION_NONE;
    }
else
return PagerAdapter.POSITION_UNCHANGED; //this ensures high performance in other operations such as editing list items.

}

এটি কেবলমাত্র তখনই কাজ করে যদি আপনি কোনও ডান ট্যাব মুছে ফেলছেন, কোনও অভ্যন্তরীণ ট্যাব বা বাম ট্যাব মুছতে, আপনাকে অবশ্যই ট্যাবগুলি পুনরায় অর্ডার করতে হবে এবং ডকুমেন্টেশন বিকাশকারী
বিটবাইটডগ

1

ভবিষ্যতের পাঠকদের জন্য!

এখন আপনি ব্যবহার করতে পারেন ViewPager2 পরিবর্তনশীল যোগ viewpager থেকে টুকরা সরানোর জন্য।

ফর্ম এপিআই রেফারেন্স উদ্ধৃত

ডান থেকে বাম লেআউট সমর্থন, উল্লম্ব অভিযোজন, সংশোধনযোগ্য ফ্রেগমেন্ট সংগ্রহ ইত্যাদিসহ তার পূর্বসূরীর বেশিরভাগ ব্যথা-পয়েন্টকে সম্বোধন করে ভিউপ্যাজার 2 ভিউপ্যাজারকে প্রতিস্থাপন করে View

এ দেখে নিন MutableCollectionFragmentActivity.ktমধ্যে googlesample / Android-viewpager2 যোগ viewpager থেকে পরিবর্তনশীল টুকরা সরানোর উদাহরণের জন্য।


আপনার জ্ঞাতার্থে:

প্রবন্ধ:

এপিআই রেফারেন্স

অব্যাহতি পত্র

নমুনাগুলি রেপো: https://github.com/googlesferences/android-viewpager2


আমার কাছে টুকরো টুকরো মেইনফ্রেগমেন্ট এবং অন্যান্য অংশ রয়েছে। আমি প্রতি 5 তম পজিশনের পরে অন্য ফ্র্যাগমেন্ট যুক্ত করছি এবং এটি অ্যারেলিস্টে নেই তাই সেই অন্য তালিকাটি তালিকায় না থাকলে কীভাবে সরিয়ে ফেলা যায়? আমি ভিউপ্যাজার 2
বি

0

মুখের উত্তরটি ঠিক কাজ করে। তবে আমি মনে করি না সবসময় POSITION_NONE ফিরিয়ে দেওয়া ভাল ধারণা। কারণ POSITION_NONE এর অর্থ হ'ল খণ্ডটি ধ্বংস করা উচিত এবং একটি নতুন খণ্ড তৈরি করা হবে। আপনি ভিউপিজারের উত্স কোডে ডেটাসেট চেঞ্জড ফাংশনে এটি পরীক্ষা করতে পারেন।

        if (newPos == PagerAdapter.POSITION_NONE) {
            mItems.remove(i);
            i--;
            ... not related code
            mAdapter.destroyItem(this, ii.position, ii.object);

সুতরাং আমি মনে করি আপনি তৈরি করেছেন এমন সমস্ত টুকরোগুলি সংরক্ষণ করতে আপনি দুর্বল রেফারেন্সের অ্যারেলিস্টটি আরও ভালভাবে ব্যবহার করতে চাই। এবং আপনি যখন কোনও পৃষ্ঠা যুক্ত বা সরিয়ে ফেলেন, আপনি নিজের অ্যারেলিস্ট থেকে সঠিক অবস্থানটি পেতে পারেন।

 public int getItemPosition(Object object) {
    for (int i = 0; i < mFragmentsReferences.size(); i ++) {
        WeakReference<Fragment> reference = mFragmentsReferences.get(i);
        if (reference != null && reference.get() != null) {
            Fragment fragment = reference.get();
            if (fragment == object) {
                return i;
            }
        }
    }
    return POSITION_NONE;
}

মন্তব্য অনুসারে, হোস্ট আইটেমটি কল করা হয় যখন হোস্ট ভিউ কোনও আইটেমের অবস্থান পরিবর্তন করে কিনা তা নির্ধারণের চেষ্টা করা হয়। এবং রিটার্ন মান এর নতুন অবস্থান মানে।

তবে এই কল্পনা করা হয় না। আমাদের এখনও একটি গুরুত্বপূর্ণ পদক্ষেপ নিতে হবে। ফ্রেগমেন্টস্টেটপেজারএডাপ্টারের উত্স কোডে, "এমফ্রেগমেন্টস" নামের একটি অ্যারে রয়েছে সেই টুকরোগুলি ক্যাশে করে যা ধ্বংস হয় না। এবং ইনস্ট্যান্ট আইটেম ফাংশনে।

if (mFragments.size() > position) {
        Fragment f = mFragments.get(position);
        if (f != null) {
            return f;
        }
    }

এটি ক্যাশেড টুকরোটি প্রত্যক্ষভাবে ফিরিয়ে দেয় যখন দেখা যায় যে ক্যাশেড খণ্ডটি শূন্য নয়। সুতরাং একটি সমস্যা আছে। উদাহরণস্বরূপ, আসুন একটি পৃষ্ঠা মুছে দিন 2 পজিশনে, প্রথমত, আমরা সেই অংশটি আমাদের নিজস্ব রেফারেন্স অ্যারেলিস্ট থেকে সরিয়ে ফেলি। সুতরাং getI আইটেম পজিশনে এটি fra খণ্ডের জন্য POSITION_NONE ফিরিয়ে দেবে এবং তারপরে সেই খণ্ডটি ধ্বংস হয়ে "এমফ্রেগমেন্টস" থেকে সরানো হবে।

 mFragments.set(position, null);

এখন 3 পজিশনে খণ্ডটি 2 পজিশনে থাকবে এবং প্যারাম পজিশন 3 সহ ইনস্ট্যান্টেড আইটেম কল করা হবে। এই মুহুর্তে, "এমফ্রেজেন্টস" এর তৃতীয় আইটেমটি নাল নয়, সুতরাং এটি সরাসরি ফিরে আসবে। তবে বাস্তবে এটি কী ফিরে এসেছিল তা ২ পজিশনের খণ্ড is সুতরাং যখন আমরা পৃষ্ঠা 3 এ পরিণত হব, আমরা সেখানে একটি খালি পৃষ্ঠা খুঁজে পাব।

এই সমস্যাটি নিয়ে কাজ করার জন্য। আমার পরামর্শ হ'ল আপনি ফ্রেগমেন্টস্টেটপেজারএডাপ্টারের উত্স কোডটি আপনার নিজের প্রকল্পে অনুলিপি করতে পারেন এবং আপনি যখন অপারেশনগুলি যোগ বা সরিয়ে ফেলেন তখন আপনাকে "এমফ্রেগমেন্টস" অ্যারেলিস্টে উপাদান যুক্ত এবং অপসারণ করা উচিত।

আপনি যদি ফ্র্যাগমেন্টস্টেটপেজারএডাপ্টারের পরিবর্তে পেজআরডাপ্টার ব্যবহার করেন তবে জিনিসগুলি আরও সহজ হবে। শুভকামনা


0

গতিশীলভাবে ভিউপজারে টুকরো যোগ করুন বা সরান।
ক্রিয়াকলাপের সূচনায় সেটআপভিউপ্যাজারকে (ভিউপ্যাজার) কল করুন। বিভিন্ন টুকরা কল সেটআপভিউপাগারকাস্টম (ভিউপাগার) লোড করতে। উদাহরণস্বরূপ বোতাম ক্লিক কল: সেটআপভিউপাগারকাস্টম (ভিউপাগার);

    private void setupViewPager(ViewPager viewPager)
{
    ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
    adapter.addFrag(new fragmnet1(), "HOME");
    adapter.addFrag(new fragmnet2(), "SERVICES");

    viewPager.setAdapter(adapter);
}

private void setupViewPagerCustom(ViewPager viewPager)
{

    ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());

    adapter.addFrag(new fragmnet3(), "Contact us");
    adapter.addFrag(new fragmnet4(), "ABOUT US");


    viewPager.setAdapter(adapter);
}

//Viewpageradapter, handles the views

static class ViewPagerAdapter extends FragmentStatePagerAdapter
{
    private final List<Fragment> mFragmentList = new ArrayList<>();
    private final List<String> mFragmentTitleList = new ArrayList<>();

    public ViewPagerAdapter(FragmentManager manager){
        super(manager);
    }

    @Override
    public Fragment getItem(int position) {
        return mFragmentList.get(position);
    }

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

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

    public void addFrag(Fragment fragment, String title){
        mFragmentList.add(fragment);
        mFragmentTitleList.add(title);
    }

    @Override
    public CharSequence getPageTitle(int position){
        return mFragmentTitleList.get(position);
    }
}

0

আমার কিছু সমস্যা ছিল FragmentStatePagerAdapter। একটি আইটেম সরানোর পরে:

  • পজিশনের জন্য অন্য আইটেম ব্যবহৃত হয়েছিল (একটি আইটেম যা পজিশনের সাথে নয় তবে তার পাশের অবস্থানে রয়েছে)
  • বা কিছু খণ্ড লোড করা হয়নি (সেই পৃষ্ঠায় কেবল ফাঁকা পটভূমি দৃশ্যমান ছিল)

প্রচুর পরীক্ষা-নিরীক্ষার পরে আমি নীচের সমাধানটি নিয়ে এসেছি।

public class SomeAdapter extends FragmentStatePagerAdapter {

    private List<Item> items = new ArrayList<Item>();

    private boolean removing;

    @Override
    public Fragment getItem(int position) {
        ItemFragment fragment = new ItemFragment();
        Bundle args = new Bundle();
        // use items.get(position) to configure fragment
        fragment.setArguments(args);
        return fragment;
    }

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

    @Override
    public int getItemPosition(Object object) {
        if (removing) {
            return PagerAdapter.POSITION_NONE;
        }

        Item item = getItemOfFragment(object);

        int index = items.indexOf(item);
        if (index == -1) {
            return POSITION_NONE;
        } else {
            return index;
        }
    }

   public void addItem(Item item) {
        items.add(item);
        notifyDataSetChanged();
    }

    public void removeItem(int position) {
        items.remove(position);

        removing = true;
        notifyDataSetChanged();
        removing = false;
    }
}

এই সমাধানটি কোনও আইটেম সরানোর ক্ষেত্রে কেবল একটি হ্যাক ব্যবহার করে। অন্যথায় (যেমন কোনও আইটেম যুক্ত করার সময়) এটি একটি মূল কোডটির পরিচ্ছন্নতা এবং কর্মক্ষমতা ধরে রাখে।

অবশ্যই, অ্যাডাপ্টারের বাইরে থেকে, আপনি কেবল অ্যাডটাইম / রিলিজ আইটেম কল করেন, নোটিফাইডডেটসেট চেঞ্জড () কল করার দরকার নেই।


0

এই সমাধান চেষ্টা করুন। বাইন্ডিং ভিউয়ের জন্য আমি ডেটাবাইন্ডিং ব্যবহার করেছি। আপনি সাধারণ "FindViewById ()" ফাংশন ব্যবহার করতে পারেন।

public class ActCPExpense extends BaseActivity implements View.OnClickListener,  {
private static final String TAG = ActCPExpense.class.getSimpleName();
private Context mContext;
private ActCpLossBinding mBinding;

private ViewPagerAdapter adapter;



@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    try {
        setContentView(R.layout.act_cp_loss);
        mBinding = DataBindingUtil.setContentView(this, R.layout.act_cp_loss);
        mContext = ActCPExpense.this;
        initViewsAct();


    } catch (Exception e) {
        LogUtils.LOGE(TAG, e);
    }

}


private void initViewsAct() {

    adapter = new ViewPagerAdapter(getSupportFragmentManager());
    adapter.addFragment(FragmentCPPayee.newInstance(), "Title");
    mBinding.viewpager.setAdapter(adapter);
    mBinding.tab.setViewPager(mBinding.viewpager);



}



@Override
public boolean onOptionsItemSelected(MenuItem itemActUtility) {
    int i = itemActUtility.getItemId();
    if (i == android.R.id.home) {
        onBackPressed();

    } 

    return super.onOptionsItemSelected(itemActUtility);
}

@Override
public void onClick(View view) {
    super.onClick(view);
    int id = view.getId();
    if (id == R.id.btnAdd) {
        addFragment();

    } else if (id == R.id.btnDelete) {
        removeFragment();

    }


}
    private void addFragment(){
    adapter.addFragment(FragmentCPPayee.newInstance("Title");
    adapter.notifyDataSetChanged();
    mBinding.tab.setViewPager(mBinding.viewpager);
}
private void removeFragment(){
    adapter.removeItem(mBinding.viewpager.getCurrentItem());
    mBinding.tab.setViewPager(mBinding.viewpager);
}


class ViewPagerAdapter extends FragmentStatePagerAdapter {
    private final List<Fragment> mFragmentList = new ArrayList<>();
    private final List<String> mFragmentTitleList = new ArrayList<>();


    public ViewPagerAdapter(FragmentManager manager) {
        super(manager);
    }

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


    @Override
    public Fragment getItem(int position) {
        return mFragmentList.get(position);
    }

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


    public void addFragment(Fragment fragment, String title) {
        mFragmentList.add(fragment);
        mFragmentTitleList.add(title);

    }

    public void removeItem(int pos) {

        destroyItem(null, pos, mFragmentList.get(pos));
        mFragmentList.remove(pos);
        mFragmentTitleList.remove(pos);
        adapter.notifyDataSetChanged();
        mBinding.viewpager.setCurrentItem(pos - 1, false);
    }

    @Override
    public CharSequence getPageTitle(int position) {
        return "Title " + String.valueOf(position + 1);
    }
}


}

0

আমি একটি ফাংশন "ক্লিয়ারফ্রেগমেন্টস" যুক্ত করেছি এবং আমি নতুন টুকরা সেট করার আগে অ্যাডাপ্টার সাফ করার জন্য সেই ফাংশনটি ব্যবহার করেছি। এটি খণ্ডগুলির যথাযথ অপসারণ কর্মগুলি কল করে। আমার পেজারআডাপ্টার ক্লাস:

private class ChartPagerAdapter extends FragmentPagerAdapter{
    private ArrayList<Fragment> fragmentList;

    ChartPagerAdapter(FragmentManager fm){
        super(fm);
        fragmentList = new ArrayList<>();
    }

    void setFragments(ArrayList<? extends Fragment> fragments){
        fragmentList.addAll(fragments);
    }

    void clearFragments(){
        for(Fragment fragment:fragmentList)
            getChildFragmentManager().beginTransaction().remove(fragment).commit();
        fragmentList.clear();
    }

    @Override
    public Fragment getItem(int i) {
        return fragmentList.get(i);
    }

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

}

0

আমি এই পদক্ষেপের দ্বারা এই সমস্যাটি সমাধান করেছি

1- ফ্র্যাগমেন্টপেজারএডাপ্টার ব্যবহার করুন

2- প্রতিটি খণ্ডে একটি এলোমেলো আইডি তৈরি করুন

fragment.id = new Random().nextInt();

3- অ্যাডাপ্টারে getItemPosition ওভাররাইড করুন r

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

অ্যাডাপ্টারে 4-ওভাররাইড getItemId

 @Override
public long getItemId(int position) {
    return mDatasetFragments.get(position).id;
}

5- এখন ডিলিট কোড হয়

 adapter.mDatasetFragments.remove(< item to delete position >);
 adapter.notifyDataSetChanged();

এটি আমার জন্য কাজ করেছে আমি আশা করি সহায়তা করি


0

আমার চূড়ান্ত সংস্করণ কোড, স্থির সমস্ত বাগ। এটি আমার 3 দিন সময় নিয়েছে

2020/07/18 আপডেট হয়েছে: আমি উত্স কোডের অনেকগুলি পরিবর্তন করেছি এবং এতগুলি বাগ ফিক্স করেছি, তবে আমি আজও এটি কার্যকর করার প্রতিশ্রুতি দিচ্ছি না।

https://github.com/lin1987www/FragmentBuilder/blob/master/commonLibrary/src/main/java/android/support/v4/app/FragmentStatePagerAdapterFix.java

public class FragmentStatePagerAdapterFix extends PagerAdapter {
    private static final String TAG = FragmentStatePagerAdapterFix.class.getSimpleName();
    private static final boolean DEBUG = false;

    private WeakReference<FragmentActivity> wrFragmentActivity;
    private WeakReference<Fragment> wrParentFragment;
    private final FragmentManager mFragmentManager;
    private FragmentTransaction mCurTransaction = null;

    protected ArrayList<Fragment> mFragments = new ArrayList<>();
    protected ArrayList<FragmentState> mFragmentStates = new ArrayList<>();
    protected ArrayList<String> mFragmentTags = new ArrayList<>();
    protected ArrayList<String> mFragmentClassNames = new ArrayList<>();
    protected ArrayList<Bundle> mFragmentArgs = new ArrayList<>();

    private Fragment mCurrentPrimaryItem = null;
    private boolean[] mTempPositionChange;

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

    public FragmentActivity getFragmentActivity() {
        return wrFragmentActivity.get();
    }

    public Fragment getParentFragment() {
        return wrParentFragment.get();
    }

    public FragmentStatePagerAdapterFix(FragmentActivity activity) {
        mFragmentManager = activity.getSupportFragmentManager();
        wrFragmentActivity = new WeakReference<>(activity);
        wrParentFragment = new WeakReference<>(null);
    }

    public FragmentStatePagerAdapterFix(Fragment fragment) {
        mFragmentManager = fragment.getChildFragmentManager();
        wrFragmentActivity = new WeakReference<>(fragment.getActivity());
        wrParentFragment = new WeakReference<>(fragment);
    }

    public void add(Class<? extends android.support.v4.app.Fragment> fragClass) {
        add(fragClass, null, null);
    }

    public void add(Class<? extends android.support.v4.app.Fragment> fragClass, Bundle args) {
        add(fragClass, args, null);
    }

    public void add(Class<? extends android.support.v4.app.Fragment> fragClass, String tag) {
        add(fragClass, null, tag);
    }

    public void add(Class<? extends android.support.v4.app.Fragment> fragClass, Bundle args, String tag) {
        add(fragClass, args, tag, getCount());
    }

    public void add(Class<? extends android.support.v4.app.Fragment> fragClass, Bundle args, String tag, int position) {
        mFragments.add(position, null);
        mFragmentStates.add(position, null);
        mFragmentTags.add(position, tag);
        mFragmentClassNames.add(position, fragClass.getName());
        mFragmentArgs.add(position, args);
        mTempPositionChange = new boolean[getCount()];
    }

    public void remove(int position) {
        if (position < getCount()) {
            mTempPositionChange = new boolean[getCount()];
            for (int i = position; i < mTempPositionChange.length; i++) {
                mTempPositionChange[i] = true;
            }
            mFragments.remove(position);
            mFragmentStates.remove(position);
            mFragmentTags.remove(position);
            mFragmentClassNames.remove(position);
            mFragmentArgs.remove(position);
        }
    }

    public void clear(){
        mFragments.clear();
        mFragmentStates.clear();
        mFragmentTags.clear();
        mFragmentClassNames.clear();
        mFragmentArgs.clear();
    }

    @Override
    public void startUpdate(ViewGroup container) {
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        Fragment fragment;
        // If we already have this item instantiated, there is nothing
        // to do.  This can happen when we are restoring the entire pager
        // from its saved state, where the fragment manager has already
        // taken care of restoring the fragments we previously had instantiated.
        fragment = mFragments.get(position);
        if (fragment != null) {
            return fragment;
        }
        if (mCurTransaction == null) {
            mCurTransaction = mFragmentManager.beginTransaction();
        }
        FragmentState fs = mFragmentStates.get(position);
        if (fs != null) {
            fragment = fs.instantiate(getFragmentActivity(), getParentFragment());
            // Fix bug
            // http://stackoverflow.com/questions/11381470/classnotfoundexception-when-unmarshalling-android-support-v4-view-viewpagersav
            if (fragment.mSavedFragmentState != null) {
                fragment.mSavedFragmentState.setClassLoader(fragment.getClass().getClassLoader());
            }
        }
        if (fragment == null) {
            fragment = Fragment.instantiate(getFragmentActivity(), mFragmentClassNames.get(position), mFragmentArgs.get(position));
        }
        if (DEBUG) {
            Log.v(TAG, "Adding item #" + position + ": f=" + fragment);
        }
        fragment.setMenuVisibility(false);
        fragment.setUserVisibleHint(false);
        mFragments.set(position, fragment);
        mFragmentStates.set(position, null);
        mCurTransaction.add(container.getId(), fragment, mFragmentTags.get(position));
        return fragment;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        Fragment fragment = (Fragment) object;
        if (mCurTransaction == null) {
            mCurTransaction = mFragmentManager.beginTransaction();
        }
        if (DEBUG) {
            Log.v(TAG, "Removing item #" + position + ": f=" + object
                    + " v=" + ((Fragment) object).getView());
        }
        if (position < getCount()) {
            FragmentState fragmentState = new FragmentState(fragment);
            Fragment.SavedState savedState = mFragmentManager.saveFragmentInstanceState(fragment);
            if (savedState != null) {
                fragmentState.mSavedFragmentState = savedState.mState;
            }
            mFragmentStates.set(position, fragmentState);
            mFragments.set(position, null);
        }
        mCurTransaction.remove(fragment);
    }

    @Override
    public void setPrimaryItem(ViewGroup container, int position, Object object) {
        Fragment fragment = (Fragment) object;
        if (fragment != mCurrentPrimaryItem) {
            if (mCurrentPrimaryItem != null) {
                mCurrentPrimaryItem.setMenuVisibility(false);
                mCurrentPrimaryItem.setUserVisibleHint(false);
            }
            if (fragment != null) {
                fragment.setMenuVisibility(true);
                fragment.setUserVisibleHint(true);
            }
            mCurrentPrimaryItem = fragment;
        }
    }

    @Override
    public void finishUpdate(ViewGroup container) {
        if (mCurTransaction != null) {
            mCurTransaction.commitAllowingStateLoss();
            mCurTransaction = null;
            mFragmentManager.executePendingTransactions();
            // Fix: Fragment is added by transaction. BUT didn't add to FragmentManager's mActive.
            for (Fragment fragment : mFragments) {
                if (fragment != null) {
                    fixActiveFragment(mFragmentManager, fragment);
                }
            }
        }
    }

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

    @Override
    public Parcelable saveState() {
        Bundle state = null;
        // 目前顯示的 Fragments
        for (int i = 0; i < mFragments.size(); i++) {
            Fragment f = mFragments.get(i);
            if (f != null && f.isAdded()) {
                if (state == null) {
                    state = new Bundle();
                }
                String key = "f" + i;
                mFragmentManager.putFragment(state, key, f);
            }
        }
        if (mFragmentStates.size() > 0) {
            if (state == null) {
                state = new Bundle();
            }
            FragmentState[] fs = new FragmentState[mFragmentStates.size()];
            mFragmentStates.toArray(fs);
            state.putParcelableArray("states_fragment", fs);
        }
        return state;
    }

    @Override
    public void restoreState(Parcelable state, ClassLoader loader) {
        if (state != null) {
            Bundle bundle = (Bundle) state;
            bundle.setClassLoader(loader);
            Parcelable[] fs = bundle.getParcelableArray("states_fragment");
            mFragments.clear();
            mFragmentStates.clear();
            mFragmentTags.clear();
            mFragmentClassNames.clear();
            mFragmentArgs.clear();
            if (fs != null) {
                for (int i = 0; i < fs.length; i++) {
                    FragmentState fragmentState = (FragmentState) fs[i];
                    mFragmentStates.add(fragmentState);
                    if (fragmentState != null) {
                        mFragmentArgs.add(fragmentState.mArguments);
                        mFragmentTags.add(fragmentState.mTag);
                        mFragmentClassNames.add(fragmentState.mClassName);
                    } else {
                        mFragmentArgs.add(null);
                        mFragmentTags.add(null);
                        mFragmentClassNames.add(null);
                    }
                    mFragments.add(null);
                }
            }
            Iterable<String> keys = bundle.keySet();
            for (String key : keys) {
                if (key.startsWith("f")) {
                    int index = Integer.parseInt(key.substring(1));
                    Fragment f = mFragmentManager.getFragment(bundle, key);
                    if (f != null) {
                        f.setMenuVisibility(false);
                        mFragments.set(index, f);
                        mFragmentArgs.set(index, f.mArguments);
                        mFragmentTags.set(index, f.mTag);
                        mFragmentClassNames.set(index, f.getClass().getName());
                    } else {
                        Log.w(TAG, "Bad fragment at key " + key);
                    }
                }
            }
            // If restore will change
            notifyDataSetChanged();
        }
    }

    public static void fixActiveFragment(FragmentManager fragmentManager, Fragment fragment) {
        FragmentManagerImpl fm = (FragmentManagerImpl) fragmentManager;
        if (fm.mActive != null) {
            int index = fragment.mIndex;
            Fragment origin = fm.mActive.get(index);
            if (origin != null) {
                if ((origin.mIndex != fragment.mIndex) || !(origin.equals(fragment))) {
                    Log.e(TAG,
                            String.format("fixActiveFragment: Not Equal! Origin: %s %s, Fragment: %s $s",
                                    origin.getClass().getName(), origin.mIndex,
                                    fragment.getClass().getName(), fragment.mIndex
                            ));
                }
            }
            fm.mActive.set(index, fragment);
        }
    }

    // Fix
    // http://stackoverflow.com/questions/10396321/remove-fragment-page-from-viewpager-in-android
    @Override
    public int getItemPosition(Object object) {
        int index = mFragments.indexOf(object);
        if (index < 0) {
            return PagerAdapter.POSITION_NONE;
        }
        boolean isPositionChange = mTempPositionChange[index];
        int result = PagerAdapter.POSITION_UNCHANGED;
        if (isPositionChange) {
            result = PagerAdapter.POSITION_NONE;
        }
        return result;
    }
}

আমার কাছে টুকরো টুকরো মেইনফ্রেগমেন্ট এবং অন্যান্য অংশ রয়েছে। আমি প্রতি 5 তম পজিশনের পরে অন্য ফ্র্যাগমেন্ট যুক্ত করছি এবং এটি অ্যারেলিস্টে নেই তাই সেই অন্য তালিকাটি তালিকায় না থাকলে কীভাবে সরিয়ে ফেলা যায়? আমি ভিউপ্যাজার 2
বি

গিথুব লিঙ্কটি কাজ করছে না
বি ডেভলপার

-1

আপনি কেবল destroyItemপদ্ধতিটি ওভাররাইড করতে পারেন

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
    fragmentManager.beginTransaction().remove((Fragment) object).commitNowAllowingStateLoss();
}

-9

আমি আশা করি এটি আপনি যা চান তা সহায়তা করতে পারে।

private class MyPagerAdapter extends FragmentStatePagerAdapter {

    //... your existing code

    @Override
    public int getItemPosition(Object object){
        return PagerAdapter.POSITION_UNCHANGED;
    }
}

9
এটি গৃহীত উত্তরের ঠিক বিপরীত - এটি কীভাবে কাজ করতে পারে ??
জোর্ডিড
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.