亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

TabLayout使用遇到的坑及方案

baishancloud / 633人閱讀

摘要:但對于我們的對于界面還原度要求較高,對于之間的間距也有一些要求,所以也要處理,對于間距部分的處理可以按照之前的方式通過反射來完成。注意,這種方式因為需要計算的文字寬度,所以要放到設置完所有的后調(diào)用。

修改下劃線寬度的坑

效果如下:

代碼實現(xiàn)方式:

如果想要實現(xiàn)這種效果,最主要控制的就是下劃線部分,現(xiàn)在網(wǎng)上有很多通過反射的方式來修改下劃線寬度的文章,但這段代碼如果實現(xiàn)我們想要的效果是不可能的,因為如果研究過源碼就知道Indicator的寬度跟Tab的寬度一致的,不能讓指示器的寬度小于Tab的寬度,所以我們只能另辟蹊徑:通過CustomView自己繪制線,通過添加OnTabSelectedListener來展示隱藏下劃線,讓原生的Indicaqtor高度為0也不會影響我們的展示。

OK! Talk is cheap, show me the code.

先隱藏原來的下劃線,讓其不顯示:
    
其次設置CustomView效果:

再手動控制切換時Tab的下劃線:
mTabLayout.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
            override fun onTabReselected(tab: TabLayout.Tab?) {
                val view = tab?.customView?.findViewById(R.id.tab_indicator)
                val textView = tab?.customView?.findViewById(R.id.tab_tv_date)
                textView?.setTextColor(mTabSelectedColor)
                view?.visibility = View.VISIBLE
            }

            override fun onTabUnselected(tab: TabLayout.Tab?) {
                val view = tab?.customView?.findViewById(R.id.tab_indicator)
                val textView = tab?.customView?.findViewById(R.id.tab_tv_date)
                textView?.setTextColor(mTabUnSelectedColor)
                view?.visibility = View.INVISIBLE
            }

            override fun onTabSelected(tab: TabLayout.Tab?) {
                val view = tab?.customView?.findViewById(R.id.tab_indicator)
                val textView = tab?.customView?.findViewById(R.id.tab_tv_date)
                textView?.setTextColor(mTabSelectedColor)
                view?.visibility = View.VISIBLE
            }

        })
        
間距部分

只是這樣的話,下劃線的問題解決了。但對于我們的UI對于界面還原度要求較高,對于Tab之間的間距也有一些要求,所以也要處理,對于間距部分的處理可以按照之前的方式通過反射來完成。注意,這種方式因為需要計算TextView的文字寬度,所以要放到設置完所有的customView后調(diào)用。

    private fun customTabWidth(tabLayout: TabLayout) {
        try {
            //拿到tabLayout的mTabStrip屬性
            val mTabStripField = tabLayout.javaClass.getDeclaredField("mTabStrip")
            mTabStripField.isAccessible = true

            val mTabStrip = mTabStripField.get(tabLayout) as LinearLayout

            val dp2 = DensityUtils.dp2px(context, 2f)
            val dp30 = DensityUtils.dp2px(context, 30f)


            for (i in 0 until mTabStrip.childCount) {
                // 此時獲取到tabView其實是我們的CustomView
                val tabView = mTabStrip.getChildAt(i)
                // 找到我們的TextView
                val mTextView = tabView.findViewById(R.id.tab_tv_date)

                // 測量出TextView文字的寬度
                var width = 0
                width = mTextView.width
                if (width == 0) {
                    mTextView.measure(0, 0)
                    width = mTextView.measuredWidth
                }

                // PDL = padding left    ---   PDR = padding right
                // |PDL30 CONTENT PDR30|  |PDL2 CONTENT PDR30| |PDL2 CONTENT PDR30| |PDL2 CONTENT PDR30|

                
                val params = tabView.layoutParams as LinearLayout.LayoutParams
                // 如果是第一個View,則View左側(cè)還要30dp的空間需要padding
                // 有了TextView的寬度,我們可以根據(jù)自己想要的效果去設置Tab的寬度,Tab的實際間距其實是0,但我們可以
                // 通過改變Padding的方式做出Tab間距的效果
                // 對于為什么用**padding**而不是**margin**的原因,請向下看
                if (i == 0) {
                    params.width = width + dp30 + dp30
                    tabView.layoutParams = params
                    tabView.setPadding(dp30, 0, dp30, 0)
                } else {
                    params.width = width + dp2 + dp30
                    tabView.layoutParams = params
                    tabView.setPadding(dp2, 0, dp30, 0)
                }

                tabView.invalidate()
            }
        } catch (e: NoSuchFieldException) {
            e.printStackTrace()
        } catch (e: IllegalAccessException) {
            e.printStackTrace()
        }
    }
修改完下劃線寬度后tab的滑動位置錯亂的坑(TabView的 MarginLeft & MarginRigt 導致的問題)

開始做的時候看網(wǎng)上相關的文檔然后做出的效果如下:

可以看到當滑過去以后,Tab又位移了一段距離,我想如果你的腦子沒有被踢過的話,肯定都知道滑動完位移后的位置是正確的位置,那么為什么會出現(xiàn)這種情況已經(jīng)如何解決??

看源碼!

因為是我們關聯(lián)的ViewPager滑動導致的Tab位移,那么就從ViewPager的移動時開始找線索,通過setupWithViewPager()方法中可以看到,TabLayout代碼中給ViewPager對象通過addOnPageChangeListener()方法添加了一個監(jiān)聽,那么我們看一下監(jiān)聽的回調(diào)好了!

 public static class TabLayoutOnPageChangeListener implements ViewPager.OnPageChangeListener {
        // 忽略無關代碼

        // **主要看這里哦~!~!~ **
        @Override
        public void onPageScrolled(final int position, final float positionOffset,
                final int positionOffsetPixels) {
            final TabLayout tabLayout = mTabLayoutRef.get();
            if (tabLayout != null) {
                // Only update the text selection if we"re not settling, or we are settling after
                // being dragged
                final boolean updateText = mScrollState != SCROLL_STATE_SETTLING ||
                        mPreviousScrollState == SCROLL_STATE_DRAGGING;
                // Update the indicator if we"re not settling after being idle. This is caused
                // from a setCurrentItem() call and will be handled by an animation from
                // onPageSelected() instead.
                final boolean updateIndicator = !(mScrollState == SCROLL_STATE_SETTLING
                        && mPreviousScrollState == SCROLL_STATE_IDLE);
                        // 這里調(diào)用了setScrollPosition去讓TabLayout進行滑動,穿進去目標下標和偏移量
                tabLayout.setScrollPosition(position, positionOffset, updateText, updateIndicator);
            }
        }

    }

再向下看一下setScrollPosition方法!

 void setScrollPosition(int position, float positionOffset, boolean updateSelectedText,
            boolean updateIndicatorPosition) {
        final int roundedPosition = Math.round(position + positionOffset);
        if (roundedPosition < 0 || roundedPosition >= mTabStrip.getChildCount()) {
            return;
        }

        // Set the indicator position, if enabled
        // 如果更新指示器的話那么會走進這里,我們指示器都隱藏掉了無需看這里
        if (updateIndicatorPosition) {
            mTabStrip.setIndicatorPositionFromTabPosition(position, positionOffset);
        }

        // Now update the scroll position, canceling any running animation
        if (mScrollAnimator != null && mScrollAnimator.isRunning()) {
            mScrollAnimator.cancel();
        }
        // 這里調(diào)用了scrollTo方法去移動位置,那么我們猜測應該是這個X位移距離算錯了,進去看一下
        scrollTo(calculateScrollXForTab(position, positionOffset), 0);

        
    }
    
    private int calculateScrollXForTab(int position, float positionOffset) {
        if (mMode == MODE_SCROLLABLE) {
    
            // 獲取目標的View
            final View selectedChild = mTabStrip.getChildAt(position);
            final View nextChild = position + 1 < mTabStrip.getChildCount()
                    ? mTabStrip.getChildAt(position + 1)
                    : null;
            final int selectedWidth = selectedChild != null ? selectedChild.getWidth() : 0;
            final int nextWidth = nextChild != null ? nextChild.getWidth() : 0;

            // base scroll amount: places center of tab in center of parent
            // 注意這里的,**selectedChild.getLeft()**,getLeft()是計算相對于父布局的左邊距,那么如果設置了margin的話,childView相當于父布局的位置就會變化了,那么我們?yōu)榱吮苊膺@種情況可以使用padding來改變距離,避免使原來的邏輯收到干擾。一切真想大白了!
            int scrollBase = selectedChild.getLeft() + (selectedWidth / 2) - (getWidth() / 2);
            // offset amount: fraction of the distance between centers of tabs
            int scrollOffset = (int) ((selectedWidth + nextWidth) * 0.5f * positionOffset);

            return (ViewCompat.getLayoutDirection(this) == ViewCompat.LAYOUT_DIRECTION_LTR)
                    ? scrollBase + scrollOffset
                    : scrollBase - scrollOffset;
        }
        return 0;
    }
TabLayout設置最后一個默認選中時位置錯亂

因為的TabLayout在dialog中, 而我想讓dialog展示之前就把數(shù)據(jù)設置完畢并且切換到默認的下標。

 fun showPos(index: Int) {
        mTabLayout.getTabAt(index)?.select()
        show()
    }

切換成功了,但是位置不對!

更操蛋的是將對話框dissmiss后再重新show的時候就正確了!?。ㄟ@個是最氣的

最后debug半天多終于搞定了!現(xiàn)在!讓我們回歸當出問題時的代碼(案發(fā)現(xiàn)場

    private fun customTabWidth(tabLayout: TabLayout) {
        // 嫌疑人在這里
        //        ↓
        tabLayout.post {

            try {
                //拿到tabLayout的mTabStrip屬性
                val mTabStripField = tabLayout.javaClass.getDeclaredField("mTabStrip")
                mTabStripField.isAccessible = true

                val mTabStrip = mTabStripField.get(tabLayout) as LinearLayout

                
                // balabala 修改Tab間距的代碼

                    tabView.invalidate()
                }
            } catch (e: NoSuchFieldException) {
                e.printStackTrace()
            } catch (e: IllegalAccessException) {
                e.printStackTrace()
            }

        }
    }

沒錯就是這個tabLayout.post(Runnable runnable)??!當我第一次運行的時候,TabLayout雖然已經(jīng)創(chuàng)建但是并沒有依附到任何Window中,導致runnable會被添加到運行隊列中,然后等到這個View已經(jīng)添加到Window時,再一起運行!那么會導致的現(xiàn)象就是,我第一次修改這個寬度的時候,其實并沒有真的修改,真的修改是在對話框展示后,TabLayout依附到View了,那時才會運行!所以才會出現(xiàn)第一次的位置是錯誤的,第二次的位置是正確的情況!!

關于本人使用TabLayout時的坑就介紹到這里了!希望能夠幫助的了大家??!

以上。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/74493.html

相關文章

  • ios局部滾動坑及解決方案

    摘要:起因最近幾天在寫一個滾動加載更多數(shù)據(jù)的插件,為局部滾動寫時,遇到了很多局部滾動的坑,在這里分享一下這些坑的解決方案。約定把產(chǎn)生滾動條的元素稱之為視窗全局滾動滾動條在或者父級元素上??右粸g覽器局部滾動默認沒有彈性滾動的效果。 起因 最近幾天在寫一個滾動加載更多數(shù)據(jù)的插件(Scrollload),為局部滾動寫demo時,遇到了很多局部滾動的坑,在這里分享一下這些坑的解決方案。以下的坑只針對...

    yhaolpz 評論0 收藏0
  • 事務與多線程坑及調(diào)優(yōu)Tips

    摘要:起因及介紹在處理原始對賬文件的時候,我將數(shù)據(jù)歸類后批量存入相應的表中。結(jié)論事務只能管著開啟事務的線程,其他子線程出了問題都感知不到,所以在多線程環(huán)境操作要慎重。高頻容易搞死服務器,低頻會阻塞自身程序。重試次數(shù)和超時時間根據(jù)業(yè)務情況設置。 起因及介紹 在處理原始對賬文件的時候,我將數(shù)據(jù)歸類后批量存入相應的表中。在持久化的時候,用了parallelStream(),想著同時存入很多表這樣可...

    wums 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<