Viewpager實現類似網易新聞的效果

1、添加Adapter

public class NewsFragmentPagerAdapter extends FragmentPagerAdapter {
    private static final String TAG ="PagerAdapter";
	private ArrayList<Fragment> fragments;
	private FragmentManager fm;
	private List<ChannelItem> userChannels;
	private ArrayList<Boolean> fragmentsUpdateFlag=new ArrayList<>();

	public NewsFragmentPagerAdapter(FragmentManager fm) {
		super(fm);
		this.fm = fm;
	}

	public NewsFragmentPagerAdapter(FragmentManager fm, ArrayList<Fragment> fragments, List<ChannelItem> userChannels) {
		super(fm);
		this.fm = fm;
		this.fragments = fragments;
		initFlag();
		this.userChannels =userChannels;
	}

	/**
	 * 初始化更新標誌位
	 */
	private void initFlag() {
		for (int i = 0; i < fragments.size(); i++) {
			fragmentsUpdateFlag.add(false);//初始化 都不需要更新
		}
	}

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

	/**
	 * @param position
	 * @return 艹 調用notifyDatasetChange getItem方法並沒有被調用
	 */
	@Override
	public Fragment getItem(int position) {
		Log.e(TAG,"getItem()被調用:"+position);
		return fragments.get(position);
	}

	/**
	 * 如果 Item 的位置如果沒有發生變化,則返回 POSITION_UNCHANGED。
	 * 如果返回了 POSITION_NONE,表示該位置的 Item 已經不存在了。
	 * 默認的實現是假設 Item 的位置永遠不會發生變化,而返回 POSITION_UNCHANGED,所以notifyXXXX沒有起作用
	 * @param object
	 * @return
	 */
	@Override
	public int getItemPosition(Object object) {
		return POSITION_NONE;
	}

	@Override
	public void destroyItem(ViewGroup container, int position, Object object) {
		super.destroyItem(container, position, object);
	}

	/**
	 * Viewpager 的刷新過程是這樣的,在每次調用 PagerAdapter 的 notifyDataSetChanged() 方法時,都會激活 getItemPosition(Object object) 方法,
	 * 該方法會遍歷 ViewPager 的所有 Item(由緩存的 Item 數量決定,默認爲當前頁和其左右加起來共3頁,這個可以自行設定,但是至少會緩存2頁),
	 * 爲每個 Item 返回一個狀態值(POSITION_NONE/POSITION_UNCHANGED),
	 * 如果是 POSITION_NONE,那麼該 Item 會被 destroyItem(ViewGroup container, int position, Object object) 方法 remove 掉,然後重新加載,
	 * 如果是 POSITION_UNCHANGED,就不會重新加載,默認是 POSITION_UNCHANGED,
	 * 所以如果不重寫 getItemPosition(Object object),修改返回值,就無法看到 notifyDataSetChanged() 的刷新效果。
	 * @param currentfrags 在這裏將所有的Fragment都移除了,貌似不太好吧
	 */
	public void setFragments(ArrayList<Fragment> currentfrags,List<ChannelItem> currentChannels) {
		/**
		 * 這裏可以確定哪些需要改變的麼?
		 * 這裏的條數 以新的Fragment爲主
		 * */
		if(currentChannels.size()>=userChannels.size()){
			for (int i = 0; i < userChannels.size(); i++) {
				if (userChannels.get(i).getId()==currentChannels.get(i).getId()){
					fragmentsUpdateFlag.set(i, false);//如果相同 就不需要更新了
				}else {
					fragmentsUpdateFlag.set(i,true);//如果不同 就更新
				}
			}
			for (int i = userChannels.size(); i < currentChannels.size(); i++) {
				fragmentsUpdateFlag.add(i,true);//多出來的部分都要更新
			}
		}else {
			//如果欄目減少了,多出來的部分就不用管了
			for (int i = 0; i < currentChannels.size(); i++) {
				if (userChannels.get(i).getId()==currentChannels.get(i).getId()){
					fragmentsUpdateFlag.set(i,false);//如果相同 就不需要更新了
				}else {
					fragmentsUpdateFlag.set(i,true);//如果不同 就更新
				}
			}
		}
		//更新集合
		fragments = currentfrags;
		userChannels=currentChannels;
		notifyDataSetChanged();
	}

	/**
	 * @param container
	 * @param position
	 * @return
	 */
	@Override
	public Object instantiateItem(ViewGroup container, final int position) {
		/*Object obj = super.instantiateItem(container, position);
		return obj;*/
		//得到緩存的fragment
		Fragment fragment = (Fragment) super.instantiateItem(container, position);
		//得到tag,這點很重要
		String fragmentTag = fragment.getTag();
		if (fragmentsUpdateFlag.get(position % getCount())) {
		//如果這個fragment需要更新
			FragmentTransaction ft = fm.beginTransaction();
			//移除舊的fragment
			ft.remove(fragment);
			//換成新的fragment
			fragment = fragments.get(position % getCount());
			//添加新fragment時必須用前面獲得的tag,這點很重要
			ft.add(container.getId(), fragment, fragmentTag);
			ft.attach(fragment);
			ft.commitAllowingStateLoss();
			//復位更新標誌
			fragmentsUpdateFlag.set(position % getCount(),false);
		}

		return fragment;
	}



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



2、Viewpager填充Adapter

    homeViewPager = (ViewPager) view.findViewById(R.id.homepager_menu_detail);
        pagerAdapter = new NewsFragmentPagerAdapter(mContext.getSupportFragmentManager(),fragments,userChannels);
        homeViewPager.setAdapter(pagerAdapter);

3、填充效果


4、滑動tab頁 Fragment加載順序

從頭條滑動到主題頁面:
08-08 17:05:33.464 15970-15970圖片的 onCreate()執行
08-08 17:05:33.464 15970-15970圖片onCreateView()執行

從專題頁滑動到圖片頁面:
08-08 17:07:08.344 15970-15970 原創的 onCreate()執行
08-08 17:07:08.344 15970-15970 原創onCreateView()執行
規律:viewPager會預加載下 一頁的數據

當所有頁面都create一遍後,viewpager預加載下一頁只會調用onCreateView方法:
08-08 17:08:18.744 15970-15970/cn.com.zgsyb.oil E/BaseFragment: 原創onCreateView()執行
08-08 17:08:20.184 15970-15970/cn.com.zgsyb.oil E/BaseFragment: 圖片onCreateView()執行
08-08 17:08:23.914 15970-15970/cn.com.zgsyb.oil E/BaseFragment: 專題onCreateView()執行
08-08 17:08:26.854 15970-15970/cn.com.zgsyb.oil E/BaseFragment: 頭條onCreateView()執行
08-08 17:08:31.974 15970-15970/cn.com.zgsyb.oil E/BaseFragment: 圖片onCreateView()執行
08-08 17:08:33.984 15970-15970/cn.com.zgsyb.oil E/BaseFragment: 原創onCreateView()執行
08-08 17:08:35.314 15970-15970/cn.com.zgsyb.oil E/BaseFragment: 本地onCreateView()執行
08-08 17:08:38.994 15970-15970/cn.com.zgsyb.oil E/BaseFragment: 培訓onCreateView()執行


5、需要解決的問題

5.1消除預加載(顯示界面的時候再加載數據)


5.2跳轉頁面順序,刷新數據





發佈了48 篇原創文章 · 獲贊 3 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章