本文主要实现底部Tab的动态添加,动态添加图片、文字状态选择器,支持tab的本和和网络图片,支持各自Tab各自控制,支持Tab的隐藏和显示,非常灵活。实现原理是自定义RadioGroup+RadioButton,效果图如下:
关于小红点和角标实现参考上一篇文章介绍:
https://blog.youkuaiyun.com/yoonerloop/article/details/107589057
要实现单选效果RadioGroup包含的子View只能是RadioButton,不能为LinearLayout,为LinearLayout则单选效果和一系列的监听就失效了,要实现子View为LinearLayout的单选只能重写LinearLayout了,可以参考:https://www.cnblogs.com/over140/p/3795877.html,这里直接使用RadioButton实现。
一、xml定义
<?xml version="1.0" encoding="utf-8"?>
<com.tencent.weapps.view.AppRadioButton xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/ab_btn"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:button="@null"
android:singleLine="true"
android:ellipsize="end"
android:gravity="center"
android:paddingTop="15dp"
android:background="@android:color/transparent"
android:textColor="@color/selector_tab_text"
android:textSize="11sp" />
二、MyRadioGroup继承自RadioGroup动态添加
private void initView() {
if (list == null || list.isEmpty()) {
setVisibility(GONE);
return;
}
removeAllViews();
setOrientation(HORIZONTAL);
setVisibility(VISIBLE);
//添加RadioButton
for (int i = 0; i < list.size(); i++) {
AppRadioButton radioButton = (AppRadioButton) LayoutInflater.from(getContext()).inflate(R.layout.item_tab, null);
radioButton.setId(i);
addView(radioButton);
}
//设置RadioButton属性
for (int i = 0; i < getChildCount(); i++) {
AppRadioButton radioButton = (AppRadioButton) getChildAt(i);
LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) radioButton.getLayoutParams();
layoutParams.weight = 1;
layoutParams.width = 0;
layoutParams.gravity = Gravity.CENTER;
radioButton.setLayoutParams(layoutParams);
if (i == 0 && !radioButton.isChecked()) {
radioButton.setChecked(true);
} else {
radioButton.setChecked(false);
}
if (!TextUtils.isEmpty(color) && !TextUtils.isEmpty(selectedColor)) {
radioButton.setTextColor(getCheckedColorStateList(selectedColor, color));
}
}
if (!TextUtils.isEmpty(backgroundColor)) {
setBackgroundColor(Color.parseColor(backgroundColor));
}
}
//设置背景颜色的状态选择器
public static ColorStateList getCheckedColorStateList(@NonNull String checkedColor,
@NonNull String unCheckedColor) {
int[][] states = new int[][]{
new int[]{-android.R.attr.state_checked}, // unchecked
new int[]{android.R.attr.state_checked} // checked
};
int[] colors = new int[]{
Color.parseColor(checkedColor),
Color.parseColor(unCheckedColor)
};
return new ColorStateList(states, colors);
}
注意这里不能偷懒,把添加RadioButton和设置属性放在一块去了,否则无法控制文字和icon之间的间距,绘制过程出现问题,要分开进行。
三、设置icon和文字
private void setData() {
if (list == null || list.isEmpty()) {
setVisibility(GONE);
return;
}
for (int i = 0; i < getChildCount(); i++) {
TabBean bean = list.get(i);
AppRadioButton radioButton = (AppRadioButton) getChildAt(i);
setRadioButton(radioButton, bean);
}
}
private void setRadioButton(AppRadioButton radioButton, TabBean bean) {
ViewUtils.setText(radioButton, bean.text);
if (TextUtils.isEmpty(bean.iconPath)) {
radioButton.setTextSize(16);
return;
} else {
radioButton.setTextSize(11);
}
radioButton.setCompoundDrawablePadding(drawablePadding);
StateListDrawable stateListDrawable = new StateListDrawable();
if (!bean.iconPath.startsWith("http") && !bean.selectedIconPath.startsWith("http")) {
try {
InputStream open = getResources().getAssets().open(bean.iconPath);
InputStream selectOpen = getResources().getAssets().open(bean.selectedIconPath);
Drawable drawable = Drawable.createFromStream(open, null);
Drawable selectDrawable = Drawable.createFromStream(selectOpen, null);
stateListDrawable.addState(new int[]{-android.R.attr.state_checked}, drawable);
stateListDrawable.addState(new int[]{android.R.attr.state_checked}, selectDrawable);
stateListDrawable.setBounds(0, 0, drawableSize, drawableSize);
radioButton.setCompoundDrawables(null, stateListDrawable, null, null);
} catch (IOException e) {
e.printStackTrace();
}
return;
}
Glide.with(getContext()).load(bean.iconPath).error(R.drawable.shape_circle_tab_default).into(new SimpleTarget<Drawable>() {
@Override
public void onResourceReady(@NonNull Drawable resource, @Nullable Transition<? super Drawable> transition) {
if (resource == null) {
return;
}
stateListDrawable.addState(new int[]{-android.R.attr.state_checked}, resource);
Glide.with(getContext()).load(bean.selectedIconPath).into(new SimpleTarget<Drawable>() {
@Override
public void onResourceReady(@NonNull Drawable selectResource, @Nullable Transition<? super Drawable> transition) {
if (selectResource == null) {
return;
}
stateListDrawable.addState(new int[]{android.R.attr.state_checked}, selectResource);
stateListDrawable.setBounds(0, 0, drawableSize, drawableSize);
radioButton.setCompoundDrawables(null, stateListDrawable, null, null);
}
@Override
public void onLoadFailed(@Nullable Drawable errorDrawable) {
super.onLoadFailed(errorDrawable);
resource.setBounds(0, 0, drawableSize, drawableSize);
radioButton.setCompoundDrawables(null, resource, null, null);
}
});
}
@Override
public void onLoadFailed(@Nullable Drawable errorDrawable) {
super.onLoadFailed(errorDrawable);
Log.d("TAG",iconPath加载失败:"+ bean.selectedIconPath);
}
});
}
四、更新RadioGroup属性
public void upRadioButton(TabBean bean, int index) {
if (getChildCount() == 0 || bean == null) {
return;
}
for (int i = 0; i < getChildCount(); i++) {
if (index == i) {
AppRadioButton radioButton = (AppRadioButton) getChildAt(i);
setRadioButton(radioButton, bean);
}
}
}
五、更新右上角角标
/**
* 更新小红点
* @param index
* @param isShow
*/
public void showRedPoint(int index, boolean isShow) {
for (int i = 0; i < getChildCount(); i++) {
if (index == i) {
AppRadioButton radioButton = (AppRadioButton) getChildAt(i);
radioButton.setShowSmallDot(isShow);
}
}
}
/**
* 更新文字
* @param index
* @param text
* @param isShow
*/
public void showRedText(int index, String text, boolean isShow) {
for (int i = 0; i < getChildCount(); i++) {
if (index == i) {
AppRadioButton radioButton = (AppRadioButton) getChildAt(i);
radioButton.setNumberDot(isShow, text);
}
}
}