仿 QQ 底部 tab 导航
Posted changhaiSmile
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了仿 QQ 底部 tab 导航相关的知识,希望对你有一定的参考价值。
仿 QQ 底部 tab 导航
原文链接: http://www.jianshu.com/p/826d730bd841 本篇博客主要实现以下效果: 使用 FragmentTabHost 实现 qq 底部 Tab 切换 使用 RadioGroup 和 RadioButton 实现仿 qq 底部切换 使用 RadioGroup 和 ViewPager 实现可以滑动切换的仿 qq 底部 Tab 切换 解决 Fragment 多次实例化的几种方案 Fragemnt 的懒加载(网上很多人称之为 Fragemnt 的最优加载) —— 由 迪鲁宾 分享本篇博客主要实现以下效果:
- 使用FragmentTabHost实现qq底部Tab切换
- 使用RadioGroup和RadioButton实现仿qq底部切换
- 使用RadioGroup和ViewPager 实现可以滑动切换的仿qq底部Tab切换
- 解决Fragment多次实例化的几种方案
- Fragemnt的懒加载(网上很多人称之为Fragemnt的最优加载)
效果图
老规矩,废话 不多说,先看效果图
FragmentTabHost实现qq底部Tab实践的效果图
RadioGroup和ViewPager 实现可以滑动切换的仿qq底部Tab效果图
使用FragmentTabHost实现qq底部Tab切换
第一步先看布局文件
<?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:orientation="vertical">
<!--用来填充Fragemnt的FrayLayout-->
<FrameLayout
android:id="@+id/main_layout_content"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
</FrameLayout>
<!--FragmentTabHost-->
<android.support.v4.app.FragmentTabHost
android:id="@android:id/tabhost"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#F6F6F6"
android:paddingBottom="5dp"
android:paddingTop="5dp">
<FrameLayout
android:id="@android:id/tabcontent"
android:layout_width="0dp"
android:layout_height="0dp"/>
</android.support.v4.app.FragmentTabHost>
</LinearLayout>
其实很简单,没什么好说的 ,就是一个vertical的LinearLayout中放置着一个FrameLayout和FragmentTabHost
接下来我们来看一下代码
public class FirstStyleActivity extends AppCompatActivity
FragmentTabHost mTabHost;
private TabWidget mTabWidget;
private List<FragmentInfo> mFragmentEntities;
private static final String TAG = "xujun";
private static final String tag = "tag";
public static final String[] mTiltles = new String[]
"首页", "课程", "直播", "个人"
;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_first_style);
mTabHost = (FragmentTabHost) findViewById(android.R.id.tabhost);
mTabHost.setup(this, getSupportFragmentManager(), R.id.main_layout_content);
mTabWidget = mTabHost.getTabWidget();
// 去掉分割线
mTabWidget.setDividerDrawable(null);
mFragmentEntities = MainFragmentFactory.getInstance().getList();
initListener();
initData();
private void initData()
int size = mFragmentEntities.size();
for (int i = 0; i < size; i++)
Log.i(TAG, "size:=" + size);
FragmentInfo fragmentInfo = mFragmentEntities.get(i);
String title = fragmentInfo.getTitle();
TabHost.TabSpec tabSpec = mTabHost.newTabSpec(title).setIndicator(getTabView
(i));
Bundle bundle = new Bundle();
bundle.putString(tag, mTiltles[i]);
mTabHost.addTab(tabSpec, fragmentInfo.getClz(), bundle);
updateTab(0);
private void initListener()
mTabHost.setOnTabChangedListener(new TabHost.OnTabChangeListener()
@Override
public void onTabChanged(String tabId)
int currentTab = mTabHost.getCurrentTab();
Log.i(TAG, "onTabChanged:currentTab:=" + currentTab);
updateTab(currentTab);
);
private View getTabView(int i)
View view = View.inflate(this, R.layout.tab_layout, null);
int currentTab = mTabHost.getCurrentTab();
Log.i(TAG, "currentTab:=" + currentTab);
setSingleView(view, currentTab, i);
return view;
private void setSingleView(View view, int currentTab, int index)
FragmentInfo fragmentInfo = mFragmentEntities.get(index);
int[] imagIds = fragmentInfo.getImagIds();
int[] colors = fragmentInfo.getColors();
TextView tv = (TextView) view.findViewById(R.id.tab_tv);
ImageView iv = (ImageView) view.findViewById(R.id.tab_icon);
tv.setText(fragmentInfo.getTitle());
Resources resources = getResources();
if (index == currentTab)
tv.setTextColor(resources.getColor(colors[1]));
iv.setImageDrawable(resources.getDrawable(imagIds[1]));
else
tv.setTextColor(getResources().getColor(colors[0]));
iv.setImageDrawable(resources.getDrawable(imagIds[0]));
private void updateTab(int currentTab)
int childCount = mTabWidget.getChildCount();
for (int i = 0; i < childCount; i++)
View view = mTabWidget.getChildTabViewAt(i);
setSingleView(view, currentTab, i);
其实说起来也很简单,主要分为以下步骤
- 第一步,实例化FragmentTabHost并设置相关样式
mTabHost = (FragmentTabHost) findViewById(android.R.id.tabhost);
mTabHost.setup(this, getSupportFragmentManager(), R.id.main_layout_content);
mTabWidget = mTabHost.getTabWidget();
// 去掉分割线
mTabWidget.setDividerDrawable(null);
for (int i = 0; i < size; i++)
Log.i(TAG, "size:=" + size);
FragmentInfo fragmentInfo = mFragmentEntities.get(i);
String title = fragmentInfo.getTitle();
TabHost.TabSpec tabSpec = mTabHost.newTabSpec(title).setIndicator(getTabView
(i));
Bundle bundle = new Bundle();
bundle.putString(tag, mTiltles[i]);
mTabHost.addTab(tabSpec, fragmentInfo.getClz(), bundle);
- 第三步,通过设置 监听器来实现底部tab颜色和图案样式的转换
mTabHost.setOnTabChangedListener(new TabHost.OnTabChangeListener()
@Override
public void onTabChanged(String tabId)
int currentTab = mTabHost.getCurrentTab();
Log.i(TAG, "onTabChanged:currentTab:=" + currentTab);
updateTab(currentTab);
);
运行上述代码及可以看到如下效果图
使用RadioGroup和RadioButton实现仿qq底部切换
第一步 ,先看布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:id="@+id/activity_second_style"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<!--用来填充Fragemnt的FrayLayout-->
<FrameLayout
android:id="@+id/fl"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
</FrameLayout>
<!--使用RadioGroup来实现tab的切换-->
<RadioGroup
android:id="@+id/rg"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<RadioButton
android:id="@+id/rb_home"
style="@style/bottom_tab"
android:drawableTop="@drawable/sel_home"
android:text="首页"/>
<RadioButton
android:id="@+id/rb_course"
style="@style/bottom_tab"
android:drawableTop="@drawable/sel_course"
android:text="课程"/>
<RadioButton
android:id="@+id/rb_direct_seeding"
style="@style/bottom_tab"
android:drawableTop="@drawable/sel_direct_seeding"
android:text="直播"/>
<RadioButton
android:id="@+id/rb_me"
style="@style/bottom_tab"
android:drawableTop="@drawable/sel_me"
android:text="我的"/>
</RadioGroup>
</LinearLayout>
其实每一个tab的选中时利用RadioGroup中RadioButton的互相排斥的特性,即每一次只能选中一个 RadioButton
至于bottom_tab的style,只不过是将相同的arr提取出来,减少布局的代码量和方便统一修改而已,平时我们在写布局代码 的时候也可以这样
<style name="bottom_tab">
<item name="android:layout_width" >0dp</item>
<item name="android:layout_height" >wrap_content</item>
<item name="android:layout_weight" >1</item>
<item name="android:text" >0dp</item>
<item name="android:gravity" >center</item>
<item name="android:textColor" >@drawable/sel_bottom_tab_text</item>
<item name="android:padding" >8dp</item>
<item name="android:button" >@null</item>
</style>
第二步,我们来看一下Activity的 代码
public class ThreeActivity extends AppCompatActivity
FrameLayout mFl;
RadioGroup mRg;
private FragmentManager mFragmentManager;
private int position = 0;
public static final String[] mTiltles = new String[]
"首页", "课程", "直播", "个人"
;
private List<Fragment> mFragments;
private Fragment mCurFragment;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_three);
mFl = (FrameLayout) findViewById(R.id.fl);
mRg = (RadioGroup) findViewById(R.id.rg);
mFragments = new ArrayList<>();
for (int i = 0; i < mTiltles.length; i++)
ItemFragement itemFragement = ItemFragement.newInstance(mTiltles[i]);
mFragments.add(itemFragement);
mCurFragment = mFragments.get(position);
replaceFragment(mCurFragment);
((RadioButton)mRg.getChildAt(position)).setChecked(true);
initListener();
private void initListener()
mRg.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener()
@Override
public void onCheckedChanged(RadioGroup group, int checkedId)
RadioButton radioButton = (RadioButton) group.findViewById(checkedId);
if (false == radioButton.isChecked())
return;
switch (checkedId)
case R.id.rb_home:
position = 0;
break;
case R.id.rb_course:
position = 1;
break;
case R.id.rb_direct_seeding:
position = 2;
break;
case R.id.rb_me:
position = 3;
break;
default:
position = 0;
break;
LUtils.i("position==" + position);
Fragment to = mFragments.get(position);
showFragment(mCurFragment, to);
mCurFragment = to;
);
private void showFragment(Fragment from, Fragment to)
FragmentManager supportFragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = supportFragmentManager.beginTransaction();
if (!to.isAdded()) // 先判断是否被add过
transaction.hide(from).add(R.id.fl, to).commit(); // 隐藏当前的fragment,add下一个到Activity中
else
transaction.hide(from).show(to).commit(); // 隐藏当前的fragment,显示下一个
/**
* 这个方法用老替换fragment
* xujun
* 2016/5/3 17:28.
*/
private void replaceFragment(Fragment fragmeny)
FragmentManager supportFragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = supportFragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fl, fragmeny).commit();
思路解析
- 实例化各个控件,这里代码就不贴出来了
- 初始化 Fragemnt 和选中各个tab
mFragments = new ArrayList<>();
for (int i = 0; i < mTiltles.length; i++)
ItemFragement itemFragement = ItemFragement.newInstance(mTiltles[i]);
mFragments.add(itemFragement);
mCurFragment = mFragments.get(position);
replaceFragment(mCurFragment);
((RadioButton)mRg.getChildAt(position)).setChecked(true);
private void replaceFragment(Fragment fragmeny)
FragmentManager supportFragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = supportFragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fl, fragmeny).commit();
- 第三步,通过监听RadioGroup的 OnCheckedChangeListener事件,来实现tab和Fragemnt的切换
mRg.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener()
@Override
public void onCheckedChanged(RadioGroup group, int checkedId)
RadioButton radioButton = (RadioButton) group.findViewById(checkedId);
if (false == radioButton.isChecked())
return;
switch (checkedId)
case R.id.rb_home:
position = 0;
break;
case R.id.rb_course:
position = 1;
break;
case R.id.rb_direct_seeding:
position = 2;
break;
case R.id.rb_me:
position = 3;
break;
default:
position = 0;
break;
LUtils.i("position==" + position);
Fragment to = mFragments.get(position);
showFragment(mCurFragment, to);
mCurFragment = to;
);
使用RadioGroup和ViewPager 实现可以滑动切换的仿qq底部Tab切换
第一步,我们 同样先看布局代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:id="@+id/activity_second_style"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<!--用来填充Fragemnt的ViewPager-->
<android.support.v4.view.ViewPager
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
</android.support.v4.view.ViewPager>
<!--使用RadioGroup来实现tab的切换-->
<RadioGroup
android:id="@+id/rg"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<RadioButton
android:id="@+id/rb_home"
style="@style/bottom_tab"
android:drawableTop="@drawable/sel_home"
android:text="首页"/>
<RadioButton
android:id="@+id/rb_course"
style="@style/bottom_tab"
android:drawableTop="@drawable/sel_course"
android:text="课程"/>
<RadioButton
android:id="@+id/rb_direct_seeding"
style="@style/bottom_tab"
android:drawableTop="@drawable/sel_direct_seeding"
android:text="直播"/>
<RadioButton
android:id="@+id/rb_me"
style="@style/bottom_tab"
android:drawableTop="@drawable/sel_me"
android:text="我的"/>
</RadioGroup>
</LinearLayout>
第二步,我们一起来看一下Activity代码
public class SecondStyleActivity extends AppCompatActivity
public static final String[] mTiltles = new String[]
"首页", "课程", "直播", "个人"
;
private List<Fragment> mFragments;
ViewPager mViewPager;
RadioGroup mRg;
private int position = 0;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second_style);
mViewPager = (ViewPager) findViewById(R.id.viewPager);
mRg = (RadioGroup) findViewById(R.id.rg);
ini以上是关于仿 QQ 底部 tab 导航的主要内容,如果未能解决你的问题,请参考以下文章
Android仿小米商城底部导航栏之二(BottomNavigationBarViewPager和Fragment的联动使用)