有空还得重新整理。。。
<RadioButton
android:id="@+id/tab_rb_message"
style="@style/navigation_bottom_radio"
android:drawableTop="@drawable/tab_message_btn"
android:text="消息"
/>
tab_message_btn,其中tab_message_press和tab_message_normal是两张图片
<?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>
二、FragmentTabhost+Viewpager:
虽然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);
}
}
}
三、Viewpager:
单独用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下载
四、取消viewpager预加载
核心思想就是利用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() {
}
然后所有fragment继承自BaseFragment,就必须实现onLoad方法,把耗时的网络操作都放在onLoad方法里,同时在有viewpager的FragmentActivity中设置如下
mViewPage.setOffscreenPageLimit(1);
经过简单测试,的确不会再预加载了,但是还有一个问题就是缓存的问题,如果添加了缓存,那每一页就都得有下拉刷新,或者要用广播通知UI的及时更新,待解决。
五、tab缓存数据,就像fragment的hide和show一样,当使用FragmentTabhost + RadioButton实现的tab菜单时,只有重写FragmentTabhost才能达到想要的效果,网上已经有人写过了,直接拿来用就好,让多个Fragment 切换时不重新实例化,详见Android重写FragmentTabHost来实现状态保存
附其他实现tab菜单的方式: