It feels like Android is full of pits, and every place has to toss people around for half a day.
Today let's talk about Android's ActionBar, Tabs, Fragment, ViewPager to switch tabs and cache pages.
There's no more about their introduction. There's a lot of information on the Internet, just the key parts.
When I was developing, I encountered several difficult problems and spent a lot of time dealing with them, which can be summarized as follows:
1. Which event callback section should I write about Fragment's internal logic processing?
2. ViewPager page switch animation carton, let me have a headache for a long time.
3. How to save the status of Fragment's current view in ViewPager so that Tabs pages will not be reloaded after switching? This place is very frustrating.
4. How tab s in ActionBar scroll through many times
Answer:
1. Fragment's event callback:
package com.ai9475.meitian.ui.fragment; import android.app.Activity; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ListView; import com.ai9475.meitian.R; import com.ai9475.meitian.view.DiaryList; import com.ai9475.util.ZLog; /** * * Created by ZHOUZ on 14-1-21. */ public class DiaryListFragment extends BaseFragment { private static final String TAG = "DiaryListFragment"; @Override public void onAttach(Activity activity) { ZLog.i(TAG, "onAttach"); super.onAttach(activity); } @Override public void onCreate(Bundle savedInstanceState) { ZLog.i(TAG, "onCreate"); super.onCreate(savedInstanceState); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { ZLog.i(TAG, "onCreateView"); return inflater.inflate(R.layout.fragment_diary_list, container, false); } @Override public void onActivityCreated(Bundle savedInstanceState) { ZLog.i(TAG, "onActivityCreated"); super.onActivityCreated(savedInstanceState); ZLog.i(TAG, "DiaryList0"); DiaryList diaryList = new DiaryList( getActivity().getApplicationContext(), (ListView) getView().findViewById(R.id.diaryListCt) ); ZLog.i(TAG, "DiaryList load0"); diaryList.load("http://m.ai9475.com/?con=meitian_app"); this.setRetainInstance(true); } @Override public void onStart() { ZLog.i(TAG, "onStart"); super.onStart(); } @Override public void onResume() { ZLog.i(TAG, "onResume"); super.onResume(); } @Override public void onPause() { ZLog.i(TAG, "onPause"); super.onPause(); } @Override public void onStop() { ZLog.i(TAG, "onStop"); super.onStop(); } @Override public void onDestroyView() { ZLog.i(TAG, "onDestroyView"); super.onDestroyView(); } @Override public void onDestroy() { ZLog.i(TAG, "onDestroy"); super.onDestroy(); } @Override public void onDetach() { ZLog.i(TAG, "onDetach"); super.onDetach(); } }
The on event in the above class is the time callback that Fragment mainly handles. Note that when you override the parent method, you need to call to execute the parent method with the same name, otherwise you will make a mistake.
Mainly override the onCreateView method to return the view object corresponding to the Fragment. Here, some simple configuration can be done before returning the view object, but do not write too time-consuming processing to block the UI main thread.
In addition, the onActivityCreated method is a callback at the end of the onCreate event of the activity, when the view corresponding to the current Fragment has been incorporated into the entire layout, at which time the view object can be obtained using the getView() method.
There are not many other events to say, some of which I am not very clear, and some of which are animated calls.
2. Cutting Page
This problem may arise in two main ways.
1. The ViewPager cache is not used and is reloaded every time you switch.
2. Loading Fragment has time-consuming and resource-consuming logic processing.
Here's the second case. When I didn't deal with the cache problem at first, I had a solution.
<android.support.v4.view.ViewPager android:id="@+id/tabsViewPager" android:layout_width="match_parent" android:layout_height="match_parent" > </android.support.v4.view.ViewPager>
mViewPager = (ViewPager) findViewById(R.id.tabsViewPager); mViewPager.setOnPageChangeListener( new ViewPager.SimpleOnPageChangeListener() { private static final String TAG = "ViewPager.SimpleOnPageChangeListener"; private ArrayList hasLoadedPages = new ArrayList<Integer>(); @Override public void onPageSelected(int position) { ZLog.i(TAG, "onPageSelected position:"+ position); getSupportActionBar().setSelectedNavigationItem(position); } @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { ZLog.i(TAG, "onPageScrolled position: "+ position +", positionOffset:"+ positionOffset +", positionOffsetPixels:"+ positionOffsetPixels); } @Override public void onPageScrollStateChanged(int state) { ZLog.i(TAG, "onPageScrollStateChanged"); int position = mViewPager.getCurrentItem(); switch (state) { // Dragging case ViewPager.SCROLL_STATE_DRAGGING : ZLog.i(TAG, "ViewPager.SCROLL_STATE_DRAGGING position:"+ position); break; // The process of settling after dragging release. case ViewPager.SCROLL_STATE_SETTLING : ZLog.i(TAG, "ViewPager.SCROLL_STATE_SETTLING position:"+ position); break; // Switching Animation Completed case ViewPager.SCROLL_STATE_IDLE : ZLog.i(TAG, "ViewPager.SCROLL_STATE_IDLE position:"+ position); // Loaded but not reloaded if (hasLoadedPages.contains(position)) break; Fragment fragment = mPager.getFragments().get(position); runCallback(position, fragment); hasLoadedPages.add(position); break; } } public void runCallback(int position, Fragment fragment) { ZLog.i(TAG, "runCallback"); DiaryList diaryList; switch (position) { case 0 : ZLog.i(TAG, "DiaryList0"); diaryList = new DiaryList( getApplicationContext(), (ListView) fragment.getView().findViewById(R.id.diaryListCt) ); ZLog.i(TAG, "DiaryList load0"); diaryList.load("http://m.ai9475.com/?con=meitian_app"); break; case 1: ZLog.i(TAG, "DiaryList1"); diaryList = new DiaryList( getApplicationContext(), (ListView) fragment.getView().findViewById(R.id.diaryListCt) ); ZLog.i(TAG, "DiaryList load1"); diaryList.load("http://m.ai9475.com/?con=meitian_app&act=hot"); break; case 2: ZLog.i(TAG, "DiaryList2"); diaryList = new DiaryList( getApplicationContext(), (ListView) fragment.getView().findViewById(R.id.diaryListCt) ); ZLog.i(TAG, "DiaryList load2"); diaryList.load("http://m.ai9475.com/?con=meitian_app"); break; } } }
This is mainly used for event monitoring of scroll switching state changes on public void onPageScrollStateChanged(int state) pages
When the scroll animation completes case ViewPager.SCROLL_STATE_IDLE, the logical processing of Fragment is performed, so that the animation will flow smoothly.
But after testing later, we found that there is a very simple solution, that is, the caching function of ViewPager, which is very simple.
3. Caching Tabs page switching without reloading data
I've been struggling here for the longest time, and sometimes I can't get started. Many articles on the Internet have talked about how to save Fragment's data and status, but I haven't mentioned how to save his current view status entirely. I don't know how to save it. Of course, I still don't know how to cache Fragment's status, but it corresponds to the Tab cache of ViewPager. Fragment still found a way to do it. He spent a lot of time doing it himself, but then he happened to find out that he had a way to do it.
// Set how many Tab s to cache for fragment s mViewPager.setOffscreenPageLimit(6);
I used 6 listView s to load the image list data in my test, and there was no cartoon phenomenon in the switching animation. It was very smooth. It was done in such a simple sentence.
After configuring this item, ViewPager will not clean up invisible Fragments when switching, trigger any events of Fragments, and therefore will not cause them to reload.
Tabs in ActionBar
After the number of tabs exceeds one screen, for example, if I set six widths above the screen now, it will become a state of horizontal scrolling, without self-realization. I didn't know that I had checked a lot of data in this area, but I only knew that it could be achieved with tabhost, but I didn't use it in ActionBar. I tried several tabs below to find out. Originally, it will be automatic, silent.
Stick the complete code of MainActivity.class:
package com.ai9475.meitian.ui; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentPagerAdapter; import android.support.v4.app.FragmentStatePagerAdapter; import android.support.v4.app.FragmentTransaction; import android.support.v4.view.ViewPager; import android.support.v7.app.ActionBar; import android.view.Menu; import android.widget.ListView; import com.ai9475.meitian.AppManager; import com.ai9475.meitian.R; import com.ai9475.meitian.ui.fragment.DiaryListFragment; import com.ai9475.meitian.ui.fragment.Test2Fragment; import com.ai9475.meitian.ui.fragment.Test3Fragment; import com.ai9475.meitian.view.DiaryList; import com.ai9475.util.ZLog; import java.util.ArrayList; public class MainActivity extends BaseActivity { private static final String TAG = "MainActivity"; private MyTabsPagerAdapter mPager; private ViewPager mViewPager; @Override protected void onCreate(Bundle savedInstanceState) { ZLog.i(TAG, "start"); // Execute parent initialization method super.onCreate(savedInstanceState); //requestWindowFeature(Window.FEATURE_NO_TITLE); ZLog.i(TAG, "setContentView"); setContentView(R.layout.activity_main); // Sliding Page View Configuration ZLog.i(TAG, "MyTabsPagerAdapter start"); mPager = new MyTabsPagerAdapter(getSupportFragmentManager()); mPager.getFragments().add(new DiaryListFragment()); mPager.getFragments().add(new Test2Fragment()); mPager.getFragments().add(new Test3Fragment()); mPager.getFragments().add(new Test3Fragment()); mPager.getFragments().add(new Test3Fragment()); mPager.getFragments().add(new Test3Fragment()); // Sliding Paging Container mViewPager = (ViewPager) findViewById(R.id.tabsViewPager); // How many fragment s are cached mViewPager.setOffscreenPageLimit(6); mViewPager.setAdapter(mPager); // Page sliding events mViewPager.setOnPageChangeListener( new ViewPager.SimpleOnPageChangeListener() { private static final String TAG = "ViewPager.SimpleOnPageChangeListener"; private ArrayList hasLoadedPages = new ArrayList<Integer>(); @Override public void onPageSelected(int position) { ZLog.i(TAG, "onPageSelected position:"+ position); getSupportActionBar().setSelectedNavigationItem(position); } @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { ZLog.i(TAG, "onPageScrolled position: "+ position +", positionOffset:"+ positionOffset +", positionOffsetPixels:"+ positionOffsetPixels); } @Override public void onPageScrollStateChanged(int state) { ZLog.i(TAG, "onPageScrollStateChanged"); int position = mViewPager.getCurrentItem(); switch (state) { // Dragging case ViewPager.SCROLL_STATE_DRAGGING : ZLog.i(TAG, "ViewPager.SCROLL_STATE_DRAGGING position:"+ position); break; // The process of settling after dragging release. case ViewPager.SCROLL_STATE_SETTLING : ZLog.i(TAG, "ViewPager.SCROLL_STATE_SETTLING position:"+ position); break; // Switching Animation Completed case ViewPager.SCROLL_STATE_IDLE : ZLog.i(TAG, "ViewPager.SCROLL_STATE_IDLE position:"+ position); /*if (hasLoadedPages.contains(position)) break; Fragment fragment = mPager.getFragments().get(position); runCallback(position, fragment); hasLoadedPages.add(position);*/ break; } } public void runCallback(int position, Fragment fragment) { ZLog.i(TAG, "runCallback"); DiaryList diaryList; switch (position) { case 0 : ZLog.i(TAG, "DiaryList0"); diaryList = new DiaryList( getApplicationContext(), (ListView) fragment.getView().findViewById(R.id.diaryListCt) ); ZLog.i(TAG, "DiaryList load0"); diaryList.load("http://m.ai9475.com/?con=meitian_app"); break; case 1: ZLog.i(TAG, "DiaryList1"); diaryList = new DiaryList( getApplicationContext(), (ListView) fragment.getView().findViewById(R.id.diaryListCt) ); ZLog.i(TAG, "DiaryList load1"); diaryList.load("http://m.ai9475.com/?con=meitian_app&act=hot"); break; case 2: ZLog.i(TAG, "DiaryList2"); diaryList = new DiaryList( getApplicationContext(), (ListView) fragment.getView().findViewById(R.id.diaryListCt) ); ZLog.i(TAG, "DiaryList load2"); diaryList.load("http://m.ai9475.com/?con=meitian_app"); break; } } } ); ActionBar actionBar = getSupportActionBar(); actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); // Tab page switching MyTabListener listener = new MyTabListener(); // Default home tab ActionBar.Tab indexTab = actionBar.newTab() .setText(getString(R.string.tab_index)) .setTabListener(listener); actionBar.addTab(indexTab); actionBar.addTab(actionBar.newTab() .setText(getString(R.string.tab_hot)) .setTabListener(listener) ); actionBar.addTab(actionBar.newTab() .setText(getString(R.string.tab_tag)) .setTabListener(listener) ); actionBar.addTab(actionBar.newTab() .setText(getString(R.string.tab_tag)) .setTabListener(listener) ); actionBar.addTab(actionBar.newTab() .setText(getString(R.string.tab_tag)) .setTabListener(listener) ); actionBar.addTab(actionBar.newTab() .setText(getString(R.string.tab_tag)) .setTabListener(listener) ); // Display Home Page indexTab.select(); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.main, menu); return true; } private class MyTabListener implements ActionBar.TabListener { @Override public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) { int position = tab.getPosition(); ZLog.i(TAG, "tab selected: "+ position); // data communication /*Bundle bundle = new Bundle(); Fragment fragment = mPager.getItem(tab.getPosition()); Toast.makeText(getApplicationContext(), "position:"+ tab.getPosition(), Toast.LENGTH_SHORT).show(); fragment.setArguments(bundle); FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction(); fragmentTransaction.add(R.id.fragmentContainer, fragment); fragmentTransaction.commit();*/ mViewPager.setCurrentItem(position); } @Override public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) { ZLog.i(TAG, "tab reselected: "+ tab.getPosition()); } @Override public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) { ZLog.i(TAG, "tab unselected: "+ tab.getPosition()); } }; public class MyTabsPagerAdapter extends FragmentPagerAdapter { private ArrayList<Fragment> mFragments = new ArrayList<Fragment>(); public MyTabsPagerAdapter(FragmentManager fm) { super(fm); } public ArrayList<Fragment> getFragments() { return this.mFragments; } @Override public Fragment getItem(int i) { return this.mFragments.get(i); } @Override public int getCount() { return this.mFragments.size(); } } }
Reproduced in: https://my.oschina.net/zhouz/blog/213092