现在不少Android APP应用底部都会有一个底部导航栏。做法很简单,之前做法是 RadioGroup+RadioButton实现这一效果。但是这种做法必须要给每一个RadioButton设置一个id值,做出的效果也很棒。可是当某一天项目需求发生了改变,导航栏由起始的四个变成了五个。是不是又要在RadioGroup中嵌套一个RadioButton,设置id,然后。。。
在Java中强调的一点是低耦合,高内聚。在Android中也不例外。所以我感觉有必要写出一个通用的底部导航。在不通过id的状态下一样可以快速实现需求。
首先 xml布局 activity_main
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.ouxun.demo.basetabdemo.MainActivity">
<FrameLayout
android:id="@+id/main_flvessel"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<!--底部导航栏-->
<LinearLayout
android:id="@+id/main_tab_llvessel"
android:background="@color/colorGray"
android:layout_width="match_parent"
android:layout_height="60dp"
android:orientation="horizontal">
<LinearLayout
android:orientation="vertical"
android:gravity="center"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="30dp"
android:layout_height="30dp"
android:background="@drawable/home_selector"/>
<TextView
android:layout_marginBottom="3dp"
android:layout_marginTop="2dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="首页"
android:textColor="@color/color_main_tab"/>
</LinearLayout>
<LinearLayout
android:orientation="vertical"
android:gravity="center"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="30dp"
android:layout_height="30dp"
android:background="@drawable/home3_selector"/>
<TextView
android:layout_marginBottom="3dp"
android:layout_marginTop="2dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="商城"
android:textColor="@color/color_main_tab"/>
</LinearLayout>
<LinearLayout
android:orientation="vertical"
android:gravity="center"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="30dp"
android:layout_height="30dp"
android:background="@drawable/home2_selector"/>
<TextView
android:layout_marginBottom="3dp"
android:layout_marginTop="2dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="圈子"
android:textColor="@color/color_main_tab"/>
</LinearLayout>
<LinearLayout
android:orientation="vertical"
android:gravity="center"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="30dp"
android:layout_height="30dp"
android:background="@drawable/home4_selector"/>
<TextView
android:layout_marginBottom="3dp"
android:layout_marginTop="2dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="个人"
android:textColor="@color/color_main_tab"
/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
activity 代码
private void initView() {
// 初始化 底部父控件LinearLayout
tabBottomParent_ll = (LinearLayout) findViewById(R.id.main_tab_llvessel);
}
该方法在onCreate方法中调用,
其实就是初始化导航栏
LinearLayout父控件。导航栏肯定是要执行点击事件的,所以下步执行监听
private void initLinener() {
/*监听底部控件被点击事件,但是整体是被LinearLayout父控件所包裹,
1.获取该父控件所有的子控件的个数
2·遍历父控件,获取子控件,监听子控件点击事件
**/
int childCount = tabBottomParent_ll.getChildCount();
for (int i = 0; i <childCount ; i++) {
LinearLayout tabSonControl_ll = (LinearLayout) tabBottomParent_ll.getChildAt(i);
tabSonControl_ll.setOnClickListener(onClicklistener);
}
}
这个方法也是在onCreate方法中调用的,写到这里我们已经拿到每一个父控件
LinearLayout中的子孩子
tabSonControl_ll当然这个东西也是LinearLayout。
/**
* 监听取出子控件被点击事件。根据点击对应的view取出被点击的角标,判断是否要更改状态
* */
private View.OnClickListener onClicklistener = new View.OnClickListener() {
@Override
public void onClick(View v) {
int sonItem = tabBottomParent_ll.indexOfChild(v);
changUi(sonItem);
}
};
我们之所以要取出这个item是因为我们要判断点击的是不是当前这个item,从而改变控件状态
即:点击自身的时候,为不可用状态 enable = false。
反之 enable = true;
·
private void changUi(int item) {
int childCount = tabBottomParent_ll.getChildCount();
for (int i = 0; i <childCount ; i++) {
if (item == i) { //当前被点击的view 为不可用状态
tabBottomParent_ll.getChildAt(i).setEnabled(false);
setEnable(tabBottomParent_ll.getChildAt(i),false);
}else {
tabBottomParent_ll.getChildAt(i).setEnabled(true);
setEnable(tabBottomParent_ll.getChildAt(i),true);
}
}
}
现在我们回想一下我们一开始写的布局整个导航栏是被LinearLayout所包裹的,直接子孩子还是一个LinearLayout,我们之前的操作都是针对于这个LinearLayout的,所以我们通过setEnable方法去同步这组控件的状态
/**
* 因为这个子孩子是一个 LinearLayout,可以会包裹其他的控件,所以这个控件整体要同步其状态,递归
* 判断孙子是否是ViewGroup,
* */
private void setEnable(View childAt, boolean b) {
childAt.setEnabled(b); // 改变状态
if(childAt instanceof ViewGroup) {
int grandSonCount = ((ViewGroup) childAt).getChildCount();
for (int i = 0; i <grandSonCount ; i++) {
setEnable(((ViewGroup) childAt).getChildAt(i),b);
}
}
}
好了 一步步写下来,通用的导航栏就写好了 是不是棒棒哒。