当前位置:   article > 正文

基于TabLayoutMediator实现TabLayout+ViewPager2(Fragment)封装

tablayoutmediator

实现功能

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代码:

  1. public final class UserTabLayoutMediator implements TabLayout.OnTabSelectedListener {
  2. private static final long ATTACH_DRAWABLE_VIEW_DELAY_MILLIS = 500l;
  3. private TabLayout tabLayout;
  4. private ViewPager2 viewPager;
  5. private TabLayoutMediator tabLayoutMediator;
  6. private UserTabConfigurationStrategy userTabConfigurationStrategy;
  7. private UserTabSelectedListener userTabSelectedListener;
  8. Map<Integer, BadgeDrawable> badgeDrawableMap = new HashMap<>();
  9. private boolean attached = false;
  10. private BadgeDrawableRunnable badgeDrawableRunnable;
  11. private boolean attachDrawableViewAsync = false;
  12. private @LayoutRes
  13. int tabViewResId = R.layout.base_user_tab_layout_mediator_tab_view; //user_tab_layout_mediator_tab_view
  14. private @IdRes
  15. int tabViewTextResId = R.id.base_user_tab_layout_mediator_text_view;
  16. private int selectTextSize;
  17. private int unselectedTextSize;
  18. private int selectTextColor;
  19. private int unselectedTextColor;
  20. private boolean fakeBoldText;
  21. private List<String> tabViewTextList;
  22. //默认设置 OffscreenPageLimit true,则ViewPager Fragment都会初始化并执行到onStart方法。当前台显示onResume->onPause
  23. private boolean offscreenPageLimit = true;
  24. private int currentItemPosition;
  25. private int gravity;
  26. private int paddingLeft;
  27. private int paddingTop;
  28. private int paddingRight;
  29. private int paddingBottom;
  30. private int marginLeft;
  31. private int marginTop;
  32. private int marginRight;
  33. private int marginBottom;
  34. private int onTabSelectPosition;
  35. public UserTabLayoutMediator() {
  36. }
  37. public UserTabLayoutMediator(TabLayout tabLayout, UserTabConfigurationStrategy tabConfigurationStrategy) {
  38. this(tabLayout, null, tabConfigurationStrategy);
  39. }
  40. public UserTabLayoutMediator(ViewPager2 viewPager, UserTabConfigurationStrategy tabConfigurationStrategy) {
  41. this(null, viewPager, tabConfigurationStrategy);
  42. }
  43. public UserTabLayoutMediator(TabLayout tabLayout, ViewPager2 viewPager, UserTabConfigurationStrategy tabConfigurationStrategy) {
  44. this.tabLayout = tabLayout;
  45. this.viewPager = viewPager;
  46. this.userTabConfigurationStrategy = tabConfigurationStrategy;
  47. }
  48. public void setTabViewText(String[] tabViewText) {
  49. if (tabViewText != null) {
  50. this.tabViewTextList = new ArrayList<>();
  51. Collections.addAll(this.tabViewTextList, tabViewText);
  52. }
  53. }
  54. public void setTabViewText(List<String> tabViewText) {
  55. this.tabViewTextList = tabViewText;
  56. }
  57. //设置自定义tab View resId
  58. public void setTabViewResId(@LayoutRes int tabViewResId) {
  59. this.tabViewResId = tabViewResId;
  60. }
  61. //设置自定义 tabView textViwId
  62. public void seTabViewTextResId(@IdRes int tabViewTextResId) {
  63. this.tabViewTextResId = tabViewTextResId;
  64. }
  65. public void setSelectFakeBoldText(boolean fakeBoldText) {
  66. this.fakeBoldText = fakeBoldText;
  67. }
  68. public void setTextSize(int selectTextSize, int unselectedTextSize) {
  69. this.selectTextSize = selectTextSize;
  70. this.unselectedTextSize = unselectedTextSize;
  71. }
  72. public void setTextColor(@ColorRes int selectTextColor, @ColorRes int unselectedTextColor) {
  73. this.selectTextColor = selectTextColor;
  74. this.unselectedTextColor = unselectedTextColor;
  75. }
  76. /**
  77. * 设置显示的ViewPager item position,未绑定,初始化设置setCurrentItem,当初始化后,直接调用ViewPager.setCurrentItem()
  78. *
  79. * @param itemPosition
  80. */
  81. public void setCurrentItemPosition(int itemPosition) {
  82. this.currentItemPosition = itemPosition;
  83. if (attached) {
  84. setCurrentItem(itemPosition);
  85. }
  86. }
  87. public void setCurrentItem(int item) {
  88. setCurrentItem(item, true);
  89. }
  90. public void setCurrentItem(int item, boolean smoothScroll) {
  91. if (viewPager != null)
  92. viewPager.setCurrentItem(item, smoothScroll);
  93. }
  94. public void setAttachDrawableViewAsync(boolean attachDrawableViewAsync) {
  95. this.attachDrawableViewAsync = attachDrawableViewAsync;
  96. }
  97. public void setOffscreenPageLimit(boolean limit) {
  98. this.offscreenPageLimit = limit;
  99. }
  100. public void setGravity(int gravity) {
  101. this.gravity = gravity;
  102. }
  103. public void setPadding(int left, int top, int right, int bottom) {
  104. this.paddingLeft = left;
  105. this.paddingTop = top;
  106. this.paddingRight = right;
  107. this.paddingBottom = bottom;
  108. }
  109. public void setMargins(int left, int top, int right, int bottom) {
  110. this.marginLeft = left;
  111. this.marginTop = top;
  112. this.marginRight = right;
  113. this.marginBottom = bottom;
  114. }
  115. //------设置监听----------------
  116. public void addUserTabConfigurationStrategy(UserTabConfigurationStrategy tabConfigurationStrategy) {
  117. this.userTabConfigurationStrategy = tabConfigurationStrategy;
  118. }
  119. public void addTabSelectedListener(UserTabSelectedListener userTabSelectedListener) {
  120. this.userTabSelectedListener = userTabSelectedListener;
  121. }
  122. public void attach() {
  123. attached = true;
  124. if (tabLayout != null && viewPager != null) {
  125. viewPager.setCurrentItem(currentItemPosition);
  126. tabLayoutMediator = new TabLayoutMediator(tabLayout, viewPager, new TabLayoutMediator.TabConfigurationStrategy() {
  127. @Override
  128. public void onConfigureTab(@NonNull TabLayout.Tab tab, int position) {
  129. if (tabViewResId != View.NO_ID) {
  130. View customView = tab.setCustomView(tabViewResId).getCustomView();
  131. setTabViewGravity(customView);
  132. TextView textView = customView.findViewById(tabViewTextResId);
  133. setTabViewText(null, textView, position);
  134. setTabViewTextViewPadding(textView);
  135. setTabViewTextViewMargins(textView);
  136. } else {
  137. setTabViewText(tab, null, position);
  138. }
  139. if (userTabConfigurationStrategy != null) {
  140. userTabConfigurationStrategy.onConfigureTab(tab, position);
  141. }
  142. }
  143. });
  144. tabLayout.addOnTabSelectedListener(this);
  145. RecyclerView.Adapter adapter = viewPager.getAdapter();
  146. if (offscreenPageLimit && adapter != null) {
  147. int itemCount = adapter.getItemCount();
  148. if (itemCount > 1)
  149. viewPager.setOffscreenPageLimit(itemCount);
  150. }
  151. tabLayoutMediator.attach();
  152. if (attachDrawableViewAsync)
  153. attachDrawableViewByAsync();
  154. }
  155. }
  156. public void detach() {
  157. attached = false;
  158. if (tabLayoutMediator != null) {
  159. tabLayoutMediator.detach();
  160. tabLayoutMediator = null;
  161. }
  162. if (tabLayout != null) {
  163. tabLayout.removeOnTabSelectedListener(this);
  164. }
  165. if (badgeDrawableMap != null) {
  166. badgeDrawableMap.clear();
  167. }
  168. removeDrawableViewCallbacks();
  169. }
  170. /**
  171. * 添加 BadgeDrawable 小红点
  172. *
  173. * @param context
  174. * @param position
  175. * @param backgroundColor
  176. */
  177. public void addBadgeDrawable(Context context, int position, @ColorRes int backgroundColor) {
  178. BadgeDrawable badge = BadgeDrawable.create(context);
  179. badge.setBackgroundColor(ContextCompat.getColor(context, backgroundColor));
  180. badge.setHorizontalOffset(5);
  181. badge.setVerticalOffset(5);
  182. badge.setVisible(true);
  183. badgeDrawableMap.put(position, badge);
  184. }
  185. /**
  186. * 添加 BadgeDrawable 未读数量
  187. *
  188. * @param context 上下文
  189. * @param position 需要添加位置
  190. * @param backgroundColor 背景颜色
  191. * @param badgeTextColor 字体颜色
  192. * @param number 显示未读数量
  193. * @param maxCharacterCount 最大位数 number 99999, max== 3 则显示:99+
  194. */
  195. public void addBadgeDrawable(Context context, int position, @ColorRes int backgroundColor, @ColorRes int badgeTextColor, int number, int maxCharacterCount) {
  196. BadgeDrawable badge = BadgeDrawable.create(context);
  197. badge.setBackgroundColor(ContextCompat.getColor(context, backgroundColor));
  198. badge.setBadgeTextColor(ContextCompat.getColor(context, badgeTextColor));
  199. badge.setHorizontalOffset(5);
  200. badge.setVerticalOffset(5);
  201. badge.setNumber(number);
  202. badge.setMaxCharacterCount(maxCharacterCount);
  203. badge.setVisible(true);
  204. badgeDrawableMap.put(position, badge);
  205. }
  206. /**
  207. * 绑定 DrawableView
  208. *
  209. * @param context
  210. * @param position
  211. * @param backgroundColor
  212. */
  213. @SuppressLint({"UnsafeExperimentalUsageError", "RestrictedApi"})
  214. public void attachDrawableView(Context context, int position, @ColorRes int backgroundColor) {
  215. addBadgeDrawable(context, position, backgroundColor);
  216. BadgeDrawable badgeDrawable = badgeDrawableMap.get(position);
  217. if (badgeDrawable != null) {
  218. View view = badgeDrawableView(position);
  219. if (view != null) {
  220. BadgeUtils.attachBadgeDrawable(badgeDrawable, view);
  221. }
  222. }
  223. }
  224. /**
  225. * 绑定 DrawableView
  226. *
  227. * @param context
  228. * @param position
  229. * @param backgroundColor
  230. * @param badgeTextColor
  231. * @param number
  232. * @param maxCharacterCount
  233. */
  234. @SuppressLint("UnsafeExperimentalUsageError")
  235. public void attachDrawableView(Context context, int position, @ColorRes int backgroundColor, @ColorRes int badgeTextColor, int number, int maxCharacterCount) {
  236. addBadgeDrawable(context, position, backgroundColor, badgeTextColor, number, maxCharacterCount);
  237. BadgeDrawable badgeDrawable = badgeDrawableMap.get(position);
  238. if (badgeDrawable != null) {
  239. View view = badgeDrawableView(position);
  240. if (view != null) {
  241. BadgeUtils.attachBadgeDrawable(badgeDrawable, view);
  242. }
  243. }
  244. }
  245. /**
  246. * 绑定 DrawableView 不可初始化之后,直接调用
  247. */
  248. @SuppressLint("UnsafeExperimentalUsageError")
  249. public void attachDrawableView() {
  250. if (tabLayout != null && attached && badgeDrawableMap.size() > 0) {
  251. for (Map.Entry<Integer, BadgeDrawable> entry : badgeDrawableMap.entrySet()) {
  252. TabLayout.Tab tabAt = tabLayout.getTabAt(entry.getKey());
  253. BadgeDrawable badgeDrawable = entry.getValue();
  254. if (tabAt != null && badgeDrawable != null) {
  255. View customView = tabAt.getCustomView();
  256. if (customView != null) {
  257. View view = customView.findViewById(tabViewTextResId);
  258. if (view != null) {
  259. BadgeUtils.attachBadgeDrawable(badgeDrawable, view);
  260. }
  261. }
  262. }
  263. }
  264. }
  265. }
  266. /**
  267. * 异步绑定 DrawableView
  268. */
  269. public void attachDrawableViewByAsync() {
  270. if (tabLayout != null && attached && badgeDrawableMap.size() > 0) {
  271. badgeDrawableRunnable = new BadgeDrawableRunnable(tabLayout, badgeDrawableMap, tabViewTextResId);
  272. tabLayout.postDelayed(badgeDrawableRunnable, ATTACH_DRAWABLE_VIEW_DELAY_MILLIS);
  273. }
  274. }
  275. /**
  276. * 移除异步线程
  277. */
  278. private void removeDrawableViewCallbacks() {
  279. if (tabLayout != null && badgeDrawableRunnable != null) {
  280. tabLayout.removeCallbacks(badgeDrawableRunnable);
  281. }
  282. }
  283. /**
  284. * 更新 BadgeDrawable
  285. *
  286. * @param position
  287. * @param number
  288. */
  289. @SuppressLint("UnsafeExperimentalUsageError")
  290. public void updateBadgeDrawable(int position, int number) {
  291. if (badgeDrawableMap != null) {
  292. if (badgeDrawableMap.containsKey(position)) {
  293. BadgeDrawable badgeDrawable = badgeDrawableMap.get(position);
  294. if (badgeDrawable != null) {
  295. badgeDrawable.setNumber(number);
  296. View view = detachBadgeDrawable(position);
  297. if (view != null) {
  298. BadgeUtils.attachBadgeDrawable(badgeDrawable, view);
  299. }
  300. }
  301. }
  302. }
  303. }
  304. /**
  305. * 移除 BadgeDrawable
  306. *
  307. * @param position
  308. * @return
  309. */
  310. @SuppressLint("UnsafeExperimentalUsageError")
  311. public View detachBadgeDrawable(int position) {
  312. if (badgeDrawableMap != null && position < badgeDrawableMap.size()) {
  313. BadgeDrawable badgeDrawable = badgeDrawableMap.get(position);
  314. if (badgeDrawable != null) {
  315. badgeDrawable.setVisible(false);
  316. View view = badgeDrawableView(position);
  317. if (view != null) {
  318. BadgeUtils.detachBadgeDrawable(badgeDrawable, view);
  319. }
  320. return view;
  321. }
  322. }
  323. return null;
  324. }
  325. /**
  326. * 获取当前 badgeDrawable ---view
  327. *
  328. * @param position
  329. * @return
  330. */
  331. private View badgeDrawableView(int position) {
  332. if (tabLayout != null) {
  333. TabLayout.Tab tabAt = tabLayout.getTabAt(position);
  334. if (tabAt != null) {
  335. View customView = tabAt.getCustomView();
  336. if (customView != null) {
  337. return customView.findViewById(tabViewTextResId);
  338. }
  339. }
  340. }
  341. return null;
  342. }
  343. private void setTabViewText(TabLayout.Tab tab, TextView textView, int position) {
  344. if (tabViewTextList != null && position < tabViewTextList.size()) {
  345. String text = tabViewTextList.get(position);
  346. if (tab != null) {
  347. tab.setText(text);
  348. }
  349. if (textView != null)
  350. textView.setText(text);
  351. } else {
  352. RecyclerView.Adapter adapter = viewPager.getAdapter();
  353. if (adapter instanceof BaseFragmentPagerAdapter) {
  354. BaseFragmentPagerAdapter pagerAdapter = (BaseFragmentPagerAdapter) adapter;
  355. CharSequence text = pagerAdapter.getPageTitle(position);
  356. if (tab != null)
  357. tab.setText(text);
  358. if (textView != null)
  359. textView.setText(text);
  360. }
  361. }
  362. }
  363. /**
  364. * 设置tabView textView padding
  365. *
  366. * @param view
  367. */
  368. private void setTabViewTextViewPadding(View view) {
  369. if (view != null && (paddingLeft != 0 || paddingTop != 0 || paddingRight != 0 || paddingBottom != 0)) {
  370. view.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);
  371. }
  372. }
  373. /**
  374. * 设置tabView textView margin
  375. *
  376. * @param view
  377. */
  378. private void setTabViewTextViewMargins(View view) {
  379. if (view != null && (marginLeft != 0 || marginTop != 0 || marginRight != 0 || marginBottom != 0)) {
  380. ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
  381. if (layoutParams instanceof LinearLayout.LayoutParams) {
  382. LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) layoutParams;
  383. params.setMargins(marginLeft, marginTop, marginRight, marginBottom);
  384. }
  385. }
  386. }
  387. /**
  388. * 设置tabView gravity
  389. *
  390. * @param view
  391. */
  392. private void setTabViewGravity(View view) {
  393. if (view != null && gravity != 0 && view instanceof LinearLayout) {
  394. LinearLayout linearLayout = (LinearLayout) view;
  395. linearLayout.setGravity(gravity);
  396. }
  397. }
  398. @Override
  399. public void onTabSelected(TabLayout.Tab tab) {
  400. if (viewPager != null)
  401. onTabSelectPosition = viewPager.getCurrentItem();
  402. if (tab != null) {
  403. View customView = tab.getCustomView();
  404. if (customView != null) {
  405. TextView textView = customView.findViewById(tabViewTextResId);
  406. if (textView != null) {
  407. if (selectTextSize != 0 && selectTextSize != unselectedTextSize)
  408. textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, selectTextSize);
  409. if (selectTextColor != 0 && selectTextColor != unselectedTextColor)
  410. textView.setTextColor(ContextCompat.getColor(textView.getContext(), selectTextColor));
  411. if (fakeBoldText)
  412. textView.getPaint().setFakeBoldText(true);
  413. }
  414. }
  415. }
  416. if (userTabSelectedListener != null) {
  417. userTabSelectedListener.onTabSelected(tab, onTabSelectPosition);
  418. }
  419. }
  420. @Override
  421. public void onTabUnselected(TabLayout.Tab tab) {
  422. if (tab != null) {
  423. View customView = tab.getCustomView();
  424. if (customView != null) {
  425. TextView textView = customView.findViewById(tabViewTextResId);
  426. if (textView != null) {
  427. if (selectTextSize != 0 && selectTextSize != unselectedTextSize)
  428. textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, unselectedTextSize);
  429. if (selectTextColor != 0 && selectTextColor != unselectedTextColor)
  430. textView.setTextColor(ContextCompat.getColor(textView.getContext(), unselectedTextColor));
  431. if (fakeBoldText)
  432. textView.getPaint().setFakeBoldText(false);
  433. }
  434. }
  435. }
  436. if (userTabSelectedListener != null) {
  437. userTabSelectedListener.onTabUnselected(tab, onTabSelectPosition);
  438. }
  439. }
  440. @Override
  441. public void onTabReselected(TabLayout.Tab tab) {
  442. if (userTabSelectedListener != null) {
  443. userTabSelectedListener.onTabReselected(tab);
  444. }
  445. }
  446. /**
  447. * 异步 BadgeDrawableView
  448. */
  449. static class BadgeDrawableRunnable implements Runnable {
  450. private WeakReference<TabLayout> tabLayoutWeakReference;
  451. private Map<Integer, BadgeDrawable> badgeDrawableMap;
  452. private int tabViewTextResId;
  453. public BadgeDrawableRunnable(TabLayout tabLayout, Map<Integer, BadgeDrawable> badgeDrawableMap, int tabViewTextResId) {
  454. if (tabLayout != null)
  455. tabLayoutWeakReference = new WeakReference<>(tabLayout);
  456. this.badgeDrawableMap = badgeDrawableMap;
  457. this.tabViewTextResId = tabViewTextResId;
  458. }
  459. @SuppressLint("UnsafeExperimentalUsageError")
  460. @Override
  461. public void run() {
  462. if (tabLayoutWeakReference != null && tabLayoutWeakReference.get() != null && badgeDrawableMap != null) {
  463. TabLayout tabLayout = tabLayoutWeakReference.get();
  464. for (Map.Entry<Integer, BadgeDrawable> entry : badgeDrawableMap.entrySet()) {
  465. TabLayout.Tab tabAt = tabLayout.getTabAt(entry.getKey());
  466. BadgeDrawable badgeDrawable = entry.getValue();
  467. if (tabAt != null && badgeDrawable != null) {
  468. View customView = tabAt.getCustomView();
  469. if (customView != null) {
  470. View view = customView.findViewById(tabViewTextResId);
  471. if (view != null) {
  472. BadgeUtils.attachBadgeDrawable(badgeDrawable, view);
  473. }
  474. }
  475. }
  476. }
  477. }
  478. }
  479. }
  480. public interface UserTabConfigurationStrategy {
  481. /**
  482. * Called to configure the tab for the page at the specified position. Typically calls {@link
  483. * TabLayout.Tab#setText(CharSequence)}, but any form of styling can be applied.
  484. *
  485. * @param tab The Tab which should be configured to represent the title of the item at the given
  486. * position in the data set.
  487. * @param position The position of the item within the adapter's data set.
  488. */
  489. void onConfigureTab(@NonNull TabLayout.Tab tab, int position);
  490. }
  491. public interface UserTabSelectedListener {
  492. void onTabSelected(TabLayout.Tab tab, int position);
  493. /**
  494. * Called when a tab exits the selected state.
  495. *
  496. * @param tab The tab that was unselected
  497. */
  498. void onTabUnselected(TabLayout.Tab tab, int unPosition);
  499. /**
  500. * Called when a tab that is already selected is chosen again by the user. Some applications may
  501. * use this action to return to the top level of a category.
  502. *
  503. * @param tab The tab that was reselected.
  504. */
  505. void onTabReselected(TabLayout.Tab tab);
  506. }
  507. }
tabView:base_user_tab_layout_mediator_tab_view 
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. android:gravity="center"
  6. android:orientation="horizontal">
  7. <TextView
  8. android:id="@id/base_user_tab_layout_mediator_text_view"
  9. android:layout_width="wrap_content"
  10. android:layout_height="wrap_content"
  11. android:text="" />
  12. </LinearLayout>

ids.xml

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <resources>
  3. <!-- tabLayout tabView id -->
  4. <item name="base_user_tab_layout_mediator_tab_view" type="id"></item>
  5. <!-- tabLayout tabView textView id -->
  6. <item name="base_user_tab_layout_mediator_text_view" type="id"></item>
  7. </resources>

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/450046
推荐阅读
相关标签
  

闽ICP备14008679号