ViewPager,ActionBar,Fragment應用--模仿通訊錄滑動效果
阿新 • • 發佈:2019-01-30
最近由Android2.3切換到Android4.0的開發,一下子居然有點不適應,Android4.0新增了一些功能模組如ActionBar,Fragment等其實在Android3.0就有了,但一直沒有做過平板上的開發,所以對這些模組非常陌生,一下子感覺Android4.0的開發難度甚大,經過十來天的努力,終於略微有所悟,在看通訊錄的時候,感覺如果將其效果模仿出來豈不是初步達到掌握這些模組。
先看圖,再列舉出程式碼:
按住左右滑動時會自動切換。
主要程式碼如下:
package com.example.testtabactionbar; import android.net.Uri; import android.os.Bundle; import android.os.Parcelable; import android.provider.ContactsContract.Contacts; import android.app.ActionBar; import android.app.Activity; import android.app.Fragment; import android.app.FragmentManager; import android.app.FragmentTransaction; import android.app.ListFragment; import android.app.ActionBar.Tab; import android.app.LoaderManager.LoaderCallbacks; import android.content.CursorLoader; import android.content.Loader; import android.database.Cursor; import android.support.v4.view.PagerAdapter; import android.support.v4.view.ViewPager; import android.text.TextUtils; import android.util.Log; import android.view.ContextMenu; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.view.ContextMenu.ContextMenuInfo; import android.widget.ArrayAdapter; import android.widget.ListView; import android.widget.SimpleCursorAdapter; import android.widget.Toast; import android.widget.SearchView.OnQueryTextListener; public class MainActivity extends Activity { private ActionBar mActionBar; private static final TabState DEFAULT_TAB = TabState.GROUPS; private TabState mCurrentTab = DEFAULT_TAB; private final MyTabListener mTabListener = new MyTabListener(); private ArraListFragment mArrayFragment; private CursorLoaderFragment mCursorFragment; private ContextMenuFragment mContextMenuFragment; private ViewPager mTabPager; private TabPagerAdapter mTabPagerAdapter; private final TabPagerListener mTabPagerListener = new TabPagerListener(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.tab_view_pager); initActionBar(); createViewAndFragment(); } private void createViewAndFragment(){ final FragmentManager fragmentManager = getFragmentManager(); final FragmentTransaction transaction = fragmentManager.beginTransaction(); mTabPager = getView(R.id.tab_pager); mTabPagerAdapter = new TabPagerAdapter(); mTabPager.setAdapter(mTabPagerAdapter); mTabPager.setOnPageChangeListener(mTabPagerListener); final String FAVORITE_TAG = "tab-pager-favorite"; final String ALL_TAG = "tab-pager-all"; final String GROUPS_TAG = "tab-pager-groups"; // Create the fragments and add as children of the view pager. // The pager adapter will only change the visibility; it'll never create/destroy // fragments. // However, if it's after screen rotation, the fragments have been re-created by // the fragment manager, so first see if there're already the target fragments // existing. mContextMenuFragment = (ContextMenuFragment) fragmentManager .findFragmentByTag(FAVORITE_TAG); mArrayFragment = (ArraListFragment) fragmentManager .findFragmentByTag(ALL_TAG); mCursorFragment = (CursorLoaderFragment) fragmentManager .findFragmentByTag(GROUPS_TAG); if (mContextMenuFragment == null) { Log.e("HJJ", "ContextMenuFragmentd == null"); mContextMenuFragment = new ContextMenuFragment(); mArrayFragment = new ArraListFragment(); mCursorFragment = new CursorLoaderFragment(); transaction.add(R.id.tab_pager, mContextMenuFragment, FAVORITE_TAG); transaction.add(R.id.tab_pager, mArrayFragment, ALL_TAG); transaction.add(R.id.tab_pager, mCursorFragment, GROUPS_TAG); } // Hide all fragments for now. We adjust visibility when we get // onSelectedTabChanged() // from ActionBarAdapter. transaction.hide(mContextMenuFragment); transaction.hide(mArrayFragment); transaction.hide(mCursorFragment); transaction.commitAllowingStateLoss(); fragmentManager.executePendingTransactions(); } private class TabPagerListener implements ViewPager.OnPageChangeListener { @Override public void onPageScrollStateChanged(int state) { } @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { // Make sure not in the search mode, in which case position != TabState.ordinal(). TabState selectedTab = TabState.fromInt(position); setCurrentTab(selectedTab, false); invalidateOptionsMenu(); } } private void initActionBar(){ mActionBar = getActionBar(); mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); // 去掉預設標題欄 mActionBar.setDisplayShowHomeEnabled(false); mActionBar.setDisplayShowTitleEnabled(false); // Set up tabs addTab(TabState.GROUPS, R.drawable.ic_tab_groups); addTab(TabState.ALL, R.drawable.ic_tab_all); addTab(TabState.FAVORITES, R.drawable.ic_tab_starred); } private class TabPagerAdapter extends PagerAdapter { private final FragmentManager mFragmentManager; private FragmentTransaction mCurTransaction = null; private boolean mTabPagerAdapterSearchMode; private Fragment mCurrentPrimaryItem; public TabPagerAdapter() { mFragmentManager = getFragmentManager(); } @Override public int getCount() { return mTabPagerAdapterSearchMode ? 1 : TabState.values().length; } /** Gets called when the number of items changes. */ @Override public int getItemPosition(Object object) { if (mTabPagerAdapterSearchMode) { if (object == mArrayFragment) { return 0; // Only 1 page in search mode } } else { if (object == mContextMenuFragment) { return TabState.FAVORITES.ordinal(); } if (object == mArrayFragment) { return TabState.ALL.ordinal(); } if (object == mCursorFragment) { return TabState.GROUPS.ordinal(); } } return POSITION_NONE; } @Override public void startUpdate(View container) { } private Fragment getFragment(int position) { if (position == TabState.FAVORITES.ordinal()) { return mContextMenuFragment; } else if (position == TabState.ALL.ordinal()) { return mArrayFragment; } else if (position == TabState.GROUPS.ordinal()) { return mCursorFragment; } throw new IllegalArgumentException("position: " + position); } @Override public Object instantiateItem(View container, int position) { if (mCurTransaction == null) { mCurTransaction = mFragmentManager.beginTransaction(); } Fragment f = getFragment(position); mCurTransaction.show(f); // Non primary pages are not visible. //f.setUserVisibleHint(f == mCurrentPrimaryItem); return f; } @Override public void destroyItem(View container, int position, Object object) { if (mCurTransaction == null) { mCurTransaction = mFragmentManager.beginTransaction(); } mCurTransaction.hide((Fragment) object); } @Override public void finishUpdate(View container) { if (mCurTransaction != null) { mCurTransaction.commitAllowingStateLoss(); mCurTransaction = null; mFragmentManager.executePendingTransactions(); } } @Override public boolean isViewFromObject(View view, Object object) { return ((Fragment) object).getView() == view; } @Override public void setPrimaryItem(View container, int position, Object object) { Fragment fragment = (Fragment) object; if (mCurrentPrimaryItem != fragment) { if (mCurrentPrimaryItem != null) { //mCurrentPrimaryItem.setUserVisibleHint(false); } if (fragment != null) { //fragment.setUserVisibleHint(true); } mCurrentPrimaryItem = fragment; } } @Override public Parcelable saveState() { return null; } @Override public void restoreState(Parcelable state, ClassLoader loader) { } } @SuppressWarnings("unchecked") public <T extends View> T getView(int id) { T result = (T)findViewById(id); if (result == null) { throw new IllegalArgumentException("view 0x" + Integer.toHexString(id) + " doesn't exist"); } return result; } protected static void showFragment(FragmentTransaction ft, Fragment f) { if ((f != null) && f.isHidden()) ft.show(f); } protected static void hideFragment(FragmentTransaction ft, Fragment f) { if ((f != null) && !f.isHidden()) ft.hide(f); } private void addTab(TabState tabState, int icon) { final Tab tab = mActionBar.newTab(); tab.setTag(tabState); tab.setTabListener(mTabListener); tab.setIcon(icon); mActionBar.addTab(tab); } public enum TabState { GROUPS, ALL, FAVORITES; public static TabState fromInt(int value) { if (GROUPS.ordinal() == value) { return GROUPS; } if (ALL.ordinal() == value) { return ALL; } if (FAVORITES.ordinal() == value) { return FAVORITES; } throw new IllegalArgumentException("Invalid value: " + value); } } private class MyTabListener implements ActionBar.TabListener { /** * If true, it won't call {@link #setCurrentTab} in {@link #onTabSelected}. * This flag is used when we want to programmatically update the current tab without * {@link #onTabSelected} getting called. */ public boolean mIgnoreTabSelected; @Override public void onTabReselected(Tab tab, FragmentTransaction ft) { } @Override public void onTabUnselected(Tab tab, FragmentTransaction ft) { } @Override public void onTabSelected(Tab tab, FragmentTransaction ft) { Log.e("HJJ", "onTabSelected..tag:" + tab.getTag()); if (!mIgnoreTabSelected) { setCurrentTab((TabState)tab.getTag()); } } } /** * Change the current tab, and notify the listener. */ public void setCurrentTab(TabState tab) { setCurrentTab(tab, true); } /** * Change the current tab */ public void setCurrentTab(TabState tab, boolean notifyListener) { if (tab == null) throw new NullPointerException(); //實際上按照Contacts中的設計,這個是應該有效的,但在此模擬程式中,它會出現問題,因此暫時將此段去掉 // if (tab == mCurrentTab) { // return; // } mCurrentTab = tab; int index = mCurrentTab.ordinal(); if ((mActionBar.getNavigationMode() == ActionBar.NAVIGATION_MODE_TABS) && (index != mActionBar.getSelectedNavigationIndex())) { mActionBar.setSelectedNavigationItem(index); } if (notifyListener) onSelectedTabChanged(tab); } private void onSelectedTabChanged(TabState tab){ FragmentManager fragmentManager = getFragmentManager(); FragmentTransaction ft = fragmentManager.beginTransaction(); int tabIndex = tab.ordinal(); Log.e("HJJ", "tabIndex:" + tabIndex); switch (tab) { case FAVORITES: if(mContextMenuFragment!=null){ mTabPager.setCurrentItem(tabIndex, false); } showFragment(ft, mContextMenuFragment); hideFragment(ft, mArrayFragment); hideFragment(ft, mCursorFragment); break; case ALL: if(mArrayFragment!=null){ mTabPager.setCurrentItem(tabIndex, false); } hideFragment(ft, mContextMenuFragment); hideFragment(ft, mCursorFragment); showFragment(ft, mArrayFragment); break; case GROUPS: if(mCursorFragment!=null){ mTabPager.setCurrentItem(tabIndex, false); } hideFragment(ft, mContextMenuFragment); hideFragment(ft, mArrayFragment); showFragment(ft, mCursorFragment); break; } if (!ft.isEmpty()) { Log.e("HJJ", "not ft isEmpty"); ft.commitAllowingStateLoss(); fragmentManager.executePendingTransactions(); // When switching tabs, we need to invalidate options menu, but executing a // fragment transaction does it implicitly. We don't have to call invalidateOptionsMenu // manually. } } public static class ArraListFragment extends ListFragment{ @Override public void onActivityCreated(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onActivityCreated(savedInstanceState); String [] array = new String[]{"C", "C++", "Java"}; setListAdapter(new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, array)); } @Override public void onListItemClick(ListView l, View v, int position, long id) { // TODO Auto-generated method stub super.onListItemClick(l, v, position, id); } } public static class CursorLoaderFragment extends ListFragment implements OnQueryTextListener, LoaderCallbacks<Cursor> { SimpleCursorAdapter mAdapter; String mCurFilter; final String[] CONTACTS_SUMMARY_PROJECTION = new String[] { Contacts._ID, Contacts.DISPLAY_NAME, Contacts.CONTACT_STATUS, Contacts.CONTACT_PRESENCE, Contacts.PHOTO_ID, Contacts.LOOKUP_KEY, }; @Override public void onActivityCreated(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onActivityCreated(savedInstanceState); setEmptyText("No phone numbers"); setHasOptionsMenu(true); mAdapter = new SimpleCursorAdapter(getActivity(), android.R.layout.simple_list_item_2, null, new String[] { Contacts.DISPLAY_NAME, Contacts.CONTACT_STATUS }, new int[] { android.R.id.text1, android.R.id.text2 }, 0); setListAdapter(mAdapter); setListShown(false); getLoaderManager().initLoader(0, null, this); } // @Override // public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { // // TODO Auto-generated method stub // MenuItem item = menu.add("Search"); // item.setIcon(android.R.drawable.ic_menu_search); // item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM // | MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW); // SearchView sv = new SearchView(getActivity()); // sv.setOnQueryTextListener(this); // item.setActionView(sv); // } @Override public boolean onQueryTextChange(String newText) { // TODO Auto-generated method stub String newFilter = !TextUtils.isEmpty(newText) ? newText : null; if (mCurFilter == null && newFilter == null) { return true; } if (mCurFilter != null && mCurFilter.equals(newFilter)) { return true; } mCurFilter = newFilter; getLoaderManager().restartLoader(0, null, this); return true; } @Override public boolean onQueryTextSubmit(String query) { // TODO Auto-generated method stub return true; } @Override public void onListItemClick(ListView l, View v, int position, long id) { // TODO Auto-generated method stub super.onListItemClick(l, v, position, id); Cursor c = (Cursor) mAdapter.getItem(position); String name = c.getString(0); Toast.makeText(getActivity(), "name:" + name, Toast.LENGTH_SHORT) .show(); } @Override public Loader<Cursor> onCreateLoader(int id, Bundle args) { // TODO Auto-generated method stub Uri baseUri; if (mCurFilter != null) { baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, Uri.encode(mCurFilter)); } else { baseUri = Contacts.CONTENT_URI; } String select = "((" + Contacts.DISPLAY_NAME + " NOTNULL) AND (" + Contacts.HAS_PHONE_NUMBER + "=1) AND (" + Contacts.DISPLAY_NAME + " != '' ))"; return new CursorLoader(getActivity(), baseUri, CONTACTS_SUMMARY_PROJECTION, select, null, Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC"); } @Override public void onLoadFinished(Loader<Cursor> loader, Cursor data) { // TODO Auto-generated method stub mAdapter.swapCursor(data); if (isResumed()) { setListShown(true); } else { setListShownNoAnimation(true); } } @Override public void onLoaderReset(Loader<Cursor> arg0) { // TODO Auto-generated method stub mAdapter.swapCursor(null); } } public static class ContextMenuFragment extends Fragment{ @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // TODO Auto-generated method stub View root = inflater.inflate(R.layout.fragment_context_menu, container, false); registerForContextMenu(root.findViewById(R.id.long_press)); return root; } @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { // TODO Auto-generated method stub super.onCreateContextMenu(menu, v, menuInfo); menu.add(Menu.NONE, R.id.a_item, Menu.NONE, "Menu A"); menu.add(Menu.NONE, R.id.b_item, Menu.NONE, "Menu B"); } @Override public boolean onContextItemSelected(MenuItem item) { // TODO Auto-generated method stub switch (item.getItemId()) { case R.id.a_item: Toast.makeText(getActivity(), "a_item...", Toast.LENGTH_SHORT).show(); break; case R.id.b_item: Toast.makeText(getActivity(), "b_item...", Toast.LENGTH_SHORT).show(); break; default: break; } return super.onContextItemSelected(item); } } }