TabLayout 另一种Tab的实现方式

               

转载于:http://blog.csdn.net/aigestudio/article/details/47155769

在5.0以前我们想要实现像网易新闻客户端那样的的Tab可以有很多种选择:

比如古老的TabHost,3.0后ActionBar所提供的Tab,以及各种成熟的Tab开源控件等,都可以直接或间接地实现Tab的效果。然而,对于这样一种使用极多的控件,Android是不会放弃将它纳入麾下的打算的,于是乎在5.0后放出的design包中Android就厚颜无耻地推出了自家官方的TabLayout控件来方便地实现类似的效果。其实这玩意跟ActionBar的Tab没什么卵的区别,只是说它更符合谷歌自家的MD设计理念,不过在实际使用中这玩意略显蛋疼,废话不多说,我们还是直接切入主题,要想使用TabLayout你就得导入Android的design包:

<code class="hljs matlab has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">dependencies <span class="hljs-cell" style="box-sizing: border-box;">{    compile <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'com.android.support:design:22.2.0'</span>}</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul>

然后在你的布局里加入TabLayout就行了:

<code class="hljs xml has-numbering" style="display:block; padding:0px; color:inherit; font-family:'Source Code Pro',monospace;font-size:undefined; white-space:pre; word-wrap:normal; background:transparent"><span class="hljs-pi" style="color:rgb(0,102,102)"><?xml version="1.0" encoding="utf-8"?></span><span class="hljs-tag" style="color:rgb(0,102,102)"><<span class="hljs-title" style="color:rgb(0,0,136)">RelativeLayout</span> <span class="hljs-attribute" style="color:rgb(102,0,102)">xmlns:android</span>=<span class="hljs-value" style="color:rgb(0,136,0)">"http://schemas.android.com/apk/res/android"</span>    <span class="hljs-attribute" style="color:rgb(102,0,102)">android:layout_width</span>=<span class="hljs-value" style="color:rgb(0,136,0)">"match_parent"</span>    <span class="hljs-attribute" style="color:rgb(102,0,102)">android:layout_height</span>=<span class="hljs-value" style="color:rgb(0,136,0)">"match_parent"</span>></span>    <span class="hljs-tag" style="color:rgb(0,102,102)"><<span class="hljs-title" style="color:rgb(0,0,136)">android.support.design.widget.TabLayout</span>        <span class="hljs-attribute" style="color:rgb(102,0,102)">android:id</span>=<span class="hljs-value" style="color:rgb(0,136,0)">"@+id/ac_tab_layout"</span>        <span class="hljs-attribute" style="color:rgb(102,0,102)">android:layout_width</span>=<span class="hljs-value" style="color:rgb(0,136,0)">"match_parent"</span>        <span class="hljs-attribute" style="color:rgb(102,0,102)">android:layout_height</span>=<span class="hljs-value" style="color:rgb(0,136,0)">"wrap_content"</span> /></span><span class="hljs-tag" style="color:rgb(0,102,102)"></<span class="hljs-title" style="color:rgb(0,0,136)">RelativeLayout</span>></span></code><ul class="pre-numbering" style="position:absolute; width:50px; top:0px; left:0px; margin:0px; padding:6px 0px 40px; border-right-width:1px; border-right-style:solid; border-right-color:rgb(221,221,221); list-style:none; text-align:right; background-color:rgb(238,238,238)"><li style="padding:0px 5px">1</li><li style="padding:0px 5px">2</li><li style="padding:0px 5px">3</li><li style="padding:0px 5px">4</li><li style="padding:0px 5px">5</li><li style="padding:0px 5px">6</li><li style="padding:0px 5px">7</li><li style="padding:0px 5px">8</li><li style="padding:0px 5px">9</li><li style="padding:0px 5px">10</li><li style="padding:0px 5px">11</li></ul>

这里需要注意的是design包中有些资源依赖于5.0,这是不是说我们就不能使用了呢,不是的,我们可以从AppCompat获得这些资源,将当前Activity的主题设置为Theme.AppCompat或其子类即可:

<code class="hljs xml has-numbering" style="display:block; padding:0px; color:inherit; font-family:'Source Code Pro',monospace;font-size:undefined; white-space:pre; word-wrap:normal; background:transparent"><span class="hljs-tag" style="color:rgb(0,102,102)"><<span class="hljs-title" style="color:rgb(0,0,136)">activity</span>    <span class="hljs-attribute" style="color:rgb(102,0,102)">android:name</span>=<span class="hljs-value" style="color:rgb(0,136,0)">"tablayout.TabLayoutActivity"</span>    <span class="hljs-attribute" style="color:rgb(102,0,102)">android:theme</span>=<span class="hljs-value" style="color:rgb(0,136,0)">"@style/Theme.AppCompat"</span> /></span></code><ul class="pre-numbering" style="position:absolute; width:50px; top:0px; left:0px; margin:0px; padding:6px 0px 40px; border-right-width:1px; border-right-style:solid; border-right-color:rgb(221,221,221); list-style:none; text-align:right; background-color:rgb(238,238,238)"><li style="padding:0px 5px">1</li><li style="padding:0px 5px">2</li><li style="padding:0px 5px">3</li></ul>

当然现在你运行不会看到任何东西,因为我们没往里面家东西嘛,与ActionBar类似的是TabLayout添加Tab也很方便,只需要调用其addTab方法即可:

<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">TabLayoutActivity</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">extends</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">Activity</span> {</span>    <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">protected</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">onCreate</span>(Bundle savedInstanceState) {        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">super</span>.onCreate(savedInstanceState);        setContentView(R.layout.ac_tab_layout);        TabLayout tabLayout = (TabLayout) findViewById(R.id.ac_tab_layout);        TabLayout.Tab tab1 = tabLayout.newTab().setText(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Tab1"</span>);        tabLayout.addTab(tab1);        TabLayout.Tab tab2 = tabLayout.newTab().setText(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Tab2"</span>);        tabLayout.addTab(tab2);        TabLayout.Tab tab3 = tabLayout.newTab().setText(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Tab3"</span>);        tabLayout.addTab(tab3);    }}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li></ul>

运行效果如下:

非常简单,不过需要注意的是,这里的Tab类是TabLayout的一个静态内部类,并且其构造方法是包内可访问的,也就是说你无法在外部构造其实例,只能通过TabLayout的newTab方法:

<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">TabLayout</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">extends</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">HorizontalScrollView</span> {</span>    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// ......省去很多代码......</span>    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">Tab</span> {</span>        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// ......省去很多代码......</span>        Tab(TabLayout parent) {            mPosition = -<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>;            mParent = parent;        }    }    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> Tab <span class="hljs-title" style="box-sizing: border-box;">newTab</span>() {        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Tab(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>);    }    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// ......省去很多代码......</span>}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li></ul>

addTab方法有四个不同的实现,拿参数最多的addTab(Tab tab, int position, boolean setSelected)方法来说,第一个参数tab就不说了,第二个参数position表示当前Tab需要插入的位置,其值必须小于当前TabLayout所拥有的Tab总数减一,如果大于则会报出数组下标溢出异常,这点很好理解,最后的boolean参数setSelected与其名意义一样,表示当前添加的Tab是否为选中状态,拿上面代码中的第三个tab3来说,我们修改其代码如下:

<code class="hljs avrasm has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">TabLayout<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Tab</span> tab3 = tabLayout<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.newTab</span>()<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.setText</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Tab3"</span>)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>tabLayout<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.addTab</span>(tab3, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>, true)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul>

运行后tab3默认就会是被选中状态:

TabLayout中的公共方法不算多,大多都很好理解,不过有一个方法爱哥表示对其极度不爽,setScrollPosition从名字上来看它是用来设置滚动位置的,大家注意我们的TabLayout中被选中的Tab下方不是有根线么,我们可以通过这个方法来设置它的位置。首先我们在布局中添加一个按钮:

<code class="hljs xml has-numbering" style="display:block; padding:0px; color:inherit; font-family:'Source Code Pro',monospace;font-size:undefined; white-space:pre; word-wrap:normal; background:transparent"><span class="hljs-pi" style="color:rgb(0,102,102)"><?xml version="1.0" encoding="utf-8"?></span><span class="hljs-tag" style="color:rgb(0,102,102)"><<span class="hljs-title" style="color:rgb(0,0,136)">RelativeLayout</span> <span class="hljs-attribute" style="color:rgb(102,0,102)">xmlns:android</span>=<span class="hljs-value" style="color:rgb(0,136,0)">"http://schemas.android.com/apk/res/android"</span>    <span class="hljs-attribute" style="color:rgb(102,0,102)">android:layout_width</span>=<span class="hljs-value" style="color:rgb(0,136,0)">"match_parent"</span>    <span class="hljs-attribute" style="color:rgb(102,0,102)">android:layout_height</span>=<span class="hljs-value" style="color:rgb(0,136,0)">"match_parent"</span>></span>    <span class="hljs-tag" style="color:rgb(0,102,102)"><<span class="hljs-title" style="color:rgb(0,0,136)">android.support.design.widget.TabLayout</span>        <span class="hljs-attribute" style="color:rgb(102,0,102)">android:id</span>=<span class="hljs-value" style="color:rgb(0,136,0)">"@+id/ac_tab_layout"</span>        <span class="hljs-attribute" style="color:rgb(102,0,102)">android:layout_width</span>=<span class="hljs-value" style="color:rgb(0,136,0)">"match_parent"</span>        <span class="hljs-attribute" style="color:rgb(102,0,102)">android:layout_height</span>=<span class="hljs-value" style="color:rgb(0,136,0)">"wrap_content"</span> /></span>    <span class="hljs-tag" style="color:rgb(0,102,102)"><<span class="hljs-title" style="color:rgb(0,0,136)">Button</span>        <span class="hljs-attribute" style="color:rgb(102,0,102)">android:id</span>=<span class="hljs-value" style="color:rgb(0,136,0)">"@+id/ac_tab_btn"</span>        <span class="hljs-attribute" style="color:rgb(102,0,102)">android:layout_width</span>=<span class="hljs-value" style="color:rgb(0,136,0)">"wrap_content"</span>        <span class="hljs-attribute" style="color:rgb(102,0,102)">android:layout_centerInParent</span>=<span class="hljs-value" style="color:rgb(0,136,0)">"true"</span>        <span class="hljs-attribute" style="color:rgb(102,0,102)">android:layout_height</span>=<span class="hljs-value" style="color:rgb(0,136,0)">"wrap_content"</span>        <span class="hljs-attribute" style="color:rgb(102,0,102)">android:text</span>=<span class="hljs-value" style="color:rgb(0,136,0)">"Move"</span> /></span><span class="hljs-tag" style="color:rgb(0,102,102)"></<span class="hljs-title" style="color:rgb(0,0,136)">RelativeLayout</span>></span></code><ul class="pre-numbering" style="position:absolute; width:50px; top:0px; left:0px; margin:0px; padding:6px 0px 40px; border-right-width:1px; border-right-style:solid; border-right-color:rgb(221,221,221); list-style:none; text-align:right; background-color:rgb(238,238,238)"><li style="padding:0px 5px">1</li><li style="padding:0px 5px">2</li><li style="padding:0px 5px">3</li><li style="padding:0px 5px">4</li><li style="padding:0px 5px">5</li><li style="padding:0px 5px">6</li><li style="padding:0px 5px">7</li><li style="padding:0px 5px">8</li><li style="padding:0px 5px">9</li><li style="padding:0px 5px">10</li><li style="padding:0px 5px">11</li><li style="padding:0px 5px">12</li><li style="padding:0px 5px">13</li><li style="padding:0px 5px">14</li><li style="padding:0px 5px">15</li><li style="padding:0px 5px">16</li><li style="padding:0px 5px">17</li></ul>

然后呢为这个按钮绑定一个点击事件监听并在其中调用setScrollPosition方法:

<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">Button btnAdd = (Button) findViewById(R.id.ac_tab_btn);btnAdd.setOnClickListener(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> View.OnClickListener() {    <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">onClick</span>(View v) {        tabLayout.setScrollPosition(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0.5</span>F, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">false</span>);    }});</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li></ul>

setScrollPosition方法的三个参数根据官方文档给出的解释如下:

第一个参数表示当前Tab的位置,第二个参数是偏移值,从文档中看到该值的取值范围是0到1的一个半开区间,最后一个参数很好理解表示是否置移动后位置所对应的Tab为选中状态,打个比方,如果我从0移动到1的位置,如果updateSelectedText为true,那么1这个位置上的文本就会是一个选中状态。上面的代码中我们只是简单地让下方的横条从0的Tab位置移动到一个0.5F的位置,效果如下:

可能大家会觉得纳闷,这个0.5F是个吊毛意思,其实positionOffset这个参数是一个倍数值,它的计算逻辑有些复杂,从源码中看setScrollPosition的逻辑,大致分为两步:

<code class="hljs java has-numbering" style="display:block; padding:0px; color:inherit; font-family:'Source Code Pro',monospace;font-size:undefined; white-space:pre; word-wrap:normal; background:transparent"><span class="hljs-keyword" style="color:rgb(0,0,136)">public</span> <span class="hljs-keyword" style="color:rgb(0,0,136)">void</span> <span class="hljs-title" style="">setScrollPosition</span>(<span class="hljs-keyword" style="color:rgb(0,0,136)">int</span> position, <span class="hljs-keyword" style="color:rgb(0,0,136)">float</span> positionOffset, <span class="hljs-keyword" style="color:rgb(0,0,136)">boolean</span> updateSelectedText) {    <span class="hljs-keyword" style="color:rgb(0,0,136)">if</span> (isAnimationRunning(getAnimation()))        <span class="hljs-keyword" style="color:rgb(0,0,136)">return</span>;    <span class="hljs-keyword" style="color:rgb(0,0,136)">if</span> (position < <span class="hljs-number" style="color:rgb(0,102,102)">0</span> || position >= mTabStrip.getChildCount())        <span class="hljs-keyword" style="color:rgb(0,0,136)">return</span>;    mTabStrip.setIndicatorPositionFromTabPosition(position, positionOffset);    scrollTo(calculateScrollXForTab(position, positionOffset), <span class="hljs-number" style="color:rgb(0,102,102)">0</span>);    <span class="hljs-keyword" style="color:rgb(0,0,136)">if</span> (updateSelectedText)        setSelectedTabView(Math.round((<span class="hljs-keyword" style="color:rgb(0,0,136)">float</span>) position + positionOffset));}</code><ul class="pre-numbering" style="position:absolute; width:50px; top:0px; left:0px; margin:0px; padding:6px 0px 40px; border-right-width:1px; border-right-style:solid; border-right-color:rgb(221,221,221); list-style:none; text-align:right; background-color:rgb(238,238,238)"><li style="padding:0px 5px">1</li><li style="padding:0px 5px">2</li><li style="padding:0px 5px">3</li><li style="padding:0px 5px">4</li><li style="padding:0px 5px">5</li><li style="padding:0px 5px">6</li><li style="padding:0px 5px">7</li><li style="padding:0px 5px">8</li><li style="padding:0px 5px">9</li><li style="padding:0px 5px">10</li></ul>

首先是

<code class="hljs avrasm has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">mTabStrip<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.setIndicatorPositionFromTabPosition</span>(position, positionOffset)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>

这段的调用,其目的很简单,就是设置Tab下方的那个横条的位置,先是调用SlidingTabStrip的setIndicatorPositionFromTabPosition方法赋值:

<code class="hljs cs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> setIndicatorPositionFromTabPosition(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> position, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">float</span> positionOffset) {    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (TabLayout.isAnimationRunning(getAnimation())) {        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span>;    } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> {        mSelectedPosition = position;        mSelectionOffset = positionOffset;        updateIndicatorPosition();        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span>;    }}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li></ul>

然后又调用了updateIndicatorPosition来做具体的位置更新操作:

<code class="hljs vbscript has-numbering" style="display:block; padding:0px; color:inherit; font-family:'Source Code Pro',monospace;font-size:undefined; white-space:pre; word-wrap:normal; background:transparent"><span class="hljs-keyword" style="color:rgb(0,0,136)">private</span> void updateIndicatorPosition() {    View selectedTitle = getChildAt(mSelectedPosition);    <span class="hljs-built_in" style="color:rgb(102,0,102)">int</span> <span class="hljs-built_in" style="color:rgb(102,0,102)">left</span>;    <span class="hljs-built_in" style="color:rgb(102,0,102)">int</span> <span class="hljs-built_in" style="color:rgb(102,0,102)">right</span>;    <span class="hljs-keyword" style="color:rgb(0,0,136)">if</span> (selectedTitle != <span class="hljs-literal" style="color:rgb(0,102,102)">null</span> && selectedTitle.getWidth() > <span class="hljs-number" style="color:rgb(0,102,102)">0</span>) {        <span class="hljs-built_in" style="color:rgb(102,0,102)">left</span> = selectedTitle.getLeft();        <span class="hljs-built_in" style="color:rgb(102,0,102)">right</span> = selectedTitle.getRight();        <span class="hljs-keyword" style="color:rgb(0,0,136)">if</span> (mSelectionOffset > <span class="hljs-number" style="color:rgb(0,102,102)">0.0</span>F && mSelectedPosition < getChildCount() - <span class="hljs-number" style="color:rgb(0,102,102)">1</span>) {            View nextTitle = getChildAt(mSelectedPosition + <span class="hljs-number" style="color:rgb(0,102,102)">1</span>);            <span class="hljs-built_in" style="color:rgb(102,0,102)">left</span> = (<span class="hljs-built_in" style="color:rgb(102,0,102)">int</span>) (mSelectionOffset * (float) nextTitle.getLeft() + (<span class="hljs-number" style="color:rgb(0,102,102)">1.0</span>F - mSelectionOffset) * (float) <span class="hljs-built_in" style="color:rgb(102,0,102)">left</span>);            <span class="hljs-built_in" style="color:rgb(102,0,102)">right</span> = (<span class="hljs-built_in" style="color:rgb(102,0,102)">int</span>) (mSelectionOffset * (float) nextTitle.getRight() + (<span class="hljs-number" style="color:rgb(0,102,102)">1.0</span>F - mSelectionOffset) * (float) <span class="hljs-built_in" style="color:rgb(102,0,102)">right</span>);        }    } <span class="hljs-keyword" style="color:rgb(0,0,136)">else</span> {        <span class="hljs-built_in" style="color:rgb(102,0,102)">left</span> = <span class="hljs-built_in" style="color:rgb(102,0,102)">right</span> = -<span class="hljs-number" style="color:rgb(0,102,102)">1</span>;    }    setIndicatorPosition(<span class="hljs-built_in" style="color:rgb(102,0,102)">left</span>, <span class="hljs-built_in" style="color:rgb(102,0,102)">right</span>);}</code><ul class="pre-numbering" style="position:absolute; width:50px; top:0px; left:0px; margin:0px; padding:6px 0px 40px; border-right-width:1px; border-right-style:solid; border-right-color:rgb(221,221,221); list-style:none; text-align:right; background-color:rgb(238,238,238)"><li style="padding:0px 5px">1</li><li style="padding:0px 5px">2</li><li style="padding:0px 5px">3</li><li style="padding:0px 5px">4</li><li style="padding:0px 5px">5</li><li style="padding:0px 5px">6</li><li style="padding:0px 5px">7</li><li style="padding:0px 5px">8</li><li style="padding:0px 5px">9</li><li style="padding:0px 5px">10</li><li style="padding:0px 5px">11</li><li style="padding:0px 5px">12</li><li style="padding:0px 5px">13</li><li style="padding:0px 5px">14</li><li style="padding:0px 5px">15</li><li style="padding:0px 5px">16</li><li style="padding:0px 5px">17</li></ul>

首先是得到当前Tab左右的坐标值,然后尝试获取下一个Tab,如果有,那么根据相对位置计算最终的左右坐标,没有则不改变使用当前的左右坐标,这很好理解,最后通过setIndicatorPosition放啊分设置最终的横条位置:

<code class="hljs vbscript has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> void setIndicatorPosition(<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">int</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">left</span>, <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">int</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">right</span>) {    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">left</span> != mIndicatorLeft || <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">right</span> != mIndicatorRight) {        mIndicatorLeft = <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">left</span>;        mIndicatorRight = <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">right</span>;        ViewCompat.postInvalidateOnAnimation(this);    }}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li></ul>

回到setScrollPosition方法中再看看第二步滚动TabLayout到指定位置:

<code class="hljs scss has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-function" style="box-sizing: border-box;">scrollTo(<span class="hljs-function" style="box-sizing: border-box;">calculateScrollXForTab(position, positionOffset)</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>)</span>;</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>

这一步在默认模式下不会被执行,TabLayout提供两种模式,一种是填充模式,也就是默认模式,表示TabLayout不可滚动,其宽度有一个最大值,所有的Tab则会挤在这个宽度中:

该模式的常量值为MODE_FIXED = 1,而我们可以通过TabLayout的setTabMode方法来设置其模式,这里我们将TabLayout的模式改为可滚动:

<code class="hljs avrasm has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">tabLayout<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.setTabMode</span>(TabLayout<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.MODE</span>_SCROLLABLE)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>

TabLayout.MODE_SCROLLABLE的常量值为0,这时候再看看效果:

这时候TabLayout变为可滚动而所有的Tab均显示完整。好我们现在回过头来看看

<code class="hljs scss has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-function" style="box-sizing: border-box;">scrollTo(<span class="hljs-function" style="box-sizing: border-box;">calculateScrollXForTab(position, positionOffset)</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>)</span>;</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>

这段代码,scrollTo这个方法相信大家做过滑动都不会太陌生,其会将当前视图滚动至指定的坐标位置,TabLayout是一个水平滚动视图,因此其Y坐标滚动至恒为0,而X坐标则通过calculateScrollXForTab这个方法来计算:

<code class="hljs cs has-numbering" style="display:block; padding:0px; color:inherit; font-family:'Source Code Pro',monospace;font-size:undefined; white-space:pre; word-wrap:normal; background:transparent"><span class="hljs-keyword" style="color:rgb(0,0,136)">private</span> <span class="hljs-keyword" style="color:rgb(0,0,136)">int</span> <span class="hljs-title" style="">calculateScrollXForTab</span>(<span class="hljs-keyword" style="color:rgb(0,0,136)">int</span> position, <span class="hljs-keyword" style="color:rgb(0,0,136)">float</span> positionOffset) {    <span class="hljs-keyword" style="color:rgb(0,0,136)">if</span> (mMode == <span class="hljs-number" style="color:rgb(0,102,102)">0</span>) {        View selectedChild = mTabStrip.getChildAt(position);        View nextChild = position + <span class="hljs-number" style="color:rgb(0,102,102)">1</span> >= mTabStrip.getChildCount() ? <span class="hljs-keyword" style="color:rgb(0,0,136)">null</span> : mTabStrip.getChildAt(position + <span class="hljs-number" style="color:rgb(0,102,102)">1</span>);        <span class="hljs-keyword" style="color:rgb(0,0,136)">int</span> selectedWidth = selectedChild == <span class="hljs-keyword" style="color:rgb(0,0,136)">null</span> ? <span class="hljs-number" style="color:rgb(0,102,102)">0</span> : selectedChild.getWidth();        <span class="hljs-keyword" style="color:rgb(0,0,136)">int</span> nextWidth = nextChild == <span class="hljs-keyword" style="color:rgb(0,0,136)">null</span> ? <span class="hljs-number" style="color:rgb(0,102,102)">0</span> : nextChild.getWidth();        <span class="hljs-keyword" style="color:rgb(0,0,136)">return</span> (<span class="hljs-keyword" style="color:rgb(0,0,136)">int</span>) (((<span class="hljs-keyword" style="color:rgb(0,0,136)">float</span>) selectedChild.getLeft() + (<span class="hljs-keyword" style="color:rgb(0,0,136)">float</span>) (selectedWidth + nextWidth) * positionOffset * <span class="hljs-number" style="color:rgb(0,102,102)">0.5</span>F + (<span class="hljs-keyword" style="color:rgb(0,0,136)">float</span>) selectedChild.getWidth() * <span class="hljs-number" style="color:rgb(0,102,102)">0.5</span>F) - (<span class="hljs-keyword" style="color:rgb(0,0,136)">float</span>) getWidth() * <span class="hljs-number" style="color:rgb(0,102,102)">0.5</span>F);    } <span class="hljs-keyword" style="color:rgb(0,0,136)">else</span> {        <span class="hljs-keyword" style="color:rgb(0,0,136)">return</span> <span class="hljs-number" style="color:rgb(0,102,102)">0</span>;    }}</code><ul class="pre-numbering" style="position:absolute; width:50px; top:0px; left:0px; margin:0px; padding:6px 0px 40px; border-right-width:1px; border-right-style:solid; border-right-color:rgb(221,221,221); list-style:none; text-align:right; background-color:rgb(238,238,238)"><li style="padding:0px 5px">1</li><li style="padding:0px 5px">2</li><li style="padding:0px 5px">3</li><li style="padding:0px 5px">4</li><li style="padding:0px 5px">5</li><li style="padding:0px 5px">6</li><li style="padding:0px 5px">7</li><li style="padding:0px 5px">8</li><li style="padding:0px 5px">9</li><li style="padding:0px 5px">10</li><li style="padding:0px 5px">11</li></ul>

这里可以看到先做了一个判断,如果模式为填充也就是MODE_FIXED的情况下是不需要滚动的,只有当模式为MODE_SCROLLABLE时才会去滚动,X坐标的计算逻辑与updateIndicatorPosition方法中的计算逻辑类似,都是通过当前Tab与下一个Tab的相对关系来计算的。那么为什么爱哥会对setScrollPosition这个方法表示极度不爽呢?首先,这个方法调用的前提根据官方文档和源码来看是需要相邻的两个Tab共同计算的,打个比方,如果我想从第0个Tab跳转至第1个Tab那么我就可以这么干:

<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">TabLayoutActivity</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">extends</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">Activity</span> {</span>    <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">protected</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">onCreate</span>(Bundle savedInstanceState) {        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">super</span>.onCreate(savedInstanceState);        setContentView(R.layout.ac_tab_layout);        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> TabLayout tabLayout = (TabLayout) findViewById(R.id.ac_tab_layout);        TabLayout.Tab tab1 = tabLayout.newTab().setText(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Tab1"</span>);        tabLayout.addTab(tab1);        TabLayout.Tab tab2 = tabLayout.newTab().setText(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Tab2"</span>);        tabLayout.addTab(tab2);        TabLayout.Tab tab3 = tabLayout.newTab().setText(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Tab3"</span>);        tabLayout.addTab(tab3);        tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);        Button btnAdd = (Button) findViewById(R.id.ac_tab_btn);        btnAdd.setOnClickListener(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> View.OnClickListener() {            <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">onClick</span>(View v) {                tabLayout.setScrollPosition(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>F, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">true</span>);        });    }}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li></ul>

从第0个Tab开始,偏移值为一个单位,效果如下:

注意到这里的一个BUG没有,淡定,好戏在后头,大家想想虽说官方文档建议第二个参数的取值区间在0到1,但是我们完全可以考虑将该值设置大于1对吧,假设,仅仅是个假设,我们将其设为2,那么是否可以表示我们能直接从第0个Tab直接跳转到第2个Tab呢?答案好像是肯定的:

<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">btnAdd.setOnClickListener(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> View.OnClickListener() {    <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">onClick</span>(View v) {        tabLayout.setScrollPosition(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>F, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">true</span>);});</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li></ul>

运行效果如下:

是不是有点意外?但是注意,这种想法是错误的!!!这里之所以能够直接跳转到第2个Tab是因为在这个例子中我们的每个Tab宽度都是一样的,如果我们将Tab稍作修改:

<code class="hljs avrasm has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">TabLayout<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Tab</span> tab1 = tabLayout<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.newTab</span>()<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.setText</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Aige"</span>)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>tabLayout<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.addTab</span>(tab1)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>TabLayout<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Tab</span> tab2 = tabLayout<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.newTab</span>()<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.setText</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"AigeStudio"</span>)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>tabLayout<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.addTab</span>(tab2)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>TabLayout<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Tab</span> tab3 = tabLayout<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.newTab</span>()<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.setText</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Studio"</span>)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>tabLayout<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.addTab</span>(tab3)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li></ul>

这时候你就会看到错误的计算显示了:

当然如果仅仅是相邻的滚动,这样做是没问题的,比如我们从第1个Tab滚动至第2个Tab:

<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">TabLayoutActivity</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">extends</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">Activity</span> {</span>    <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">protected</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">onCreate</span>(Bundle savedInstanceState) {        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">super</span>.onCreate(savedInstanceState);        setContentView(R.layout.ac_tab_layout);        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> TabLayout tabLayout = (TabLayout) findViewById(R.id.ac_tab_layout);        TabLayout.Tab tab1 = tabLayout.newTab().setText(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Aige"</span>);        tabLayout.addTab(tab1);        TabLayout.Tab tab2 = tabLayout.newTab().setText(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"AigeStudio"</span>);        tabLayout.addTab(tab2, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">true</span>);        TabLayout.Tab tab3 = tabLayout.newTab().setText(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Studio"</span>);        tabLayout.addTab(tab3);        tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);        Button btnAdd = (Button) findViewById(R.id.ac_tab_btn);        btnAdd.setOnClickListener(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> View.OnClickListener() {            <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">onClick</span>(View v) {                tabLayout.setScrollPosition(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>F, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">true</span>);            }        });    }}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li></ul>

这样就没问题:

使用setScrollPosition的另一个问题是,滚动时Tab底部那个横条切换生硬,不知道大家注意到没,没注意到往上看之前的一些切换动图,非常生硬,然而如果我们用另外一种方式来做这种切换就显得很带感了,Tab类中提供了一个select方法来设置当前Tab被选中:

<code class="hljs cs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> final <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> Tab {    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// ......省去很多代码......</span>    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">select</span>() {        mParent.selectTab(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>);    }    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// ......省去很多代码......</span>}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li></ul>

这个方法所带来的效果就很不一样了,比如我们点击设置第三个Tab被选中:

<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">TabLayoutActivity</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">extends</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">Activity</span> {</span>    <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">protected</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">onCreate</span>(Bundle savedInstanceState) {        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">super</span>.onCreate(savedInstanceState);        setContentView(R.layout.ac_tab_layout);        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> TabLayout tabLayout = (TabLayout) findViewById(R.id.ac_tab_layout);        TabLayout.Tab tab1 = tabLayout.newTab().setText(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Aige"</span>);        tabLayout.addTab(tab1);        TabLayout.Tab tab2 = tabLayout.newTab().setText(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"AigeStudio"</span>);        tabLayout.addTab(tab2);        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> TabLayout.Tab tab3 = tabLayout.newTab().setText(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Studio"</span>);        tabLayout.addTab(tab3);        tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);        Button btnAdd = (Button) findViewById(R.id.ac_tab_btn);        btnAdd.setOnClickListener(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> View.OnClickListener() {            <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">onClick</span>(View v) {                tab3.select();            }        });    }}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li></ul>

效果是不是要动感的多呢:

从源码里可以看到select方法本质是调用了TabLayout中的selectTab方法:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值