The default TabLayout with mode set to scrollable gives the following:
The position of the selected tab indicator is not fixed. If the first tab is selected, tab indicator is at the left most side of the screen.
But below is the view from the Samsung Music app:
The selected tab is always at the center of the screen and the first/last items are not bound to the start/end of the screen.
Also, they have cool animation:
Things I tried: 1: I tried a few things without any knowledge like adding padding and margin to the last/first tab items. Made no changes. Also, the tab indicator is not an issue for me. I have removed it by setting transparent color and also the text size and font of the selected tab can be changed in the code in the selected and unselected callbacks.
Moreover, using this logic, I change the text of the tab item that is being used to scroll. It will not provide the effect to each of the tabs that pass through the center. ** Is there a way to get this kind of tab layout?**
Below is my experimental code with no logic, but only with a starter code with the callback event:
contentBinding.tabLayout.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
override fun onTabSelected(tab: TabLayout.Tab?) {
if (tab != null) {
Log.d("TAB_LAYOUT", "onTabSelected: "+tab.text)
//tab.view. ...
// Set huge text size and font
}
}
override fun onTabUnselected(tab: TabLayout.Tab?) {
if (tab != null) {
Log.d("TAB_LAYOUT", "onTabUnselected: "+tab.text)
//tab.view. ...
// Set normal unselected text size and font
}
}
override fun onTabReselected(tab: TabLayout.Tab?) {
if (tab != null) {
Log.d("TAB_LAYOUT", "onTabReselected: "+tab.text)
//tab.view. ...
// Set huge text size and font
}
}
})
for (i in 0..4){
val mytab = contentBinding.tabLayout.getTabAt(i)
mytab?.view?.setOnTouchListener(object : View.OnTouchListener {
override fun onTouch(v: View?, event: MotionEvent?): Boolean {
Log.d("TAB_ITEM_ALL"+i, "onTouch: "+event.toString())
if (event != null) {
if(event.action == ACTION_MOVE)
// if(event.x > prevX){
// moving away logic
// }
// else{
// moving towards
// }
return false
}
return false
}
})
}
This code is totally flawed! It is not even the recommended method, I assume!!!
Should I use animation or translation or etc?
Any kind of help will be appreciated.
So, I solved it out myself without using TabLayout. Used a HorizontalScrollview, placed TextViews in it. And managed the animation by increasing/decreasing the scale of the views as the textviews move away/closer to the center.
The pending part is to scroll them programmatically to align with center when the scroll has stopped. So that at any point of time (when not being scrolled), one of the textview has its center at the screens center.
Here is the code:
// Get the mid point of the screen
val width = Resources.getSystem().displayMetrics.widthPixels/2
// When at centre, thews will be 1.7x the original
val maxScale = 1.7f
val diffScale = maxScale - 1.0f
// Have put the text views in list, as i have to perform the same calculations for each of the textviews
val tabs = listOf(binding.textView11, binding.textView10, binding.textView9,
binding.textView8, binding.textView7, binding.textView6,
binding.textView5, binding.textView4, binding.textView3,
)
// Making a list of textview along with its width, used to calculate the center of the view
val myTabs = mutableListOf<MyTab>()
for (tab in tabs){
val newTab = MyTab()
newTab.view = tab
tab.post {
newTab.width = (tab.width.toFloat()*maxScale)/2
}
myTabs += newTab
}
binding.horizontalScrollView.isSmoothScrollingEnabled = true
// scroll change listener, to perform calculations whenever the views move
binding.horizontalScrollView.setOnScrollChangeListener(
(View.OnScrollChangeListener { v, _, _, _, _ ->
run {
for (tab in myTabs){
// get the mid point of the view = (starting loc + width/2)
val loc = IntArray(2)
tab.view.getLocationInWindow(loc)
val viewMid = loc[0] + tab.width
// logic to scale the views as the mid point moves away from the center of the screen
// max scale, when view at center = 1.7x
// min scale when view away from center = 1.0x (no scale)
val diff = abs(width-viewMid)
if(diff <= tab.width) {
val p = (diff / tab.width)
val pr = p * diffScale
val change = max(maxScale - pr, 1.0f)
tab.view.scaleX = change
tab.view.scaleY = change
}
}
}
})
)