欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

viewpager2 动态刷新效果

程序员文章站 2022-06-16 09:57:32
public class ViewPagerActivity extends AppCompatActivity { private List fragmentList = new ArrayList<>(); private ViewPager2Adapter adapter; private ViewPagerFragment viewPagerFragment1; private ViewPagerFragment vie....

viewpager2具体使用和引入依赖就不再多说了,现在想实现一个功能,怎么动态更改fragment的顺序,毕竟有些产品会提出tab可以拖动变化,那么fragment也得跟着tab的顺序重新排序。

如果想做到这些,就要先了解到viewpager2实现的adapter

先了解一下FragmentStateAdapter:

默认的实现方法有getItemCount\createFragment,这两个方法

getItemCount就不说了

createFragment:

viewpager2 动态刷新效果

意思就是

1、Fragment将用于显示item

2、当Fragment离视口太远时,就是切换到老前面了,它将被销毁,其状态将被保存。当item再次靠近视口时,将请求一个新的Fragment,并使用以前保存的状态来初始化它。recycler的

相当于做了recyclerview的复用加载

另外还有两个方法介绍一下:

viewpager2 动态刷新效果

1、默认实现适用于不添加、移动和移除项的集合,在这里可以进行移动的操作

2、重写时,还要重写containsItem(long)

3、如果该项不是集合的一部分,则返回RecyclerView.NO_标识

 

viewpager2 动态刷新效果

1、默认实现适用于不添加、移动和移除项的集合

2、重写时,还要重写getItemId(int)

 

按照我个人的理解,就是每个fragment需要有一个独立的标识,通过这个标识来进行移动替换和删除操作,

getItemId就是作为获取唯一标识的方法,FragmentStateAdapter类的源码里,实际上是处于recyclerview里的obBindVIewHolder的方法里面
@Override
    public final void onBindViewHolder(final @NonNull FragmentViewHolder holder, int position) {
        final long itemId = holder.getItemId();
        final int viewHolderId = holder.getContainer().getId();
        final Long boundItemId = itemForViewHolder(viewHolderId); // item currently bound to the VH
        if (boundItemId != null && boundItemId != itemId) {
            removeFragment(boundItemId);
            mItemIdToViewHolder.remove(boundItemId);
        }

        mItemIdToViewHolder.put(itemId, viewHolderId); // this might overwrite an existing entry
        ensureFragment(position);

        /** Special case when {@link RecyclerView} decides to keep the {@link container}
         * attached to the window, but not to the view hierarchy (i.e. parent is null) */
        final FrameLayout container = holder.getContainer();
        if (ViewCompat.isAttachedToWindow(container)) {
            if (container.getParent() != null) {
                throw new IllegalStateException("Design assumption violated.");
            }
            container.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
                @Override
                public void onLayoutChange(View v, int left, int top, int right, int bottom,
                        int oldLeft, int oldTop, int oldRight, int oldBottom) {
                    if (container.getParent() != null) {
                        container.removeOnLayoutChangeListener(this);
                        placeFragmentInViewHolder(holder);
                    }
                }
            });
        }
          here
        gcFragments();
    }

这里就明显是为了获取一个itemId,用于对比是不是在列表已然存在,其实再往上走就会发现他是recyclerview里面的getItem,就是将fragment自定义了一个标识,默认的是下标自然不行,所以这里要自定义。

然后再配合containsItem来进行增删的标识判断,相当于包了一层。

  private void ensureFragment(int position) {
        ///here/
        long itemId = getItemId(position);
        if (!mFragments.containsKey(itemId)) {
            // TODO(133419201): check if a Fragment provided here is a new Fragment
            Fragment newFragment = createFragment(position);
            newFragment.setInitialSavedState(mSavedStates.get(itemId));
            mFragments.put(itemId, newFragment);
        }
    }

然后看看containsItem在源码里做了什么:节选一个removeFragment的方法,这个方法很明显是为了删除已有的fragment的。containsItem就作为了是否已被移除的标准,如果里面不存在了标识,那么就会被删除

private void removeFragment(long itemId) {
        Fragment fragment = mFragments.get(itemId);

        if (fragment == null) {
            return;
        }

        if (fragment.getView() != null) {
            ViewParent viewParent = fragment.getView().getParent();
            if (viewParent != null) {
                ((FrameLayout) viewParent).removeAllViews();
            }
        }

        if (!containsItem(itemId)) {
            mSavedStates.remove(itemId);
        }

        if (!fragment.isAdded()) {
            mFragments.remove(itemId);
            return;
        }

        if (shouldDelayFragmentTransactions()) {
            mHasStaleFragments = true;
            return;
        }

        if (fragment.isAdded() && containsItem(itemId)) {
            mSavedStates.put(itemId, mFragmentManager.saveFragmentInstanceState(fragment));
        }
        mFragmentManager.beginTransaction().remove(fragment).commitNow();
        mFragments.remove(itemId);
    }

 

实际上在创建的时候就调用了这个方法

@Override
    public final void onBindViewHolder(final @NonNull FragmentViewHolder holder, int position) {
        final long itemId = holder.getItemId();
        final int viewHolderId = holder.getContainer().getId();
        final Long boundItemId = itemForViewHolder(viewHolderId); // item currently bound to the VH
        if (boundItemId != null && boundItemId != itemId) {
            removeFragment(boundItemId);
            mItemIdToViewHolder.remove(boundItemId);
        }

        mItemIdToViewHolder.put(itemId, viewHolderId); // this might overwrite an existing entry
        ensureFragment(position);

        /** Special case when {@link RecyclerView} decides to keep the {@link container}
         * attached to the window, but not to the view hierarchy (i.e. parent is null) */
        final FrameLayout container = holder.getContainer();
        if (ViewCompat.isAttachedToWindow(container)) {
            if (container.getParent() != null) {
                throw new IllegalStateException("Design assumption violated.");
            }
            container.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
                @Override
                public void onLayoutChange(View v, int left, int top, int right, int bottom,
                        int oldLeft, int oldTop, int oldRight, int oldBottom) {
                    if (container.getParent() != null) {
                        container.removeOnLayoutChangeListener(this);
                        placeFragmentInViewHolder(holder);
                    }
                }
            });
        }

        gcFragments();
    }

下面就根据这俩特性开始研究一下实现。这个博客是我借鉴的一篇,但是只有代码

https://zhuanlan.zhihu.com/p/105700960

然后上自己的代码

public class ViewPager2Adapter extends FragmentStateAdapter {
    private List<Fragment> fragmentList;
    private List<Long> fragmentIds = new ArrayList<>();//用于存储更新fragment的特定标识
    private HashSet<Long> creatIds = new HashSet<>();//得用hashset防重,用于存储adapter内的顺序


    public ViewPager2Adapter(@NonNull FragmentActivity fragmentActivity, List<Fragment> fragmentList) {
        super(fragmentActivity);
        this.fragmentList = fragmentList;
        update(fragmentList);
    }

    public void update(List<Fragment> fragmentLists) {
        fragmentIds.clear();
        for (int i = 0; i< fragmentLists.size(); i++){
            fragmentIds.add(((ViewPagerFragment)fragmentLists.get(i)).getTypeId());
        }
    }


    @NonNull
    @Override
    public Fragment createFragment(int position) {
        Long ids = fragmentIds.get(position);
        creatIds.add(ids);//创建的时候将未添加的fragment添加进来,每次刷新都会调用这里,其次调用containsItem
        return fragmentList.get(position);
    }

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

    /**
     * 这两个方法必须重写,作为数据改变刷新检测的工具
     * @param position
     * @return
     */
    @Override
    public long getItemId(int position) {
        return fragmentIds.get(position);
    }

    @Override
    public boolean containsItem(long itemId) {
        return creatIds.contains(itemId);
    }
}

 

下面这里简单用了一下notifyDataSetChanged的方法,这个更新不过就是利用了recyclerview的更新操作,实现思路在这里,具体优化具体分析

public class ViewPagerActivity extends AppCompatActivity {

    private List<Fragment> fragmentList = new ArrayList<>();
    private ViewPager2Adapter adapter;
    private ViewPagerFragment viewPagerFragment1;
    private ViewPagerFragment viewPagerFragment2;
    private ViewPagerFragment viewPagerFragment3;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.viewpager2_view);
        initView();
    }

    private void initView() {
        viewPagerFragment1 = new ViewPagerFragment(1l).newInstance(1l);
        viewPagerFragment2 = new ViewPagerFragment(2l).newInstance(2l);
        viewPagerFragment3 = new ViewPagerFragment(3l).newInstance(3l);
        fragmentList.add(viewPagerFragment1);
        fragmentList.add(viewPagerFragment2);
        fragmentList.add(viewPagerFragment3);
        ViewPager2 viewPager2 = findViewById(R.id.viewpager);
        Button change = findViewById(R.id.change);
        adapter = new ViewPager2Adapter(this, fragmentList);
        viewPager2.setAdapter(adapter);
        change.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Collections.shuffle(fragmentList);//随机排序
                adapter.update(fragmentList);
//              adapter.notifyItemRemoved(0);//删除操作
                adapter.notifyDataSetChanged();
            }
        });
    }
}
public class ViewPagerFragment extends Fragment {

    private  long key;

    public ViewPagerFragment(long l) {
        this.key = l;
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View inflate = inflater.inflate(R.layout.viewpagerfragment_layout, container);
        return inflate;
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        key = getArguments().getLong("key");
        TextView textview = view.findViewById(R.id.textview);
        textview.setText("我是"+key);
    }

    public  long getTypeId() {
        return key;
    }
    public ViewPagerFragment newInstance(long l) {
        ViewPagerFragment viewPagerFragment = new ViewPagerFragment(l);
        Bundle bundle = new Bundle();
        bundle.putLong("key", l);
        viewPagerFragment.setArguments(bundle);
        return viewPagerFragment;
    }
}

 

本文地址:https://blog.csdn.net/czZ__czZ/article/details/110226631

相关标签: android