实现功能
1、TabLayout+ViewPager2(Fragments)
2、TabLayout
①、动态设置TabView(setTabViewResId),TextView动态设置IdseTabViewTextResId(),并获取TextView对象
②、默认全部Fragmnet预加载,可通过setOffscreenPageLimit(boolean)控制
③、UserTabConfigurationStrategy监听,获取所有TabView初始化对象
④、UserTabSelectedListener,获取TabLayout切换时候监听回调,包含切换前后上个item position
⑤、设置和更新 未读数和小红,包含是否开启初始化后立马显示未读数和小红点,也可以网络请求后设置
⑥、TabView支持选中字体加粗、字体大小、颜色,未选中字体加粗、字体大小、颜色
⑦、设置TextView,内边距和外边距。
在保留官方TabLayout和ViewPager2所有特性前提下,封装其他公共方法。
UserTabLayoutMediator代码:
public final class UserTabLayoutMediator implements TabLayout.OnTabSelectedListener {
private static final long ATTACH_DRAWABLE_VIEW_DELAY_MILLIS = 500l;
private TabLayout tabLayout;
private ViewPager2 viewPager;
private TabLayoutMediator tabLayoutMediator;
private UserTabConfigurationStrategy userTabConfigurationStrategy;
private UserTabSelectedListener userTabSelectedListener;
Map badgeDrawableMap = new HashMap<>();
private boolean attached = false;
private BadgeDrawableRunnable badgeDrawableRunnable;
private boolean attachDrawableViewAsync = false;
private @LayoutRes
int tabViewResId = R.layout.base_user_tab_layout_mediator_tab_view; //user_tab_layout_mediator_tab_view
private @IdRes
int tabViewTextResId = R.id.base_user_tab_layout_mediator_text_view;
private int selectTextSize;
private int unselectedTextSize;
private int selectTextColor;
private int unselectedTextColor;
private boolean fakeBoldText;
private List tabViewTextList;
//默认设置 OffscreenPageLimit true,则ViewPager Fragment都会初始化并执行到onStart方法。当前台显示onResume->onPause
private boolean offscreenPageLimit = true;
private int currentItemPosition;
private int gravity;
private int paddingLeft;
private int paddingTop;
private int paddingRight;
private int paddingBottom;
private int marginLeft;
private int marginTop;
private int marginRight;
private int marginBottom;
private int onTabSelectPosition;
public UserTabLayoutMediator() {
}
public UserTabLayoutMediator(TabLayout tabLayout, UserTabConfigurationStrategy tabConfigurationStrategy) {
this(tabLayout, null, tabConfigurationStrategy);
}
public UserTabLayoutMediator(ViewPager2 viewPager, UserTabConfigurationStrategy tabConfigurationStrategy) {
this(null, viewPager, tabConfigurationStrategy);
}
public UserTabLayoutMediator(TabLayout tabLayout, ViewPager2 viewPager, UserTabConfigurationStrategy tabConfigurationStrategy) {
this.tabLayout = tabLayout;
this.viewPager = viewPager;
this.userTabConfigurationStrategy = tabConfigurationStrategy;
}
public void setTabViewText(String[] tabViewText) {
if (tabViewText != null) {
this.tabViewTextList = new ArrayList<>();
Collections.addAll(this.tabViewTextList, tabViewText);
}
}
public void setTabViewText(List tabViewText) {
this.tabViewTextList = tabViewText;
}
//设置自定义tab View resId
public void setTabViewResId(@LayoutRes int tabViewResId) {
this.tabViewResId = tabViewResId;
}
//设置自定义 tabView textViwId
public void seTabViewTextResId(@IdRes int tabViewTextResId) {
this.tabViewTextResId = tabViewTextResId;
}
public void setSelectFakeBoldText(boolean fakeBoldText) {
this.fakeBoldText = fakeBoldText;
}
public void setTextSize(int selectTextSize, int unselectedTextSize) {
this.selectTextSize = selectTextSize;
this.unselectedTextSize = unselectedTextSize;
}
public void setTextColor(@ColorRes int selectTextColor, @ColorRes int unselectedTextColor) {
this.selectTextColor = selectTextColor;
this.unselectedTextColor = unselectedTextColor;
}
/**
* 设置显示的ViewPager item position,未绑定,初始化设置setCurrentItem,当初始化后,直接调用ViewPager.setCurrentItem()
*
* @param itemPosition
*/
public void setCurrentItemPosition(int itemPosition) {
this.currentItemPosition = itemPosition;
if (attached) {
setCurrentItem(itemPosition);
}
}
public void setCurrentItem(int item) {
setCurrentItem(item, true);
}
public void setCurrentItem(int item, boolean smoothScroll) {
if (viewPager != null)
viewPager.setCurrentItem(item, smoothScroll);
}
public void setAttachDrawableViewAsync(boolean attachDrawableViewAsync) {
this.attachDrawableViewAsync = attachDrawableViewAsync;
}
public void setOffscreenPageLimit(boolean limit) {
this.offscreenPageLimit = limit;
}
public void setGravity(int gravity) {
this.gravity = gravity;
}
public void setPadding(int left, int top, int right, int bottom) {
this.paddingLeft = left;
this.paddingTop = top;
this.paddingRight = right;
this.paddingBottom = bottom;
}
public void setMargins(int left, int top, int right, int bottom) {
this.marginLeft = left;
this.marginTop = top;
this.marginRight = right;
this.marginBottom = bottom;
}
//------设置监听----------------
public void addUserTabConfigurationStrategy(UserTabConfigurationStrategy tabConfigurationStrategy) {
this.userTabConfigurationStrategy = tabConfigurationStrategy;
}
public void addTabSelectedListener(UserTabSelectedListener userTabSelectedListener) {
this.userTabSelectedListener = userTabSelectedListener;
}
public void attach() {
attached = true;
if (tabLayout != null && viewPager != null) {
viewPager.setCurrentItem(currentItemPosition);
tabLayoutMediator = new TabLayoutMediator(tabLayout, viewPager, new TabLayoutMediator.TabConfigurationStrategy() {
@Override
public void onConfigureTab(@NonNull TabLayout.Tab tab, int position) {
if (tabViewResId != View.NO_ID) {
View customView = tab.setCustomView(tabViewResId).getCustomView();
setTabViewGravity(customView);
TextView textView = customView.findViewById(tabViewTextResId);
setTabViewText(null, textView, position);
setTabViewTextViewPadding(textView);
setTabViewTextViewMargins(textView);
} else {
setTabViewText(tab, null, position);
}
if (userTabConfigurationStrategy != null) {
userTabConfigurationStrategy.onConfigureTab(tab, position);
}
}
});
tabLayout.addOnTabSelectedListener(this);
RecyclerView.Adapter adapter = viewPager.getAdapter();
if (offscreenPageLimit && adapter != null) {
int itemCount = adapter.getItemCount();
if (itemCount > 1)
viewPager.setOffscreenPageLimit(itemCount);
}
tabLayoutMediator.attach();
if (attachDrawableViewAsync)
attachDrawableViewByAsync();
}
}
public void detach() {
attached = false;
if (tabLayoutMediator != null) {
tabLayoutMediator.detach();
tabLayoutMediator = null;
}
if (tabLayout != null) {
tabLayout.removeOnTabSelectedListener(this);
}
if (badgeDrawableMap != null) {
badgeDrawableMap.clear();
}
removeDrawableViewCallbacks();
}
/**
* 添加 BadgeDrawable 小红点
*
* @param context
* @param position
* @param backgroundColor
*/
public void addBadgeDrawable(Context context, int position, @ColorRes int backgroundColor) {
BadgeDrawable badge = BadgeDrawable.create(context);
badge.setBackgroundColor(ContextCompat.getColor(context, backgroundColor));
badge.setHorizontalOffset(5);
badge.setVerticalOffset(5);
badge.setVisible(true);
badgeDrawableMap.put(position, badge);
}
/**
* 添加 BadgeDrawable 未读数量
*
* @param context 上下文
* @param position 需要添加位置
* @param backgroundColor 背景颜色
* @param badgeTextColor 字体颜色
* @param number 显示未读数量
* @param maxCharacterCount 最大位数 number 99999, max== 3 则显示:99+
*/
public void addBadgeDrawable(Context context, int position, @ColorRes int backgroundColor, @ColorRes int badgeTextColor, int number, int maxCharacterCount) {
BadgeDrawable badge = BadgeDrawable.create(context);
badge.setBackgroundColor(ContextCompat.getColor(context, backgroundColor));
badge.setBadgeTextColor(ContextCompat.getColor(context, badgeTextColor));
badge.setHorizontalOffset(5);
badge.setVerticalOffset(5);
badge.setNumber(number);
badge.setMaxCharacterCount(maxCharacterCount);
badge.setVisible(true);
badgeDrawableMap.put(position, badge);
}
/**
* 绑定 DrawableView
*
* @param context
* @param position
* @param backgroundColor
*/
@SuppressLint({"UnsafeExperimentalUsageError", "RestrictedApi"})
public void attachDrawableView(Context context, int position, @ColorRes int backgroundColor) {
addBadgeDrawable(context, position, backgroundColor);
BadgeDrawable badgeDrawable = badgeDrawableMap.get(position);
if (badgeDrawable != null) {
View view = badgeDrawableView(position);
if (view != null) {
BadgeUtils.attachBadgeDrawable(badgeDrawable, view);
}
}
}
/**
* 绑定 DrawableView
*
* @param context
* @param position
* @param backgroundColor
* @param badgeTextColor
* @param number
* @param maxCharacterCount
*/
@SuppressLint("UnsafeExperimentalUsageError")
public void attachDrawableView(Context context, int position, @ColorRes int backgroundColor, @ColorRes int badgeTextColor, int number, int maxCharacterCount) {
addBadgeDrawable(context, position, backgroundColor, badgeTextColor, number, maxCharacterCount);
BadgeDrawable badgeDrawable = badgeDrawableMap.get(position);
if (badgeDrawable != null) {
View view = badgeDrawableView(position);
if (view != null) {
BadgeUtils.attachBadgeDrawable(badgeDrawable, view);
}
}
}
/**
* 绑定 DrawableView 不可初始化之后,直接调用
*/
@SuppressLint("UnsafeExperimentalUsageError")
public void attachDrawableView() {
if (tabLayout != null && attached && badgeDrawableMap.size() > 0) {
for (Map.Entry entry : badgeDrawableMap.entrySet()) {
TabLayout.Tab tabAt = tabLayout.getTabAt(entry.getKey());
BadgeDrawable badgeDrawable = entry.getValue();
if (tabAt != null && badgeDrawable != null) {
View customView = tabAt.getCustomView();
if (customView != null) {
View view = customView.findViewById(tabViewTextResId);
if (view != null) {
BadgeUtils.attachBadgeDrawable(badgeDrawable, view);
}
}
}
}
}
}
/**
* 异步绑定 DrawableView
*/
public void attachDrawableViewByAsync() {
if (tabLayout != null && attached && badgeDrawableMap.size() > 0) {
badgeDrawableRunnable = new BadgeDrawableRunnable(tabLayout, badgeDrawableMap, tabViewTextResId);
tabLayout.postDelayed(badgeDrawableRunnable, ATTACH_DRAWABLE_VIEW_DELAY_MILLIS);
}
}
/**
* 移除异步线程
*/
private void removeDrawableViewCallbacks() {
if (tabLayout != null && badgeDrawableRunnable != null) {
tabLayout.removeCallbacks(badgeDrawableRunnable);
}
}
/**
* 更新 BadgeDrawable
*
* @param position
* @param number
*/
@SuppressLint("UnsafeExperimentalUsageError")
public void updateBadgeDrawable(int position, int number) {
if (badgeDrawableMap != null) {
if (badgeDrawableMap.containsKey(position)) {
BadgeDrawable badgeDrawable = badgeDrawableMap.get(position);
if (badgeDrawable != null) {
badgeDrawable.setNumber(number);
View view = detachBadgeDrawable(position);
if (view != null) {
BadgeUtils.attachBadgeDrawable(badgeDrawable, view);
}
}
}
}
}
/**
* 移除 BadgeDrawable
*
* @param position
* @return
*/
@SuppressLint("UnsafeExperimentalUsageError")
public View detachBadgeDrawable(int position) {
if (badgeDrawableMap != null && position < badgeDrawableMap.size()) {
BadgeDrawable badgeDrawable = badgeDrawableMap.get(position);
if (badgeDrawable != null) {
badgeDrawable.setVisible(false);
View view = badgeDrawableView(position);
if (view != null) {
BadgeUtils.detachBadgeDrawable(badgeDrawable, view);
}
return view;
}
}
return null;
}
/**
* 获取当前 badgeDrawable ---view
*
* @param position
* @return
*/
private View badgeDrawableView(int position) {
if (tabLayout != null) {
TabLayout.Tab tabAt = tabLayout.getTabAt(position);
if (tabAt != null) {
View customView = tabAt.getCustomView();
if (customView != null) {
return customView.findViewById(tabViewTextResId);
}
}
}
return null;
}
private void setTabViewText(TabLayout.Tab tab, TextView textView, int position) {
if (tabViewTextList != null && position < tabViewTextList.size()) {
String text = tabViewTextList.get(position);
if (tab != null) {
tab.setText(text);
}
if (textView != null)
textView.setText(text);
} else {
RecyclerView.Adapter adapter = viewPager.getAdapter();
if (adapter instanceof BaseFragmentPagerAdapter) {
BaseFragmentPagerAdapter pagerAdapter = (BaseFragmentPagerAdapter) adapter;
CharSequence text = pagerAdapter.getPageTitle(position);
if (tab != null)
tab.setText(text);
if (textView != null)
textView.setText(text);
}
}
}
/**
* 设置tabView textView padding
*
* @param view
*/
private void setTabViewTextViewPadding(View view) {
if (view != null && (paddingLeft != 0 || paddingTop != 0 || paddingRight != 0 || paddingBottom != 0)) {
view.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);
}
}
/**
* 设置tabView textView margin
*
* @param view
*/
private void setTabViewTextViewMargins(View view) {
if (view != null && (marginLeft != 0 || marginTop != 0 || marginRight != 0 || marginBottom != 0)) {
ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
if (layoutParams instanceof LinearLayout.LayoutParams) {
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) layoutParams;
params.setMargins(marginLeft, marginTop, marginRight, marginBottom);
}
}
}
/**
* 设置tabView gravity
*
* @param view
*/
private void setTabViewGravity(View view) {
if (view != null && gravity != 0 && view instanceof LinearLayout) {
LinearLayout linearLayout = (LinearLayout) view;
linearLayout.setGravity(gravity);
}
}
@Override
public void onTabSelected(TabLayout.Tab tab) {
if (viewPager != null)
onTabSelectPosition = viewPager.getCurrentItem();
if (tab != null) {
View customView = tab.getCustomView();
if (customView != null) {
TextView textView = customView.findViewById(tabViewTextResId);
if (textView != null) {
if (selectTextSize != 0 && selectTextSize != unselectedTextSize)
textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, selectTextSize);
if (selectTextColor != 0 && selectTextColor != unselectedTextColor)
textView.setTextColor(ContextCompat.getColor(textView.getContext(), selectTextColor));
if (fakeBoldText)
textView.getPaint().setFakeBoldText(true);
}
}
}
if (userTabSelectedListener != null) {
userTabSelectedListener.onTabSelected(tab, onTabSelectPosition);
}
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {
if (tab != null) {
View customView = tab.getCustomView();
if (customView != null) {
TextView textView = customView.findViewById(tabViewTextResId);
if (textView != null) {
if (selectTextSize != 0 && selectTextSize != unselectedTextSize)
textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, unselectedTextSize);
if (selectTextColor != 0 && selectTextColor != unselectedTextColor)
textView.setTextColor(ContextCompat.getColor(textView.getContext(), unselectedTextColor));
if (fakeBoldText)
textView.getPaint().setFakeBoldText(false);
}
}
}
if (userTabSelectedListener != null) {
userTabSelectedListener.onTabUnselected(tab, onTabSelectPosition);
}
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
if (userTabSelectedListener != null) {
userTabSelectedListener.onTabReselected(tab);
}
}
/**
* 异步 BadgeDrawableView
*/
static class BadgeDrawableRunnable implements Runnable {
private WeakReference tabLayoutWeakReference;
private Map badgeDrawableMap;
private int tabViewTextResId;
public BadgeDrawableRunnable(TabLayout tabLayout, Map badgeDrawableMap, int tabViewTextResId) {
if (tabLayout != null)
tabLayoutWeakReference = new WeakReference<>(tabLayout);
this.badgeDrawableMap = badgeDrawableMap;
this.tabViewTextResId = tabViewTextResId;
}
@SuppressLint("UnsafeExperimentalUsageError")
@Override
public void run() {
if (tabLayoutWeakReference != null && tabLayoutWeakReference.get() != null && badgeDrawableMap != null) {
TabLayout tabLayout = tabLayoutWeakReference.get();
for (Map.Entry entry : badgeDrawableMap.entrySet()) {
TabLayout.Tab tabAt = tabLayout.getTabAt(entry.getKey());
BadgeDrawable badgeDrawable = entry.getValue();
if (tabAt != null && badgeDrawable != null) {
View customView = tabAt.getCustomView();
if (customView != null) {
View view = customView.findViewById(tabViewTextResId);
if (view != null) {
BadgeUtils.attachBadgeDrawable(badgeDrawable, view);
}
}
}
}
}
}
}
public interface UserTabConfigurationStrategy {
/**
* Called to configure the tab for the page at the specified position. Typically calls {@link
* TabLayout.Tab#setText(CharSequence)}, but any form of styling can be applied.
*
* @param tab The Tab which should be configured to represent the title of the item at the given
* position in the data set.
* @param position The position of the item within the adapter's data set.
*/
void onConfigureTab(@NonNull TabLayout.Tab tab, int position);
}
public interface UserTabSelectedListener {
void onTabSelected(TabLayout.Tab tab, int position);
/**
* Called when a tab exits the selected state.
*
* @param tab The tab that was unselected
*/
void onTabUnselected(TabLayout.Tab tab, int unPosition);
/**
* Called when a tab that is already selected is chosen again by the user. Some applications may
* use this action to return to the top level of a category.
*
* @param tab The tab that was reselected.
*/
void onTabReselected(TabLayout.Tab tab);
}
}
tabView:base_user_tab_layout_mediator_tab_view
ids.xml