版权声明:本文为HaiyuKing原创文章,转载请注明出处!
前言
自定义底部选项卡布局LinearLayout类,然后配合Fragment,实现切换Fragment功能。
缺点:
1、底部选项卡区域的高度值需要使用一个固定值,并且和使用的图片资源的高度相匹配。
比如,Demo中设置的底部选项卡的高度值为52dp,那么就需要使用drawable-xxhdpi目录下的72X72大小的图片资源。并且在图片资源中设计好内边距:
2、activity_main.xml布局文件中引用TabBottomLayout的时候,需要注意使用当前项目的TabBottomFragmentLayout的完整路径;
效果图
代码分析
TabBottomFragmentLayout:底部选项卡布局类——自定义的LinearLayout子类;实现了各个选项卡的布局、状态切换、点击事件的回调。
切换Fragment采用的是add-hide-show方式,而不是replace方式。所以fragment会在add的时候初始化一次,切换的时候不会重加载。
使用步骤
一、项目组织结构图
注意事项:
1、导入类文件后需要change包名以及重新import R文件路径
2、Values目录下的文件(strings.xml、dimens.xml、colors.xml等),如果项目中存在,则复制里面的内容,不要整个覆盖
二、导入步骤
将TabBottomFragmentLayout.java文件复制到项目中
package com.why.project.tabbottomfragmentlayoutdemo.views.tab;import android.content.Context;import android.graphics.drawable.Drawable;import android.support.v4.content.ContextCompat;import android.util.AttributeSet;import android.view.Gravity;import android.view.LayoutInflater;import android.view.View;import android.widget.CheckedTextView;import android.widget.LinearLayout;import com.why.project.tabbottomfragmentlayoutdemo.R;import java.util.ArrayList;import java.util.Arrays;import java.util.List;/** * @Create By HaiyuKing * @Used 底部选项卡布局类(注意:这个是tab_bottom_item的父布局) */public class TabBottomFragmentLayout extends LinearLayout{ private Context mContext; //选项卡的CheckedTextView控件的android:drawableTop属性的数组【是一系列selector选择器xml文件】,所以类型是int //底部选项卡对应的图标 private int[] bottomtab_IconIds = {R.drawable.home_tab_home_selector,R.drawable.home_tab_message_selector,R.drawable.home_tab_contact_selector}; //底部选项卡对应的文字 //CharSequence与String都能用于定义字符串,但CharSequence的值是可读可写序列,而String的值是只读序列。 private CharSequence[] bottomtab_Titles = {getResources().getString(R.string.home_function_home),getResources().getString(R.string.home_function_message),getResources().getString(R.string.home_function_contact)}; //选项卡的各个选项的view的集合:用于更改背景颜色 private Listbottomtab_Items = new ArrayList (); //选项卡的各个选项的CheckedTextView的集合:用于切换时改变图标和文字颜色 private List bottomTab_checkeds = new ArrayList (); public TabBottomFragmentLayout(Context context, AttributeSet attrs) { super(context, attrs); mContext = context; List tab_titleList = new ArrayList (); tab_titleList = Arrays.asList(bottomtab_Titles); //初始化view:创建多个view对象(引用tab_bottom_item文件),设置图片和文字,然后添加到这个自定义类的布局中 initAddBottomTabItemView(tab_titleList); } //初始化控件 private void initAddBottomTabItemView(List tabTitleList){ int countChild = this.getChildCount(); if(countChild > 0){ this.removeAllViewsInLayout();//清空控件 //将各个选项的view添加到集合中 bottomtab_Items.clear(); //将各个选项卡的各个选项的标题添加到集合中 bottomTab_checkeds.clear(); } //设置要添加的子布局view的参数 LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); params.weight = 1;//在tab_bottom_item文件的根节点RelativeLayout中是无法添加的,而这个是必须要写上的,否则只会展现一个view params.gravity = Gravity.CENTER; for(int index=0;index
后续可根据实际情况修改图标的selector文件、选项卡的文字内容:
//选项卡的CheckedTextView控件的android:drawableTop属性的数组【是一系列selector选择器xml文件】,所以类型是int //底部选项卡对应的图标 private int[] bottomtab_IconIds = { R.drawable.home_tab_home_selector,R.drawable.home_tab_message_selector,R.drawable.home_tab_contact_selector}; //底部选项卡对应的文字 //CharSequence与String都能用于定义字符串,但CharSequence的值是可读可写序列,而String的值是只读序列。 private CharSequence[] bottomtab_Titles = { getResources().getString(R.string.home_function_home),getResources().getString(R.string.home_function_message),getResources().getString(R.string.home_function_contact)};
将tab_bottom_item.xml文件复制到项目中
将图片资源和selector文件复制到项目中【后续可根据实际情况更换图片】
在colors.xml文件中添加以下代码:【后续可根据实际情况更改背景颜色、文字颜色值】
#3F51B5 #303F9F #FF4081 #00000000 #00000000 #8a8a8a #38ADFF
在dimens.xml文件中添加以下代码:【后续可根据实际情况更改底部选项卡区域的高度值、文字大小值】
16dp 16dp 52dp 14sp 16sp 18sp 20sp
在strings.xml文件中添加以下代码:【后续可根据实际情况更改底部选项卡的文字内容】
TabBottomFragmentLayoutDemo 首页 消息 我的
至此,TabBottomFragmentLayout类集成到项目中了。
三、使用方法
在Activity布局文件中引用TabBottomFragmentLayout布局类【注意:需要重新引用TabBottomFragmentLayout类的完整路径】
创建需要用到的fragment类和布局文件【后续可根据实际情况更改命名,并且需要重新import R文件】
MainFragment的布局文件:
在Activity中使用如下【继承FragmentActivity或者其子类】
package com.why.project.tabbottomfragmentlayoutdemo;import android.os.Bundle;import android.support.v4.app.FragmentActivity;import android.support.v4.app.FragmentManager;import android.support.v4.app.FragmentTransaction;import android.util.Log;import com.why.project.tabbottomfragmentlayoutdemo.fragment.HomeFragment;import com.why.project.tabbottomfragmentlayoutdemo.fragment.MessageFragment;import com.why.project.tabbottomfragmentlayoutdemo.fragment.ContactFragment;import com.why.project.tabbottomfragmentlayoutdemo.views.tab.TabBottomFragmentLayout;public class MainActivity extends FragmentActivity { private static final String TAG = "MainActivity"; //自定义底部选项卡 private TabBottomFragmentLayout mBottomTabLayout; private FragmentManager fragmentManager;//碎片管理器 /**碎片声明*/ private HomeFragment homeFragment;//首页 private MessageFragment messageFragment;//消息 private ContactFragment contactFragment;//我的 /**首页fragment索引值--需要和TabBottomLayout中的数组的下标值对应*/ public static final int Home_Fragment_Index = 0; /**消息fragment索引值*/ public static final int Message_Fragment_Index = 1; /**我的fragment索引值*/ public static final int Contact_Fragment_Index = 2; /**保存的选项卡的下标值*/ private int savdCheckedIndex = Home_Fragment_Index; /**当前的选项卡的下标值*/ private int mCurrentIndex = -1; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //初始化控件 initView(); //初始化数据 initData(); //初始化控件的点击事件 initEvent(); //初始化碎片管理器 fragmentManager = getSupportFragmentManager(); } @Override protected void onResume() { // TODO Auto-generated method stub super.onResume(); Log.w(TAG, "{onResume}"); //设置保存的或者初始的选项卡标红显示 SwitchTab(savdCheckedIndex); mCurrentIndex = -1;//解决按home键后长时间不用,再次打开显示空白的问题 //设置保存的或者初始的选项卡展现对应的fragment ShowFragment(savdCheckedIndex); } /** * 初始化控件 * */ private void initView(){ mBottomTabLayout = (TabBottomFragmentLayout) findViewById(R.id.bottomtab_Layout); } /**初始化数据*/ private void initData() { } /** * 初始化点击事件 * */ private void initEvent(){ //每一个选项卡的点击事件 mBottomTabLayout.setOnBottomTabSelectedListener(new TabBottomFragmentLayout.OnBottomTabSelectListener() { @Override public void onBottomTabSelected(int index) { ShowFragment(index);//独立出来,用于OnResume的时候初始化展现相应的Fragment } }); } /**控制切换选项卡*/ public void SwitchTab(int checkedIndex){ if(mBottomTabLayout != null){ mBottomTabLayout.setTabsDisplay(checkedIndex); } } /** * 显示选项卡对应的Fragment*/ public void ShowFragment(int checkedIndex){ if(mCurrentIndex == checkedIndex) { return; } //开启一个事务 FragmentTransaction transcation = fragmentManager.beginTransaction(); //隐藏全部碎片 hideFragments(transcation); switch (checkedIndex) { case Home_Fragment_Index: if(homeFragment == null){ homeFragment = HomeFragment.getInstance(HomeFragment.class,null); transcation.add(R.id.center_layout, homeFragment); }else{ transcation.show(homeFragment); } break; case Message_Fragment_Index: if(messageFragment == null){ messageFragment = MessageFragment.getInstance(MessageFragment.class,null); transcation.add(R.id.center_layout, messageFragment); }else{ transcation.show(messageFragment); } break; case Contact_Fragment_Index: if(contactFragment == null){ contactFragment = ContactFragment.getInstance(ContactFragment.class,null); transcation.add(R.id.center_layout, contactFragment); }else{ transcation.show(contactFragment); } break; default: break; } savdCheckedIndex = checkedIndex; mCurrentIndex = checkedIndex; transcation.commitAllowingStateLoss(); } /**隐藏全部碎片 * 需要注意:不要在OnResume方法中实例化碎片,因为先添加、显示,才可以隐藏。否则会出现碎片无法显示的问题*/ private void hideFragments(FragmentTransaction transaction) { if (null != homeFragment) { transaction.hide(homeFragment); } if (null != messageFragment) { transaction.hide(messageFragment); } if (null != contactFragment) { transaction.hide(contactFragment); } } /** * http://blog.csdn.net/caesardadi/article/details/20382815 * */ // 自己记录fragment的位置,防止activity被系统回收时,fragment错乱的问题【按home键返回到桌面一段时间,然后在进程里面重新打开,会发现RadioButton的图片选中状态在第二个,但是文字和背景颜色的选中状态在第一个】 //onSaveInstanceState()只适合用于保存一些临时性的状态,而onPause()适合用于数据的持久化保存。 protected void onSaveInstanceState(Bundle outState) { //http://www.cnblogs.com/chuanstone/p/4672096.html?utm_source=tuicool&utm_medium=referral //总是执行这句代码来调用父类去保存视图层的状态”。其实到这里大家也就明白了,就是因为这句话导致了重影的出现 //super.onSaveInstanceState(outState); outState.putInt("selectedCheckedIndex", savdCheckedIndex); outState.putInt("mCurrentIndex", mCurrentIndex); } @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { savdCheckedIndex = savedInstanceState.getInt("selectedCheckedIndex"); mCurrentIndex = savedInstanceState.getInt("mCurrentIndex"); super.onRestoreInstanceState(savedInstanceState); }}
混淆配置
无
参考资料
暂时空缺