• 【Android】TabLayout设置使用自定义的样式的图片显示问题


    序言

    TabLayout我们经常使用,用来和ViewPager2进行组合使用,做多Fragment切换页面效果。
    TabLayout我们经常看到的的显示效果是上面文字,下面一个线段,在各大浏览器/新闻类APP可以看到,这个效果也是对TabLayout配置参数可以实现的,但是我们想要实现这种效果
    在这里插入图片描述
    我们有两个Tab,左边和右边的,选中左边的之后,左边的就是橙色,然后箭头指向右边,选中右边的,右边变成橙色,然后箭头指向左边。

    这个需要对TabLayout进行配置。

    实现

    首先Tablayout在xml里面的配置

        <com.google.android.material.tabs.TabLayout
            android:id="@+id/tab"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="fill"
            android:background="@color/white"
            android:paddingStart="0dp"
            android:paddingEnd="0dp"
            app:tabGravity="fill"
            app:tabIndicatorColor="@color/white"
            app:tabIndicatorHeight="0dp"
            app:tabMaxWidth="0dp"
            app:tabMode="fixed"
            app:tabPaddingEnd="-1dp"
            app:tabPaddingStart="-1dp"
            app:tabRippleColor="@null" />
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    其中这个

          app:tabPaddingEnd="-1dp"
          app:tabPaddingStart="-1dp"
    
    • 1
    • 2

    是因为Tab本身自己是有默认的Padding的,这样是为了能让我们图片充满TabLayout的空间。

    在这里插入图片描述
    在这里插入图片描述

    然后我们需要准备好这种图片放在项目里面
    接下来就是很正常的操作了,创建Adapter继承FragmentStateAdapter,然后往里面加内容

    class TabAdapter(
        val fragment: FragmentActivity,
        val mContext: Context,
        val index: Int
    ) : FragmentStateAdapter(fragment) {
    
        private class ViewPagerData(var imageBgId: Int, var imageIcon: Int, var textId: Int)
    
        private val viewPagerDataList: MutableList<ViewPagerData> = mutableListOf()
    
        init {
            viewPagerDataList.add(
                ViewPagerData(
                    R.drawable.ic_un_selected,
                    R.mipmap.ic_un_change,
                    R.string.lable_type
                )
            )
            viewPagerDataList.add(
                ViewPagerData(
                    R.drawable.ic_un_selected,
                    R.mipmap.ic_un_change,
                    R.string.installation
                )
            )
        }
    
        override fun getItemCount(): Int = viewPagerDataList.size
    
        override fun createFragment(position: Int): Fragment {
            return when (position) {
                0 -> OneFragment()
                1 -> TwoFragment()
                else -> OneFragment()
            }
        }
    
        @SuppressLint("MissingInflatedId")
        fun getTabView(position: Int): View? {
            val view =
                LayoutInflater.from(mContext).inflate(R.layout.view_layout, null)
            val tabBg = view.findViewById<LinearLayout>(R.id.ll_bg)
            val tabTextView = view.findViewById<TextView>(R.id.tv_name)
            val tabImageView = view.findViewById<ImageView>(R.id.iv_icon)
            // 在这里设置初始颜色和图标
            tabTextView.setText(viewPagerDataList[position].textId)
            tabTextView.setTextColor(mContext.resources.getColor(R.color.color_first_level_word))
            tabImageView.setImageResource(viewPagerDataList[position].imageIcon)
            tabBg.setBackgroundResource(viewPagerDataList[position].imageBgId)
            return view
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    里面的view_layout文件

    
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/ll_bg"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:orientation="horizontal">
    
        <ImageView
            android:id="@+id/iv_tab_icon"
            android:layout_width="@dimen/agree_user_width_22"
            android:layout_height="@dimen/agree_user_width_22"
            android:layout_gravity="center_vertical" />
    
        <TextView
            android:id="@+id/tv_name"
            android:layout_width="wrap_content"
            android:layout_height="@dimen/Standard_height48"
            android:layout_marginStart="@dimen/margin_8"
            android:gravity="center_vertical"
            android:textColor="@color/color_first_level_word"
            android:textSize="@dimen/textSize_18sp" />
    LinearLayout>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    注意:在设置这个Tab的高度的时候,有时候可能因为系统的问题,导致我们设置的Tab图片无法充满这个TabLayout的空间,解决办法上面有提到,其中左右无法充满就是使用这个方法解决,在TabLayout里面加

          app:tabPaddingEnd="-1dp"
          app:tabPaddingStart="-1dp"
    
    • 1
    • 2

    这个上面提到了,但是上下不充满的话就无法使用这个设置了,
    需要我们在设置TabLayout的时候
    1.设置TabLayout的上下高度

       android:layout_height="wrap_content"
    
    • 1

    2.在设置我们每个Tab的xml文件时,就是上面的view_layout文件里面设置高度,但是不要在父View里面设置高度,就像上面的view_layout里面,父View是LinearLayout,不能将LinearLayout的高度设置成我们需要的,要将其设置成

      android:layout_height="wrap_content"
    
    • 1

    然后在里面的子View里面,将某个高度设置成我们需要的高度,撑起这个布局,比如我们将TextView的高度设置成48dp,这也是我们需要的TabLayout的高度,这样的话可以解决我们的Tab图片在上下方向上不能充满TabLayout的空间的问题。

    然后我们就可以在Activity里面使用了

    val adapter = TabAdapter(this, this, 0)
    binding.viewPager.adapter = adapter
    binding.viewPager.setIsFocusableInTouchModeKtx(false)
    binding.viewPager.isUserInputEnabled = false
    TabLayoutMediator(binding.tab, binding.viewPager) { tab: TabLayout.Tab, position: Int ->
         tab.customView = adapter.getTabView(position)
    }.attach()
    binding.tab.isTabIndicatorFullWidth = false
    binding.viewPager.setCurrentItem(0, false)
    //初始修改选中的item文字图片颜色
    binding.tab.getTabAt(0)?.customView?.findViewById<LinearLayout>(R.id.ll_bg)?.setBackgroundResource(R.mipmap.ic_select)
    binding.tab.getTabAt(0)?.customView?.findViewById<ImageView>(R.id.iv_icon)?.setImageResource(R.mipmap.ic_change)
    binding.tab.getTabAt(0)?.customView?.findViewById<TextView>(R.id.tv_name)?.setTextColor(getColor(R.color.color_brand))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    这样我们就已经将TabLayout和ViewPager2绑定成功了,但是我们在选择Tab的时候,还是要根据选择的Tab更换相应的背景和图片的。
    我们要对这个TabLayout监听

    binding.tab.addOnTabSelectedListener(object :
       TabLayout.OnTabSelectedListener {
       //选中的item处理
       override fun onTabSelected(tab: TabLayout.Tab) {
           val view = tab.customView
           if (view != null) {
               val tabBg = view.findViewById<LinearLayout>(R.id.ll_bg)
               val tabImageView =
                   view.findViewById<ImageView>(R.id.iv_icon)
               val tabTextView =
                   view.findViewById<TextView>(R.id.tv_name)
               val position = tab.position
               if (position == 0) {
               //因为我们只有两个Item的Tab,所以这个0代表的是第一个,也就是左边的Tab被选中了,
               //此时我们要更换图片和其他需要更换的东西,同理当我们选中其他的Tab也是要这么做的
                   tabBg.setBackgroundResource(R.mipmap.ic_select)
                   tabImageView.setImageResource(R.mipmap.ic_change)
                   abTextView.setTextColor(getColor(R.color.color_brand)) // 替换成选中颜色
               } else {
                   tabBg.setBackgroundResource(R.mipmap.ic_right_select)
                   tabImageView.setImageResource(R.mipmap.ic_change)
                   tabTextView.setTextColor(getColor(R.color.color_brand)) // 替换成选中颜色
               }
           }
       }
    
       //未选中的item处理
       override fun onTabUnselected(tab: TabLayout.Tab) {
           val view = tab.customView
           if (view != null) {
               val tabBg = view.findViewById<LinearLayout>(R.id.ll_bg)
               val tabImageView =
                   view.findViewById<ImageView>(R.id.iv_icon)
               val tabTextView =
                   view.findViewById<TextView>(R.id.tv_name)
               val position = tab.position
               if (position == 0) {
               //0代表第一个没有被选中
               //跟上面的处理逻辑一样
               } else {
               //跟上面的处理逻辑一样        
                         
               }
           }
       }
    
       override fun onTabReselected(tab: TabLayout.Tab) {
       // 不需要处理
       }
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
  • 相关阅读:
    CrossOver2023虚拟机软件安装双系统教程
    SqlServer 提供的数据迁移方案
    @RequestMapping注解标识的位置
    代码重构:面向单元测试
    01、RabbitMQ入门
    Python——目标检测标签中的英文名转化为对应的类别编号
    剑指 Offer 50. 第一个只出现一次的字符(Python3解法)
    Css3新布局---Grid网格
    uni-app的支付与打包上传
    一些bug总结
  • 原文地址:https://blog.csdn.net/qq_43358469/article/details/134335159