<RadioButton android:id="@+id/tab_rb_message" style="@style/navigation_bottom_radio" android:drawableTop="@drawable/tab_message_btn" android:text="消息" />
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@mipmap/tab_message_press" android:state_checked="true"/> <item android:drawable="@mipmap/tab_message_normal"/> </selector>
<style name="navigation_bottom_radio"> <!-- 内部组件的排列 --> <item name="android:gravity">center_horizontal</item> <!-- 背景样式 --> <item name="android:background">@android:color/transparent</item> <!-- 宽度 --> <item name="android:layout_width">wrap_content</item> <!-- 高度 --> <item name="android:layout_height">match_parent</item> <!-- 设置RadioButton的原来图片为空 --> <item name="android:button">@null</item> <!-- 与其他组件宽度占相同比重 --> <item name="android:layout_weight">1.0</item> <!-- 底部的空隙 --> <item name="android:paddingBottom">2.0dip</item> <!-- 顶部的空隙 --> <item name="android:paddingTop">2.0dip</item> <!-- 图片与文字的空隙 --> <item name="android:drawablePadding">1.0dip</item> <!-- 文字的大小 --> <item name="android:textSize">12sp</item> <!-- 文字的颜色 --> <item name="android:textColor">@color/tab_text_color_selector</item> </style>tab_text_color_selector.xml位于 res/color 文件夹下,其中tab_text_color就是菜单文字被选中的颜色
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_checked="true" android:color="@color/tab_text_color"/> <item android:state_checked="false" android:color="@android:color/black"/> <item android:color="@android:color/black"/> </selector>
虽然tabactivity已经在3.0后废弃了,但是依然不阻碍这种tab风格菜单的流行程度,代替它的则是使用了FragmentTabhost的FragmentActivity,子tab采用的是fragment,顺便在每一个tab菜单底部添加一个红线的位移动画效果,类似酷我音乐Android版顶部菜单效果,制作出来的gif图中底部红线位移动画有点卡顿,实际运行效果是很流畅的,效果图如下:
看起来很简单,但是考虑到viewpager本身有预加载的机制,所以最后在实际项目中还是去掉了viewpager滑动菜单这项功能
主要类的全部代码如下
package com.example.fragmenttabhostviewpager; import java.util.ArrayList; import java.util.List; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentPagerAdapter; import android.support.v4.app.FragmentTabHost; import android.support.v4.view.ViewPager; import android.support.v4.view.ViewPager.OnPageChangeListener; import android.util.DisplayMetrics; import android.view.animation.Animation; import android.view.animation.TranslateAnimation; import android.widget.LinearLayout; import android.widget.RadioButton; import android.widget.RadioGroup; import android.widget.RadioGroup.OnCheckedChangeListener; import android.widget.TabHost.OnTabChangeListener; import android.widget.TabHost.TabSpec; import android.widget.ImageView; public class MainActivity extends FragmentActivity { private RadioGroup rg; private RadioButton firstBtn; private RadioButton secondBtn; private RadioButton thirdBtn; private FragmentTabHost mFragmentTabhost; public static final String SHOW_OF_FIRST_TAG = "first"; public static final String SHOW_OF_SECOND_TAG = "second"; public static final String SHOW_OF_THIRD_TAG = "third"; private int SCREEN_WIDTH; private float currentX;// 当前X坐标 private float preX;// 前一操作的X坐标 private ImageView mRedlineIV; private List<Fragment> list = new ArrayList<Fragment>(); private ViewPager mViewPager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); DisplayMetrics metrics = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(metrics); SCREEN_WIDTH = metrics.widthPixels; setContentView(R.layout.activity_main); mFragmentTabhost = (FragmentTabHost) findViewById(android.R.id.tabhost); rg = (RadioGroup) findViewById(R.id.tab_rg_menu); firstBtn = (RadioButton) findViewById(R.id.tab_rb_1); secondBtn = (RadioButton) findViewById(R.id.tab_rb_2); thirdBtn = (RadioButton) findViewById(R.id.tab_rb_3); mViewPager = (ViewPager) findViewById(R.id.pager); mRedlineIV = (ImageView) findViewById(R.id.tab_menu_red_line); LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( SCREEN_WIDTH / 3, LinearLayout.LayoutParams.WRAP_CONTENT); mRedlineIV.setLayoutParams(params); mRedlineIV.setImageResource(R.drawable.ic_launcher); mFragmentTabhost.setup(this, getSupportFragmentManager(), R.id.pager); TabSpec tabSpec0 = mFragmentTabhost.newTabSpec(SHOW_OF_FIRST_TAG) .setIndicator("0"); TabSpec tabSpec1 = mFragmentTabhost.newTabSpec(SHOW_OF_SECOND_TAG) .setIndicator("1"); TabSpec tabSpec2 = mFragmentTabhost.newTabSpec(SHOW_OF_THIRD_TAG) .setIndicator("2"); mFragmentTabhost.addTab(tabSpec0, Fragment1.class, null); mFragmentTabhost.addTab(tabSpec1, Fragment2.class, null); mFragmentTabhost.addTab(tabSpec2, Fragment3.class, null); rg.setOnCheckedChangeListener(new OnCheckedChangeListener() { @Override public void onCheckedChanged(RadioGroup group, int checkedId) { // TODO Auto-generated method stub switch (checkedId) { case R.id.tab_rb_1: preX = currentX; currentX = 0; mFragmentTabhost.setCurrentTabByTag(SHOW_OF_FIRST_TAG); break; case R.id.tab_rb_2: preX = currentX; currentX = SCREEN_WIDTH * 1 / 3; mFragmentTabhost.setCurrentTabByTag(SHOW_OF_SECOND_TAG); break; case R.id.tab_rb_3: preX = currentX; currentX = SCREEN_WIDTH * 2 / 3; mFragmentTabhost.setCurrentTabByTag(SHOW_OF_THIRD_TAG); break; default: break; } Animation translateAnimation = new TranslateAnimation(preX, currentX, 0, 0); translateAnimation.setFillAfter(true); translateAnimation.setDuration(1000); mRedlineIV.setAnimation(translateAnimation); } }); mFragmentTabhost.setOnTabChangedListener(new OnTabChangeListener() { @Override public void onTabChanged(String tabId) { // TODO Auto-generated method stub int position = mFragmentTabhost.getCurrentTab(); mViewPager.setCurrentItem(position); } }); mFragmentTabhost.setCurrentTab(0); Fragment1 p1 = new Fragment1(); Fragment2 p2 = new Fragment2(); Fragment3 p3 = new Fragment3(); list.add(p1); list.add(p2); list.add(p3); mViewPager.setAdapter(new MenuAdapter(getSupportFragmentManager())); mViewPager.setOnPageChangeListener(new ViewPagerListener()); } class MenuAdapter extends FragmentPagerAdapter { public MenuAdapter(FragmentManager fm) { super(fm); // TODO Auto-generated constructor stub } @Override public Fragment getItem(int arg0) { return list.get(arg0); } @Override public int getCount() { return list.size(); } } class ViewPagerListener implements OnPageChangeListener { @Override public void onPageScrollStateChanged(int arg0) { } @Override public void onPageScrolled(int arg0, float arg1, int arg2) { } @Override public void onPageSelected(int index) { if (index == 0) { firstBtn.setChecked(true); } else if (index == 1) { secondBtn.setChecked(true); } else if (index == 2) { thirdBtn.setChecked(true); } mFragmentTabhost.setCurrentTab(index); } } }
DEMO1下载
单独用viewpager实现的底部menu效果和第一种是一样的,但是代码上却比第一种更优化了。
下面贴出主要类的代码:
package com.example.viewpagermenu; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentPagerAdapter; import android.support.v4.view.ViewPager; import android.support.v4.view.ViewPager.OnPageChangeListener; import android.util.DisplayMetrics; import android.util.Log; import android.view.animation.Animation; import android.view.animation.TranslateAnimation; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.RadioButton; import android.widget.RadioGroup; import android.widget.RadioGroup.OnCheckedChangeListener; public class MainActivity extends FragmentActivity { private RadioGroup mRadioGroup; private RadioButton mFirstBtn; private RadioButton mSecondBtn; private RadioButton mThirdBtn; private ImageView mRedlineIV; private ViewPager mViewPager; private Fragment mFragmentArray[] = { new Fragment1(), new Fragment2(), new Fragment3() }; private int SCREEN_WIDTH; private float mCurrentX;// 当前X坐标 private float mPreX;// 前一操作的X坐标 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); DisplayMetrics metrics = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(metrics); SCREEN_WIDTH = metrics.widthPixels; setContentView(R.layout.activity_main); Log.i("TAG", "0000"); mRadioGroup = (RadioGroup) findViewById(R.id.tab_rg_menu); mFirstBtn = (RadioButton) findViewById(R.id.tab_rb_1); mSecondBtn = (RadioButton) findViewById(R.id.tab_rb_2); mThirdBtn = (RadioButton) findViewById(R.id.tab_rb_3); mViewPager = (ViewPager) findViewById(R.id.pager); mRedlineIV = (ImageView) findViewById(R.id.tab_menu_red_line); LinearLayout.LayoutParams parmas = new LinearLayout.LayoutParams( SCREEN_WIDTH / 3, LinearLayout.LayoutParams.WRAP_CONTENT); mRedlineIV.setLayoutParams(parmas); mRadioGroup.setOnCheckedChangeListener(new OnCheckedChangeListener() { @Override public void onCheckedChanged(RadioGroup group, int checkedId) { // TODO Auto-generated method stub switch (checkedId) { case R.id.tab_rb_1: mPreX = mCurrentX; mCurrentX = 0; mViewPager.setCurrentItem(0); break; case R.id.tab_rb_2: mPreX = mCurrentX; mCurrentX = SCREEN_WIDTH * 1 / 3; mViewPager.setCurrentItem(1); break; case R.id.tab_rb_3: mPreX = mCurrentX; mCurrentX = SCREEN_WIDTH * 2 / 3; mViewPager.setCurrentItem(2); break; default: break; } Animation translateAnimation = new TranslateAnimation(mPreX, mCurrentX, 0, 0); translateAnimation.setFillAfter(true); translateAnimation.setDuration(400); mRedlineIV.setAnimation(translateAnimation); } }); mViewPager.setAdapter(new MenuAdapter(getSupportFragmentManager())); mViewPager.setOnPageChangeListener(new ViewPagerListener()); mViewPager.setCurrentItem(0); } class MenuAdapter extends FragmentPagerAdapter { public MenuAdapter(FragmentManager fm) { super(fm); // TODO Auto-generated constructor stub } @Override public Fragment getItem(int pos) { return mFragmentArray[pos]; } @Override public int getCount() { return mFragmentArray.length; } } class ViewPagerListener implements OnPageChangeListener { @Override public void onPageScrollStateChanged(int arg0) { } @Override public void onPageScrolled(int arg0, float arg1, int arg2) { } @Override public void onPageSelected(int index) { if (index == 0) { mFirstBtn.setChecked(true); } else if (index == 1) { mSecondBtn.setChecked(true); } else if (index == 2) { mThirdBtn.setChecked(true); } } } }DEMO2下载
核心思想就是利用fragment的setUserVisibleHint()和viewpager的setOffscreenPageLimit()这两个方法,首先写一个Fragment抽象基类即BaseFragment,重写它的setUserVisibleHint,详情可参见这里,关键代码如下:
@Override public void setUserVisibleHint(boolean isVisibleToUser) { // TODO Auto-generated method stub super.setUserVisibleHint(isVisibleToUser); if (getUserVisibleHint()) { isVisible = true; onLoad(); } else { isVisible = false; notLoad(); } } protected abstract void onLoad(); protected void notLoad() { }
mViewPage.setOffscreenPageLimit(1);经过简单测试,的确不会再预加载了,但是还有一个问题就是缓存的问题,如果添加了缓存,那每一页就都得有下拉刷新,或者要用广播通知UI的及时更新,待解决。
附其他实现tab菜单的方式:
1,静态fragment实现底部菜单tab;
2,Android仿QQ空间底部菜单;
3,fragment + fragmentTabHost实现底部菜单;
4,android viewpager+fragment仿微信底部菜单滑动效果