问题很难描述,现在viewPager加顶部tab的界面几乎特别常见了,本文的目的就是实现对顶部tab重新排序,且下面的viewPager可以正确响应新的位置。
首先,相信一开始做得人都会发现,改变adapter的数据源,并调用下面的方法
this.notifyDataSetChanged();viewPager并不会有什么变化,并没刷新。跟踪可以发现,每次会调用一个getItemPosition的方法
<pre name="code" class="html">/**
* Called when the host view is attempting to determine if an item's position
* has changed. Returns {@link #POSITION_UNCHANGED} if the position of the given
* item has not changed or {@link #POSITION_NONE} if the item is no longer present
* in the adapter.
*
* <p>The default implementation assumes that items will never
* change position and always returns {@link #POSITION_UNCHANGED}.
*
* @param object Object representing an item, previously returned by a call to
* {@link #instantiateItem(View, int)}.
* @return <strong>object's new position index from [0, {@link #getCount()})</strong>,
* {@link #POSITION_UNCHANGED} if the object's position has not changed,
* or {@link #POSITION_NONE} if the item is no longer present.
*/
public int getItemPosition(Object object) {
return POSITION_UNCHANGED;
}
注意粗体字,就是他。如果需要页面刷新的应该有使用过返回POSITION NONE,这里我们只是简单的改变位置,所以只要返回新的位置即可。
<pre name="code" class="html"> @Override
public int getItemPosition(Object object) {
// Log.i("tab", "getItemPosition");
for (int i = 0; i < mTitle.length; i++) {
// 用标签判断是不是同一个fragment
if (mTitle[i].equals(((MainFragment) object).getTitle())) {
int newPosition = findNewPosition(i);
// Log.i("tab", "new position=" + newPosition + " which is " + ((MainFragment) object).getTitle());
<strong>return newPosition</strong>;
}
}
return super.getItemPosition(object);
}
很简单是吧?
另外,由于FragmentPagerAdapter是通过设置tag去寻找fragment,省去了我们去做缓存的处理,也因此我们只做了上面的处理后有的界面会出现缓存的或者空白的现象。
我们发现,每次要展现一个fragment是,适配器会调用instantiateItem。
<pre name="code" class="html"> @Override
public Object instantiateItem(ViewGroup container, int position) {
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
<strong> final long itemId = getItemId(position);</strong>
// Do we already have this fragment?
<strong> String name = makeFragmentName(container.getId(), itemId);
Fragment fragment = mFragmentManager.findFragmentByTag(name);</strong>
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));
}
if (fragment != mCurrentPrimaryItem) {
fragment.setMenuVisibility(false);
fragment.setUserVisibleHint(false);
}
return fragment;
}
<pre name="code" class="html"> private static String makeFragmentName(int viewId, long id) {
return "android:switcher:" + viewId + ":" + id;
}
可以发现,在instantiateItem函数中,每次通过
<strong>findFragmentByTag去查找fragment</strong>
tag其实就是item的id加上cantainer的id,默认的getItemID是返回position,所以我们只要重写getItemID就好了。
<pre name="code" class="html">/**
* Return a unique identifier for the item at the given position.
*
* <p>The default implementation returns the given position.
* <strong>Subclasses should override this method if the positions of items can change.</strong></p>
*
* @param position Position within this adapter
* @return Unique identifier for the item at position
*/
public long getItemId(int position) {
return position;
}
</pre><p></p><p>好的,方案出来了</p><p></p><pre name="code" class="html"><pre name="code" class="html"> @Override
public long getItemId(int position) {
// Log.i("tab", "getItemId " + position + " : " + newIdList.get(position));
// 返回新的id instantiateItem会通过getItemID去作为tag去查找fragment
return newIdList.get(position);
}
下面贴一下我的其他代码
用于触发重新排序的方法
public void insertTo(int from, int to) { // 改变标题排序 String tempString = titles.get(from); titles.remove(from); titles.add(to, tempString); Log.i("change", titles.toString()); // 生成新的id记录 int temp = newIdList.get(from); newIdList.remove(from); newIdList.add(to, temp); // Log.i("change", newIdList.toString()); this.notifyDataSetChanged(); // 刷新标题 for (int i = 0; i < mAdapter.getCount(); i++) { tabLayout.getTabAt(i).setText(mAdapter.getPageTitle(i)); } }另外上面的Tab标签使用的是TabLayout,这几乎是现在逐渐流行开的官方控件了,使用特别简单。
viewPager = (ViewPager) findViewById(R.id.vp_meipai); mAdapter = new mPagerAdapter(getSupportFragmentManager(), titleList); viewPager.setAdapter(mAdapter); tabLayout = (TabLayout) findViewById(R.id.tl_tap); // tabLayout.setTabsFromPagerAdapter(mAdapter);// 标题从viewPagerAdapter中获取 下一句(setupWithViewPager)默认调用 tabLayout.setupWithViewPager(viewPager);// 实现与ViewPager联动
@Override public Fragment getItem(int position) { // Log.i("tab", "getItem" + position); // MainFragment fragment= MainFragment.newInstance(titleList.get(position), "position" + position); MainFragment fragment = MainFragment.newInstance(mTitle[newIdList.get(position)], "position" + newIdList.get(position)); return fragment; } @Override public int getCount() { // Log.i("tab","getCount"); return titles.size(); }