不管什么APP,都会用到底部导航栏,一般实现方式有两种:
- 自定义组合控件
- RadioGroup+RadioButton
本文将通过自定义组合控件的方式手把手教大家撸一个简单实用的底部导航栏。
首先我们需要自定义一个NagivationTab。
public class NavigateTab extends LinearLayout {
private ImageView navTabIv = null;
private TextView navTabTv = null;
private int curPosition = 0;
public NavigateTab(Context context) {
super(context);
init(context, null);
}
public NavigateTab(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public NavigateTab(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.navigate_tab_layout, this);
navTabIv = (ImageView) view.findViewById(R.id.navigate_tab_iv);
navTabTv = (TextView) view.findViewById(R.id.navigate_tab_tv);
}
public void setCurPosition(int position){
curPosition = position;
}
public int getCurPosition() {
return curPosition;
}
public void setImageResource(int resId){
navTabIv.setImageResource(resId);
}
public void setText(String text){
navTabTv.setText(text);
}
public void setTextColor(int textColor){
navTabTv.setTextColor(textColor);
}
public void setTextSize(float textSize){
navTabTv.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
}
}
这里自定义的tab是继承一个线性布局,代码很简单,就不多解释了。
下面是tab引用的布局文件。
<merge xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:id="@+id/navigate_tab_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:id="@+id/navigate_tab_iv"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/navigate_tab_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dimen_size_2"
android:text="text" />
</LinearLayout>
</merge>
值得注意的是这里根布局使用的是merge标签,减少了布局嵌套。
接下来我们在自定义一个NagivationBar。
public class NavigateBar extends LinearLayout implements OnLimitClickListener {
// 导航栏tab个数
private int tabCount = 0;
// 默认状态下tab图片集合
private List<Integer> defaultImageList = null;
// 选中状态下tab图片集合
private List<Integer> focusImageList = null;
// tab文字集合
private List<String> tabTextList = null;
// 导航栏tab默认字体颜色
private int defaultTextColor = 0xFF555555;
// 导航栏tab选中字体颜色
private int focusTextColor = 0xFF000000;
// 字体大小
private float textSize = 14F;
private Context context = null;
private ArrayList<NavigateTab> tabList = null;
private OnNavigateListener listener = null;
public NavigateBar(Context context) {
super(context);
this.context = context;
init(context, null);
}
public NavigateBar(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
init(context, attrs);
}
public NavigateBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.context = context;
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
defaultImageList = new ArrayList<>();
focusImageList = new ArrayList<>();
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.NavigateBar);
tabCount = array.getInt(R.styleable.NavigateBar_tabCount, 0);
int defaultImageArrResId = array.getResourceId(R.styleable.NavigateBar_defaultImageArray, 0);
int focusImageArrResId = array.getResourceId(R.styleable.NavigateBar_focusImageArray, 0);
int textArrResId = array.getResourceId(R.styleable.NavigateBar_textArray, 0);
TypedArray defaultImageTypeArray = context.getResources().obtainTypedArray(defaultImageArrResId);
if (defaultImageTypeArray != null && defaultImageTypeArray.length() > 0) {
for (int i = 0; i < defaultImageTypeArray.length(); i++) {
defaultImageList.add(defaultImageTypeArray.getResourceId(i, 0));
}
}
TypedArray focusImageTypeArray = context.getResources().obtainTypedArray(focusImageArrResId);
if (focusImageTypeArray != null && focusImageTypeArray.length() > 0) {
for (int i = 0; i < focusImageTypeArray.length(); i++) {
focusImageList.add(focusImageTypeArray.getResourceId(i, 0));
}
}
String[] tabTextArray = context.getResources().getStringArray(textArrResId);
if (tabTextArray != null && tabTextArray.length > 0) {
tabTextList = Arrays.asList(tabTextArray);
}
defaultTextColor = array.getColor(R.styleable.NavigateBar_defaultTextColor, 0xFF555555);
focusTextColor = array.getColor(R.styleable.NavigateBar_focusTextColor, 0xFF000000);
textSize = array.getDimension(R.styleable.NavigateBar_textSize, 14F);
// 回收
array.recycle();
setOrientation(HORIZONTAL);
initTabs();
}
public void setOnNavigateListener(OnNavigateListener listener) {
this.listener = listener;
registerListener();
}
private void registerListener() {
if (tabList != null && tabList.size() > 0) {
for (NavigateTab tab : tabList) {
tab.setOnClickListener(new OnLimitClickHelper(this));
}
}
}
public void setFocusPosition(int position) {
for (int i = 0; i < tabList.size(); i++) {
if (i == position) {
tabList.get(i).setImageResource(focusImageList.get(i));
tabList.get(i).setTextColor(focusTextColor);
} else {
tabList.get(i).setImageResource(defaultImageList.get(i));
tabList.get(i).setTextColor(defaultTextColor);
}
}
}
private void initTabs() {
this.removeAllViews();
tabList = new ArrayList<>();
if (tabCount > 0) {
for (int i = 0; i < tabCount; i++) {
NavigateTab navigateTab = new NavigateTab(context);
navigateTab.setCurPosition(i);
navigateTab.setImageResource(defaultImageList.get(i));
navigateTab.setText(tabTextList.get(i));
navigateTab.setTextSize(textSize);
navigateTab.setTextColor(defaultTextColor);
LinearLayout.LayoutParams params = new LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT, 1.0F);
navigateTab.setLayoutParams(params);
tabList.add(navigateTab);
this.addView(navigateTab);
}
}
}
@Override
public void onClick(View view) {
if (listener != null) {
if (view instanceof NavigateTab) {
int position = ((NavigateTab) view).getCurPosition();
setFocusPosition(position);
listener.onClickNavigate(position);
}
}
}
public interface OnNavigateListener {
void onClickNavigate(int position);
}
}
大家可以看到,我们通过自定义的属性来配置nagivationTab个数、文字、焦点/默认 图片和文字颜色。
<declare-styleable name="NavigateBar">
<attr name="tabCount" format="integer" />
<attr name="defaultImageArray" format="reference" />
<attr name="focusImageArray" format="reference" />
<attr name="textArray" format="reference" />
<attr name="defaultTextColor" format="color" />
<attr name="focusTextColor" format="color" />
<attr name="textSize" format="dimension" />
</declare-styleable>
至此,我们自定义的底部导航栏已完成,是不是很简单😄😄😄。下面给大家看看activity和布局文件的使用。
Activity
public class NavTestActivity extends AppCompatActivity implements OnNavigateListener {
NavigateBar navigateBar;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test_nav);
navigateBar = findViewById(R.id.navigate_bar);
navigateBar.setOnNavigateListener(this);
navigateBar.setFocusPosition(0);
}
@Override
public void onClickNavigate(int position) {
Toast.makeText(this, "" + position, Toast.LENGTH_SHORT).show();
}
}
布局文件
<com.tbh.library.widgets.NavigateBar
android:id="@+id/navigate_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
app:defaultImageArray="@array/navigate_default_image"
app:focusImageArray="@array/navigate_focus_image"
app:textArray="@array/navigate_bar_text"
app:tabCount="4"
app:defaultTextColor="#000000"
app:focusTextColor="#0000FF"
app:textSize="14sp"/>
strings.XML
<string-array name="navigate_bar_text">
<item>首页</item>
<item>直播</item>
<item>关注</item>
<item>广场</item>
<item>我的</item>
</string-array>
<integer-array name="navigate_default_image">
<item>@drawable/home_default</item>
<item>@drawable/live_default</item>
<item>@drawable/attention_default</item>
<item>@drawable/square_default</item>
<item>@drawable/mine_default</item>
</integer-array>
<integer-array name="navigate_focus_image">
<item>@drawable/home_focus</item>
<item>@drawable/live_focus</item>
<item>@drawable/attention_focus</item>
<item>@drawable/square_focus</item>
<item>@drawable/mine_focus</item>
</integer-array>
最后附上效果图,第一次写技术文章,欢迎大家转载评论。