和原博文的区别:
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
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:id="@+id/title_bar"
android:layout_width="match_parent"
android:layout_height="48dp"
android:background="@color/bg_title_bar">
<TextView
android:id="@+id/title_bar_text"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:gravity="center"
android:text="xx"
android:textColor="@color/text_title_bar"
android:textSize="18sp" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_alignParentBottom="true"
android:background="@color/div_white" />
</RelativeLayout>
<RadioGroup
android:id="@+id/rg_tab_bar"
android:layout_width="match_parent"
android:layout_height="56dp"
android:layout_alignParentBottom="true"
android:background="@color/bg_white"
android:orientation="horizontal">
<RadioButton
android:id="@+id/rb_channel"
style="@style/tab_menu_item"
android:drawableTop="@drawable/tab_menu_channel"
android:text="@string/tab_menu_alert" />
<RadioButton
android:id="@+id/rb_message"
style="@style/tab_menu_item"
android:drawableTop="@drawable/tab_menu_message"
android:text="@string/tab_menu_profile" />
<RadioButton
android:id="@+id/rb_better"
style="@style/tab_menu_item"
android:drawableTop="@drawable/tab_menu_better"
android:text="@string/tab_menu_pay" />
<RadioButton
android:id="@+id/rb_setting"
style="@style/tab_menu_item"
android:drawableTop="@drawable/tab_menu_setting"
android:text="@string/tab_menu_setting" />
</RadioGroup>
<View
android:id="@+id/div_tab_bar"
android:layout_width="match_parent"
android:layout_height="2px"
android:layout_above="@id/rg_tab_bar"
android:background="@color/div_white" />
<android.support.v4.view.ViewPager
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@id/div_tab_bar"
android:layout_below="@id/title_bar" />
</RelativeLayout>
fg_content.xml(4个Fragment共用此布局文件)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/bg_white"
android:orientation="vertical">
<TextView
android:id="@+id/txt_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="XX"
android:textColor="@color/text_yellow"
android:textSize="20sp" />
</LinearLayout>
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截图,自然明了。
。