Tablayout ViewPage 使用示例

上一篇文章介绍了使用 FragmenttabHost 来使用 tab 导航;到 Android 5.0 的时候,又推出了 TabLayout。因此,有必要对tablayout 进行了解下。

首先我们来看MainActivity,看起来有点多,那是因为包含了 toolbar 的代码:

public class MainActivity extends AppCompatActivity {

    private TabLayout tabLayout;
    private ViewPager viewPager;
    private MyViewPagerAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });

        tabLayout = (TabLayout) findViewById(R.id.tab_layout);
        viewPager = (ViewPager) findViewById(R.id.pager);

        int s = 0;

        if (viewPager != null) {
            setupViewPager(viewPager);
        }
    }

    private void setupViewPager(ViewPager viewPager) {
        adapter = new MyViewPagerAdapter(getSupportFragmentManager(), this);
        adapter.addFragment(new TabFragment1().newInstance("Page1"), "Tab 1");
        adapter.addFragment(new TabFragment2().newInstance("Page2"), "Tab 2");
        adapter.addFragment(new TabFragment3().newInstance("Page3"), "Tab 3");
        viewPager.setAdapter(adapter);
        tabLayout.setupWithViewPager(viewPager);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
}

首先是初始化 tabLayout 和 viewPager,接着是建立一个 MyViewPagerAdapter 的实例,并向里面添加 fragment。

那我们就去看看神秘的 MyViewPagerAdapter。

public class MyViewPagerAdapter extends FragmentStatePagerAdapter {

    private final List<Fragment> myFragments = new ArrayList<>();
    private final List<String> myFragmentTitles = new ArrayList<>();
    private Context context;

    public MyViewPagerAdapter(FragmentManager fm, Context context) {
        super(fm);
        this.context = context;
    }

    public void addFragment(Fragment fragment, String title) {
        myFragments.add(fragment);
        myFragmentTitles.add(title);
    }

    @Override
    public Fragment getItem(int position) {
        return myFragments.get(position);
    }

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

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

 这里我们重写了其中几个方法,分别是 getItem,getCount,getPageTitle。那这样我们的数量能够传进去嘛?

不用怕,当我们调用 setAdapt 的时候,其实就把 adapt 传进 ViewPager 了,当需要获取数量的时候,直接调用这个方法就可以了。

tabLayout.setupWithViewPager(viewPager) 则是把tab 与ViewPage 建立联系,这样在变动的时候一起变,在TabLaout 中,可以通过 viewPager.getAdapt 来获取我们刚刚穿进去的adapt;这样两者都有 adapt 这个变量了。

public void setupWithViewPager(ViewPager viewPager) {
        PagerAdapter adapter = viewPager.getAdapter();
        if(adapter == null) {
            throw new IllegalArgumentException("ViewPager does not have a PagerAdapter set");
        } else {
            this.setTabsFromPagerAdapter(adapter);
            viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(this));
            this.setOnTabSelectedListener(new TabLayout.ViewPagerOnTabSelectedListener(viewPager));
        }
    }

 看源码可以发现 tablayout 和 viewpager 互相设置或者添加监听器,这样无论是滑动 viewPager,还是点击tab都可以实现 view 的切换,两者就可以同步了。

public static class ViewPagerOnTabSelectedListener implements TabLayout.OnTabSelectedListener {
        private final ViewPager mViewPager;

        public ViewPagerOnTabSelectedListener(ViewPager viewPager) {
            this.mViewPager = viewPager;
        }

        public void onTabSelected(TabLayout.Tab tab) {
            this.mViewPager.setCurrentItem(tab.getPosition());
        }

        public void onTabUnselected(TabLayout.Tab tab) {
        }

        public void onTabReselected(TabLayout.Tab tab) {
        }
    }

我们可以具体看看 ViewPagerOnTabSelectedListener,发现其实现了 TabLayout.OnTabSelectedListener 的接口,在构造函数中,将 viewPager 变量赋值给内部变量,这样在 tab 选中的时候,获取选中 tab 的 position,然后再将设置显示 同样位置的 fragment 即可。

public static class TabLayoutOnPageChangeListener implements OnPageChangeListener {
        private final WeakReference<TabLayout> mTabLayoutRef;
        private int mScrollState;

        public TabLayoutOnPageChangeListener(TabLayout tabLayout) {
            this.mTabLayoutRef = new WeakReference(tabLayout);
        }

        public void onPageScrollStateChanged(int state) {
            this.mScrollState = state;
        }

        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
            TabLayout tabLayout = (TabLayout)this.mTabLayoutRef.get();
            if(tabLayout != null) {
                tabLayout.setScrollPosition(position, positionOffset, this.mScrollState == 1);
            }

        }

        public void onPageSelected(int position) {
            TabLayout tabLayout = (TabLayout)this.mTabLayoutRef.get();
            if(tabLayout != null) {
                tabLayout.getTabAt(position).select();
            }

        }
    }

当滑动页面,回掉  onPageSelected,传入目前选中的 pager,这时候只要指定对应的 tab 即可。这样两者很好的进行同步了。

我们再来看看布局文件:

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:context=".MainActivity">

    <android.support.design.widget.AppBarLayout android:layout_height="wrap_content"
        android:layout_width="match_parent" android:theme="@style/AppTheme.AppBarOverlay">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:popupTheme="@style/AppTheme.PopupOverlay"
            app:layout_scrollFlags="scroll|enterAlways" />

        <android.support.design.widget.TabLayout
            android:id="@+id/tab_layout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="#eeeeee"
            app:tabTextColor="#888888"
            app:tabSelectedTextColor="#000000"
            app:tabGravity="fill"
            app:tabMode="fixed"/>

    </android.support.design.widget.AppBarLayout>


        <android.support.v4.view.ViewPager
            android:id="@+id/pager"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_behavior="@string/appbar_scrolling_view_behavior"/>


    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:layout_margin="@dimen/fab_margin"
        android:src="@android:drawable/ic_dialog_email" />

</android.support.design.widget.CoordinatorLayout>

 因为有 toolbar ,所以布局文件看上去有些复杂,但其实很简单。

简化后的布局(id 不一定对得上,其他地方 copy 过来的):

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/tabLayout"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:background="#cdc36e"
        app:tabMode="fixed"
        app:tabGravity="fill"/>

    <android.support.v4.view.ViewPager
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/viewPager"
        android:layout_below="@+id/tabLayout"
        android:layout_centerHorizontal="true" />
</RelativeLayout>

至于 fragment 文件可以参考上一篇文章中的布局 

fragmentTabHost 使用示例

或者直接查看源码所在地:

https://github.com/huanshen/Learn-Android/tree/master/TablayoutViewpager

posted @ 2017-11-19 22:20  huansky  阅读(1071)  评论(0编辑  收藏  举报