ViewPager+Fragment实现底部导航栏(左右滑动/点击切换)

您所在的位置:网站首页 苹果手机怎么样截屏可以上下滑动 ViewPager+Fragment实现底部导航栏(左右滑动/点击切换)

ViewPager+Fragment实现底部导航栏(左右滑动/点击切换)

2024-07-12 01:12| 来源: 网络整理| 查看: 265

声明: 本博文主要参考和借鉴了5.2.4 Fragment实例精讲——底部导航栏+ViewPager滑动切换页面。

和原博文的区别:

1.针对Demo中的 代码进行了部分优化 2.针对原博文中的”ViewPager的缓存机制“部分,通过log日志形式进行详细说明 3.针对原博文中下列几种ViewPager左右切换过程中的常量值的错误说明进行更正!

ViewPager.SCROLL_STATE_IDLE ViewPager.SCROLL_STATE_DRAGGING ViewPager.SCROLL_STATE_SETTING

Demo效果图: 这里写图片描述

项目结构: 这里写图片描述

代码实现: Step 1:相关布局文件layout (1).activity.xml

 

fg_content.xml(4个Fragment共用此布局文件)

  Step 2:4个基本相同的Fragment

public class MyFragment1 extends Fragment { private static final String TAG = "MyFragment1"; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fg_content, container, false); TextView txt_content = (TextView) view.findViewById(R.id.txt_content); txt_content.setText("第一个Fragment"); Log.i(TAG, "onCreateView: 0000--------MyFragment1"); return view; } @Override public void onDestroyView() { super.onDestroyView(); Log.i(TAG, "onDestroyView: 0000-------MyFragment1"); } @Override public void onDestroy() { super.onDestroy(); Log.i(TAG, "onDestroy: 0000--------MyFragment1"); } public MyFragment1() { } }

  Step 3:主程序MainActivity

public class MainActivity extends AppCompatActivity implements RadioGroup.OnCheckedChangeListener, ViewPager.OnPageChangeListener { private static final String TAG = "MainActivity"; public static final int PAGE_ONE = 0; public static final int PAGE_TWO = 1; public static final int PAGE_THREE = 2; public static final int PAGE_FOUR = 3; private TextView titleBarText; private RadioGroup rgTabBar; private RadioButton rbChannel; private RadioButton rbMessage; private RadioButton rbBetter; private RadioButton rbSetting; private ViewPager viewpager; private MyFragmentPagerAdapter mAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mAdapter = new MyFragmentPagerAdapter(getSupportFragmentManager()); initViews(); } private void initViews() { titleBarText = (TextView) findViewById(R.id.title_bar_text); rgTabBar = (RadioGroup) findViewById(R.id.rg_tab_bar); rbChannel = (RadioButton) findViewById(R.id.rb_channel); rbMessage = (RadioButton) findViewById(R.id.rb_message); rbBetter = (RadioButton) findViewById(R.id.rb_better); rbSetting = (RadioButton) findViewById(R.id.rb_setting); viewpager = (ViewPager) findViewById(R.id.viewpager); rgTabBar.setOnCheckedChangeListener(this); viewpager.setAdapter(mAdapter); viewpager.setCurrentItem(0); viewpager.addOnPageChangeListener(this); rbChannel.setChecked(true); } @Override public void onCheckedChanged(RadioGroup group, int checkedId) { switch (checkedId) { case R.id.rb_channel: viewpager.setCurrentItem(PAGE_ONE); titleBarText.setText("提醒"); break; case R.id.rb_message: viewpager.setCurrentItem(PAGE_TWO); titleBarText.setText("信息"); break; case R.id.rb_better: viewpager.setCurrentItem(PAGE_THREE); titleBarText.setText("我的"); break; case R.id.rb_setting: viewpager.setCurrentItem(PAGE_FOUR); titleBarText.setText("设置"); break; } } @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { } @Override public void onPageScrollStateChanged(int state) { /** * 原博文中注释(state的状态有三个,0表示什么都没做,1正在滑动,2滑动完毕)有误 * 特此更正为如下: * *SCROLL_STATE_IDLE : 值为0,表示当前页已经选定。 *SCROLL_STATE_DRAGGING: 值为1,表示当前页面正在拖动。 *SCROLL_STATE_SETTING: 值为2,表示当前页面正在拖动中,还没有到选定状态。 */ Log.i(TAG, "onPageScrollStateChanged: state::" + state); if (state == 2) { int currentItemPosition = viewpager.getCurrentItem(); Log.w(TAG, "onPageScrollStateChanged: currentItemPosition::" + currentItemPosition); switch (currentItemPosition) { case PAGE_ONE: rbChannel.setChecked(true); titleBarText.setText("提醒"); break; case PAGE_TWO: rbMessage.setChecked(true); titleBarText.setText("信息"); break; case PAGE_THREE: rbBetter.setChecked(true); titleBarText.setText("我的"); break; case PAGE_FOUR: rbSetting.setChecked(true); titleBarText.setText("设置"); break; } } } }

上述MainActivity中的代码中,ViewPager的onPageScrollStateChanged(int state)中必须加上

if (state == 2) { … } 的判断,虽然不加也能得到正确的结果,但是通过log你会发现if判断中的逻辑会调用很多次,因为当你刚开始拖动**(SCROLL_STATE_DRAGGING: 值为1,表示当前页面正在拖动。),以及拖动过程结束手刚离开屏幕(SCROLL_STATE_SETTING: 值为2,表示当前页面正在拖动中,还没有到选定状态。)**,再到选定到当前的fragment界面(**SCROLL_STATE_IDLE : 值为0,表示当前页已经选定。)**都会调用…这样会很浪费系统性能。 执行顺序是: 1:如果state==1,则手刚开始滑动,底边导航栏就会进行切换 2:正常 0:如果state-==0,则页面停留,不再变化之后,底边导航栏才会进行切换,滞后感十分明显 针对ViewPager中的三个常量值,代码注释中已经详细说明了,在此不在赘述。

  Step 4:ViewPager适配器(自定义FragmentPagerAdapter类) 代码很简单,只需传递一个FragmentManager过来,其他都在这里完成!

public class MyFragmentPagerAdapter extends FragmentPagerAdapter { private final int PAGER_COUNT = 4; private MyFragment1 myFragment1; private MyFragment2 myFragment2; private MyFragment3 myFragment3; private MyFragment4 myFragment4; public MyFragmentPagerAdapter(FragmentManager fm) { super(fm); myFragment1 = new MyFragment1(); myFragment2 = new MyFragment2(); myFragment3 = new MyFragment3(); myFragment4 = new MyFragment4(); } @Override public int getCount() { return PAGER_COUNT; } @Override public Object instantiateItem(ViewGroup vg, int position) { return super.instantiateItem(vg, position); } @Override public void destroyItem(ViewGroup container, int position, Object object) { System.out.println("position Destory" + position); super.destroyItem(container, position, object); } @Override public Fragment getItem(int position) { Fragment fragment = null; switch (position) { case MainActivity.PAGE_ONE: fragment = myFragment1; break; case MainActivity.PAGE_TWO: fragment = myFragment2; break; case MainActivity.PAGE_THREE: fragment = myFragment3; break; case MainActivity.PAGE_FOUR: fragment = myFragment4; break; } return fragment; } }

使用PagerAdapter要重写相关方法:

getCount( ):获得viewpager中有多少个view

destroyItem( ):移除一个给定位置的页面。适配器有责任从容器中删除这个视图。这是为了确保 在finishUpdate(viewGroup)返回时视图能够被移除。

instantiateItem( ):①将给定位置的view添加到ViewGroup(容器)中,创建并显示出来 ②返回一个代表新增页面的Object(key),通常都是直接返回view本身就可以了, 当然你也可以自定义自己的key,但是key和每个view要一一对应的关系

isViewFromObject( ):判断instantiateItem(ViewGroup, int)函数所返回来的Key与一个页面视图是否是 代表的同一个视图(即它俩是否是对应的,对应的表示同一个View),通常我们直接写 return view == object;就可以了,至于为什么要这样讲起来比较复杂,后面有机会进行了解吧 貌似是ViewPager中有个存储view状态信息的ArrayList,根据View取出对应信息的吧!

至此,ViewPager+Fragment实现底部导航栏完成。 下面针对ViewPager的缓存机制做下说明: 直接引用原博文说明。

一个页面切换的组件,我们可以往里面填充多个View,然后我们可以通过触摸屏幕左右滑动 切换不同的View,和前面学习的ListView一样,我们需要一个Adapter(适配器),将要显示的View和 我们的ViewPager进行绑定,而ViewPager有他自己特定的Adapter——PagerAdapter!另外,Google 官方是建议我们使用Fragment来填充ViewPager的,这样可以更加方便的生成每个Page以及管理 每个Page的生命周期!当然它给我们提供了两个不同的Adapter,他们分别是:FragmentPageAdapter和FragmentStatePagerAdapter! 而我们本节用到的则是前者:FragmentPageAdapter! 另外要说一点的是ViewPager的缓存机制ViewPager会缓存当前页,前一页,以及后一页,比如有1,2,3,4这四个页面: 当我们 ——>处于第一页:缓存1,2 ——> 处于第二页:缓存 1,2,3 ——> 处于第三页:缓存2,3,4 ——> 处于第四页缓存3,4这样!

详情见log截图,自然明了。 ViewPager缓存机制 至此,完结,如有疑问请留言告知。 后续会出一篇关于FragmentPageAdapter和FragmentStatePagerAdapter的区别的文章。

附上demo链接(本来不想加积分的,但是csdn上传资源时,好像最小1积分,请谅解)。 https://download.csdn.net/download/zhangqunshuai/10459362。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3