[Android] TabLayout settings use custom styles to display images

Preface

TabLayout is often used in combination with ViewPager2 to create multiple Fragment switching page effects.
The display effect we often see in TabLayout is the text above and a line segment below, which can be seen in major browsers/news APPs. This effect can also be achieved with TabLayout configuration parameters. But we want to achieve this effect
Insert image description here
We have two Tabs, the left one and the right one. After selecting the left one, the left one will be orange, and then the arrow points to the right. When the right one is selected, the right one will become Orange, then the arrow points to the left.

This requires configuring TabLayout.

accomplish

First, the configuration of Tablayout in 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" />

Among them this one

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

It's because Tab itself has default Padding, so that our picture can fill the space of TabLayout.

Insert image description here
Insert image description here

Then we need to prepare this kind of picture and put it in the project
The next step is a very normal operation, create an Adapter that inherits FragmentStateAdapter, and then add content to it

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
    }
}

The view_layout file inside

<?xml version="1.0" encoding="utf-8"?>
<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>

Note: When setting the height of the Tab, sometimes due to system problems, the Tab image we set cannot fill the space of the TabLayout. The solution is mentioned above. If the left and right cannot be filled, use this method to solve it. Add in TabLayout

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

This is mentioned above, but if the top and bottom are not full, this setting cannot be used.
We need to set the TabLayout when
1. Setting TabLayout's top and bottom height

   android:layout_height="wrap_content"

2. When setting the xml file of each of our Tabs, set the height in the view_layout file above, but do not set the height in the parent View. Just like in the view_layout above, the parent View is a LinearLayout, and the height of the LinearLayout cannot be set. What we need is to set it to

  android:layout_height="wrap_content"

Then in the sub-View inside, set a certain height to the height we need to support this layout. For example, we set the height of TextView to 48dp, which is also the height of TabLayout we need. In this way, our Tab The problem is that the picture cannot fill the space of TabLayout in the upper and lower directions.

Then we can use it in 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))

In this way, we have successfully bound TabLayout and ViewPager2, but when we select Tab, we still need to change the corresponding background and picture according to the selected Tab.
We want to monitor this 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) {
    
    
   // 不需要处理
   }
})

Guess you like

Origin blog.csdn.net/qq_43358469/article/details/134335159