1. 程式人生 > >TabLayout 中 item 的自定義 & 使用 Fragment 的注意事項

TabLayout 中 item 的自定義 & 使用 Fragment 的注意事項

採用預設模式: 自定義 item 後(tabitem): 在 Fragment 採用 TabLayout + ViewPager 佈局:

public class OrderFragment extends Fragment {

    private TabLayout mTabLayout;
    private ViewPager mViewPager;

    public OrderFragment() {

    }

    public static OrderFragment newInstance() {
        OrderFragment fragment =
new OrderFragment(); Bundle args = new Bundle(); fragment.setArguments(args); return fragment; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (getArguments() != null) { } } @Nullable
@Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_order, container, false); initView(view); initTab(); return view; } private
void initView(View view) { mTabLayout = (TabLayout) view.findViewById(R.id.tab_layout); mViewPager = (ViewPager) view.findViewById(R.id.view_pager); } private void initTab() { String[] titles = {"待簽到", "進行中", "已完成", "已取消"}; ArrayList<Fragment> mFragmentList = new ArrayList<>(); mFragmentList.add(FirstFragment.newInstance()); mFragmentList.add(SecondFragment.newInstance()); mFragmentList.add(ThirdFragment.newInstance()); mFragmentList.add(FourthFragment.newInstance()); OrderPagerAdapter orderPagerAdapter = new OrderPagerAdapter(getChildFragmentManager(), titles, mFragmentList); mViewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(mTabLayout)); mViewPager.setAdapter(orderPagerAdapter); mTabLayout.setupWithViewPager(mViewPager); for (int i = 0; i < titles.length; i++) { // 獲得每一個tab TabLayout.Tab tab = mTabLayout.getTabAt(i); if (tab != null) { // 給每一個tab設定view tab.setCustomView(R.layout.item_tab_order_page); TextView textView = (TextView) tab.getCustomView().findViewById(R.id.tv_tab_title); textView.setText(titles[i]); if (i == 0) { // 設定第一個 tab 被選中 tab.getCustomView().findViewById(R.id.rl_tab).setSelected(true); textView.setTextColor(Color.BLACk); tab.getCustomView().findViewById(R.id.tab_indicator).setBackgroundColor(Color.BLUE); } } } mTabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() { @Override public void onTabSelected(TabLayout.Tab tab) { // mViewPager.setCurrentItem(tab.getPosition()); tab.getCustomView().findViewById(R.id.rl_tab).setSelected(true); TextView textView = (TextView) tab.getCustomView().findViewById(R.id.tv_tab_title); textView.setTextColor(Color.BLACk); tab.getCustomView().findViewById(R.id.tab_indicator).setBackgroundColor(Color.BLUE); } @Override public void onTabUnselected(TabLayout.Tab tab) { tab.getCustomView().findViewById(R.id.rl_tab).setSelected(false); TextView textView = (TextView) tab.getCustomView().findViewById(R.id.tv_tab_title); textView.setTextColor(Color.GRAY); tab.getCustomView().findViewById(R.id.tab_indicator).setBackgroundColor(Color.WHITE); } @Override public void onTabReselected(TabLayout.Tab tab) { } }); // tab 之間的分割線 LinearLayout linearLayout = (LinearLayout) mTabLayout.getChildAt(0); linearLayout.setShowDividers(LinearLayout.SHOW_DIVIDER_MIDDLE); linearLayout.setDividerDrawable(ContextCompat.getDrawable(getActivity(), R.drawable.divider_vertical)); } }

FragmentPagerAdapter:

public class OrderPagerAdapter extends FragmentPagerAdapter {

    private String[] mTitles;
    private ArrayList<Fragment> mFragmentList;

    public OrderPagerAdapter(FragmentManager fm, String[] titles, ArrayList<Fragment> fragmentList) {
        super(fm);
        mTitles = titles;
        mFragmentList = fragmentList;
    }

	// 已經採用自定義 item,這裡可以忽略掉
    /*@Override
    public CharSequence getPageTitle(int position) {
        return mTitles[position];
    }*/

    @Override
    public Fragment getItem(int position) {
        /*Fragment fragment = mFragmentList.get(position);
        Bundle bundle = new Bundle();
        bundle.putString("title", mTitles[position]);
        fragment.setArguments(bundle);*/
        return mFragmentList.get(position);
    }

    @Override
    public int getCount() {
        return mTitles.length;
    }
}

TabLayout + ViewPager 佈局檔案:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <android.support.design.widget.TabLayout
        android:id="@+id/tab_layout"
        android:layout_width="match_parent"
        android:layout_height="45dp"
        android:background="@color/white"
        app:tabIndicatorHeight="0dp" />

    <android.support.v4.view.ViewPager
        android:id="@+id/view_pager"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</LinearLayout>

自定義 item 佈局檔案:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/rl_tab"
    android:layout_width="match_parent"
    android:layout_height="@dimen/tab_item_height">

    <TextView
        android:id="@+id/tv_tab_title"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_centerInParent="true"
        android:gravity="center" />

    <TextView
        android:id="@+id/tv_tab_count"
        android:layout_width="@dimen/size_15"
        android:layout_height="@dimen/size_15"
        android:layout_alignParentRight="true"
        android:layout_marginTop="@dimen/size_5"
        android:background="@drawable/bg_circle_ff0000"
        android:gravity="center"
        android:text="3"
        android:textColor="@color/white"
        android:textSize="@dimen/size_10"
        android:textStyle="bold" />

    <View
        android:id="@+id/tab_indicator"
        android:layout_width="match_parent"
        android:layout_height="@dimen/size_2"
        android:layout_alignParentBottom="true"
        android:layout_marginLeft="@dimen/size_5"
        android:layout_marginRight="@dimen/size_5"
        android:background="@color/white" />

</RelativeLayout>

右上角數量提示背景圖(用 xml 當背景圖效率高於用圖片,且佔用少):

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval"
    android:useLevel="false">

    <solid android:color="#ff0000" />
    <size
        android:width="50dp"
        android:height="50dp" />

</shape>

用 newInstance 來初始化 Fragment: Activity 在預設情況下,切換橫豎屏,Activity 會銷燬重建,依附於上面的 Fragment 也會銷燬重建,Fragment 是通過反射進行重建的,而且,只調用了無參構造的方法,這也是有部分人通過 new Fragment() 的方式構建 Fragment時,遇到螢幕切換時,Fragment 會報空指標異常的原因!注意看程式碼中 f.setArguments(args); 也就是說,Fragment 在初始化之後會把引數儲存在 arguments 中,當 Fragment 再次重建的時候,它會檢查 arguments 中是否有引數存在,如果有,則拿出來再用,所以我們再 onCreate() 方法裡面才可以拿到之前設定的引數,但是:Fragment 在重建的時候不會呼叫有參構造,所以,通過 new Fragment() 的方法來初始化,Fragment 重建時,我們通過有參建構函式設定的引數就沒有了。

// 谷歌提供的模版
public class BlankFragment extends Fragment {
        // TODO: Rename parameter arguments, choosenames that match
        // the fragment initialization parameters,e.g. ARG_ITEM_NUMBER
        private static final String ARG_PARAM1 = "param1";
        private static final String ARG_PARAM2 = "param2";
        // TODO: Rename and change types of parameters
        private String mParam1;
        private String mParam2;

        public BlankFragment() {
                // Required empty public constructor
        }

        public static BlankFragment newInstance(String param1, String param2) {
                BlankFragment fragment = new BlankFragment();
                Bundle args = new Bundle();
                args.putString(ARG_PARAM1, param1);
                args.putString(ARG_PARAM2, param2);
                fragment.setArguments(args);
                return fragment;
        }

        @Override
        public void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                if (getArguments() != null) {
                        mParam1 = getArguments().getString(ARG_PARAM1);
                        mParam2 = getArguments().getString(ARG_PARAM2);
                }
         }

        @Override
        public View onCreateView(LayoutInflater inflater,ViewGroup container,  BundlesavedInstanceState) {
                // Inflate the layout for this fragment
                return inflater.inflate(R.layout.fragment_blank, container, false);
        }
}

PagerAdapter,FragmentPagerAdapter,FragmentPagerStateAdapter 的區別:

  • 三種 Adapter 的快取策略各有不同:
    • PagerAdapter:快取三個,通過重寫 instantiateItem 和 destroyItem 達到建立和銷燬 view 的目的。
    • FragmentPagerAdapter:內部通過 FragmentManager 來持久化每一個 Fragment,在 destroyItem 方法呼叫時只是 detach 對應的 Fragment,並沒有真正移除。
    • FragmentPagerStateAdapter:內部通過 FragmentManager 來管理每一個 Fragment,在 destroyItem 方法呼叫時移除對應的 Fragment。
  • 分情況使用這三個 Adapter :
    • PagerAdapter:當所要展示的檢視比較簡單時適用。
    • FragmentPagerAdapter:當所要展示的檢視是 Fragment,並且數量比較少時適用。
    • FragmentStatePagerAdapter:當所要展示的檢視是 Fragment,並且數量比較多時適用。