ViewPager,TabLayout,Fragment實現tabs滑動

  工做半年了,準備在新的一年開始寫點博客,記錄本身的成長,若是能給別人一些參考就更好了。android

Demo實現:

  前段時間公司的項目遇到了使用 ViewPager,TabLayoutFragment實現一個多個tab之間的滑動,這樣的效果在大部分的app中都有,由於有了5.0之後的TabLayout控件,實現這樣的效果簡單多了。下面是demo的效果圖:
圖片描述app

  接下來就是代碼了,先是Fragenmnt的xml文件:ide

<?xml version="1.0" encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:gravity="center"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:gravity="center"
        android:id="@+id/tv_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="hello world"
        />
</LinearLayout>

  爲了簡單就寫了個TextView,而後是Fragment的代碼:this

public class TestFragment extends Fragment {

    private static final String TAG ="TestFragment";
    private  int mIndex;
    @BindView(R.id.tv_content)
    TextView mContentTv;
    private View mTestView;
    
    public TestFragment(){}

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        mTestView = inflater.inflate(R.layout.fragment_test, container, false);
        ButterKnife.bind(this, mTestView);
        return mTestView;

    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        mContentTv.setText("TestFragment" + mIndex);
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mIndex = getArguments().getInt("index");//根據不一樣的額index顯示不一樣的內容
        
    }

    @Override
    public void onStart() {
        super.onStart();
        Log.d(TAG,"onStart()" + mIndex);
    }

    @Override
    public void onPause() {
        super.onPause();
        Log.d(TAG,"onPause()" + mIndex);
    }

    @Override
    public void onResume() {
        super.onResume();
        Log.d(TAG,"onResume()" + mIndex);
    }
}

  那幾個生命週期方法是爲了待會在Tab之間切換時跟蹤一下Fragment的生命週期方法。代碼裏爲了偷懶使用了butterknife插件=_=
  而後是Adapter的代碼:spa

 


    public class ViewPagerAdapter extends FragmentPagerAdapter {
    
        private List<String> mTabTitles ;
        private static final int FRAGMENT_COUNT = 6;
    
        public ViewPagerAdapter(FragmentManager fragmentManager, List<BaseFragment> fragments,List<String> tabTitles) {
            super(fragmentManager);
            mTabTitles = tabTitles;
        }
    
        @Override
        public Fragment getItem(int position) {
            TestFragment testFragment = new TestFragment();
            Bundle bundle = new Bundle();
            bundle.putInt("index",position);//傳入不一樣的index
            testFragment.setArguments(bundle);
            return testFragment;
        }
    
        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            return super.instantiateItem(container, position);
        }
    
        @Override
        public int getCount() {
            return FRAGMENT_COUNT;
        }
    
        //設置Tab的標題
        @Override
        public CharSequence getPageTitle(int position) {
            return mTabTitles.get(position);
        }
    }

  好像也沒什麼註釋的,接下來就是Activity的代碼了,把這些組合起來使用:插件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.why.demo.MainActivity">

    <android.support.design.widget.TabLayout
        android:id="@+id/tab_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:tabIndicatorColor="@color/colorAccent"
        app:tabIndicatorHeight="2dp"
        app:tabMode="fixed">

    </android.support.design.widget.TabLayout>
    <android.support.v4.view.ViewPager
        android:id="@+id/view_pager"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        >
    </android.support.v4.view.ViewPager>
</LinearLayout>
TabLayout的屬性app:tabMode還有一直模式scrollable,能夠自行嘗試。代碼部分:
public class MainActivity extends AppCompatActivity {

    @BindView(R.id.tab_layout)
    TabLayout mTabLayout;
    @BindView(R.id.view_pager)
    ViewPager mViewPager;
    private List<String> mTabTitles = new ArrayList<>();

    private List<BaseFragment> mFragments = new ArrayList<>();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);
        initTab();
        mViewPager.setAdapter(new ViewPagerAdapter(getSupportFragmentManager(),mFragments,mTabTitles));
     
        mTabLayout.setupWithViewPager(mViewPager);//注意:這行代碼不能少,使TabLayout和ViewPager綁定
    }

    //設置Tab的title
    private void initTab() {
        for (int i = 0; i < 6; i++) {
            mTabTitles.add("Tab" + i);
        }
    }
}

  這裏的代碼就只是將ViewPager和TabLayout結合,並設置了Adapter。到這裏效果就出來了,固然這裏沒有對TabLayout的講解,TabLayout出來也挺久了,除了官網的介紹外,也有不少博客對其進行了講解,這裏也就不介紹了。日誌

Fragment生命週期跟蹤:

  寫到這裏效果是有了,可是因爲ViewPager的預加載機制,致使我當時想實現幾個頁面同步更新同步(就是幾個tab用相同的內容,好比在tab1刪除了一些內容,但願在tab2也發生改變了,因爲預加載的緣由Fragment主要生命週期的方法不會再調用了因此沒法在Fragment的生存週期方法中實現改變)更新內容時遇到了點麻煩。先說下ViewPager預加載,每次加載三個,好比如今是ta2那麼ta1和tab3也被加載了(固然也能夠取消預加載),好比我在Acivity經過mViewPager.setCurrentItem(3),demo初始界面:
圖片描述code

日誌:
圖片描述xml

  能夠看到tab2,tab3,tab4的生命週期都被調用了。若是咱們從左往右滑動,日誌以下:
圖片描述生命週期

  如今在tab4,tab2調用了onPause(),tab5被加載了,tab3已經加載過了。若是咱們一開始是從右往左滑動,那麼日誌以下:
圖片描述

  如今在tab2,tab4調用了onPause(),tab1被加載了。

不一樣Tab的同步更新:

  回到前面的問題,如何同步更新不一樣tab的內容?在網上找到了一個方法,已經找不到到那篇csdn博客了,表示感謝,解決了個人問題。
  那篇博客裏的解決方法是給每一個fragment打上tag,使用是FragmentPagerAdapter內部的 String makeFragmentName(int viewId, long id)方法,這裏咱們能夠直接複製放在本身定義的ViewPagerAdapter裏給fragment打tag,這個動做放在instantiateItem(ViewGroup container, int position)中,而後要同步更新的時候調用FragmentManager.findFragmentByTag()獲取對應的Fragment就能夠調用相應的方法了,這裏是打上tag後的代碼:

public class ViewPagerAdapter extends FragmentPagerAdapter {

private List<String> mTabTitles ;
private static final int FRAGMENT_COUNT = 6;

private List<String> mFragmentTags = new ArrayList<>();

private FragmentManager mFragmentManager;

public ViewPagerAdapter(FragmentManager fragmentManager, List<BaseFragment> fragments,List<String> tabTitles) {
    super(fragmentManager);
    mTabTitles = tabTitles;
    this.mFragmentManager = fragmentManager;
}

@Override
public Fragment getItem(int position) {
    TestFragment testFragment = new TestFragment();
    Bundle bundle = new Bundle();
    bundle.putInt("index",position);//傳入不一樣的index
    testFragment.setArguments(bundle);
    return testFragment;
}

@Override
public Object instantiateItem(ViewGroup container, int position) {
    mFragmentTags.add(makeFragmentName(container.getId(),position));//設置tag
    return super.instantiateItem(container, position);
}

@Override
public int getCount() {
    return FRAGMENT_COUNT;
}

//設置Tab的標題
@Override
public CharSequence getPageTitle(int position) {
    return mTabTitles.get(position);
}

//這個方法是FragmentPagerAdapter內部方法,其內部就是根據這個給fragment打tag的,咱們直接使用能夠獲取正確的tag。
private static String makeFragmentName(int viewId, long id) {
    return "android:switcher:" + viewId + ":" + id;
}
//這個方法能夠在Fragment的代碼中調用
public void synchronizedFragment() {
    for (int i = 0; i < mFragmentTags.size();i++) {
        TestFragment testFragment = (TestFragment) mFragmentManager.findFragmentByTag(mFragmentTags.get(i));

        //接下來就能夠調用testFragment相應的更新方法了
        testFragment.update();
    }

}

}

  就這些了,有些內容參考過別人的文章就不一一貼出來了(好久之前看的),不少內容網上都有,這裏只是作個總結。

相關文章
相關標籤/搜索