Android自定義超級(jí)炫酷的ViewPage指示器
思路
其實(shí)主要的內(nèi)容就是自定義一個(gè)帶顏色漸變的一個(gè)TextView,需要定義兩個(gè)畫筆,一個(gè)負(fù)責(zé)繪制未選中顏色,一個(gè)負(fù)責(zé)繪制選中時(shí)的顏色,各自繪制各自的區(qū)域就能繪制出一個(gè)帶顏色漸變的TextView
然后外部再包裝一層LinearLayout,水平排放每個(gè)tab,再監(jiān)聽Viewpage的滑動(dòng),根據(jù)滑動(dòng)百分比來改變TextView的選中以及未選中區(qū)域的大小三,代碼實(shí)現(xiàn)
難點(diǎn)
繪制漸變色的TextView其實(shí)最重要的還是計(jì)算基線的位置,基線位置計(jì)算出來,那么就能調(diào)用drawText()方法去繪制我們的文本了,基線計(jì)算方式參考文末
代碼實(shí)現(xiàn)漸變TextView
@RequiresApi(Build.VERSION_CODES.Q) class CustomTextView : AppCompatTextView { /** * 未選中畫筆 */ private var mUnSelectPaint: Paint? = null /** * 選中畫筆 */ private var mSelectPaint: Paint? = null /** * 滑動(dòng)進(jìn)度百分比 */ var mScrollProcess = 0f /** * 是否左邊滑動(dòng) */ var mScrollToLeft = true /** * 文字縮放比例 */ var mTextScale = 0.7f /** * 選中顏色以及未選中顏色 */ private var mSelectColor = Color.parseColor("#8966FF") private var mUnSelectColor = Color.parseColor("#DBC0FF") constructor(context: Context) : this(context, null) constructor(context: Context, attributeSet: AttributeSet?) : this(context, attributeSet, 0) constructor(context: Context, attributeSet: AttributeSet?, defStyleAttr: Int) : super( context, attributeSet, defStyleAttr ) { //初始化畫筆 mUnSelectPaint = Paint() mUnSelectPaint?.apply { color = mUnSelectColor textSize = this@CustomTextView.textSize isAntiAlias = true isDither = true } mSelectPaint = Paint() mSelectPaint?.apply { color = mSelectColor textSize = this@CustomTextView.textSize isAntiAlias = true isDither = true } } /** * 繪制內(nèi)容 */ override fun onDraw(canvas: Canvas?) { val x = width * mScrollProcess if (mScrollToLeft) { drawText(canvas!!, mUnSelectPaint!!, x, width.toFloat()) drawText(canvas!!, mSelectPaint!!, 0f, x) } else { drawText(canvas!!, mUnSelectPaint!!, 0f, width - x) drawText(canvas!!, mSelectPaint!!, width - x, width.toFloat()) } } /** * 繪制文字 */ private fun drawText(canvas: Canvas, paint: Paint, startX: Float, endX: Float) { paint.textSize = textSize * mTextScale //保存畫布,剪切畫布(設(shè)置畫布顯示區(qū)域) canvas.save() canvas.clipRect(startX, 0f, endX, height.toFloat()) //獲取文字矩形區(qū)域 var bounds = Rect() paint.getTextBounds(text, 0, text.length, bounds) //獲取文字的度量指標(biāo) val fontMetrics = paint.fontMetrics //計(jì)算基線到中心點(diǎn)位置 val dy = (fontMetrics.bottom - fontMetrics.top) / 2 - fontMetrics.bottom //計(jì)算基線 val baseLine = height / 2 + dy //繪制文字 canvas.drawText( text.toString(), (width / 2 - bounds.width() / 2).toFloat(), baseLine, paint ) canvas.restore() } /** * 設(shè)置選中 未選中顏色 */ fun setColor(selectColor: Int, unSelectColor: Int) { mSelectColor = selectColor mUnSelectColor = unSelectColor mSelectPaint?.color = selectColor mUnSelectPaint?.color = unSelectColor invalidate() } }
1,在構(gòu)造方法中初始化兩支畫筆,分別用于繪制未選中區(qū)域和選中區(qū)域
2,在onDraw()方法中根據(jù)滑動(dòng)百分計(jì)算出繪制區(qū)域的寬度
3,判斷滑動(dòng)方向
4,開始繪制文本
- 設(shè)置畫筆的文字大小(文字大小 * 縮放比例)
- 保存畫布,并根據(jù)計(jì)算出來的繪制區(qū)域的開始坐標(biāo)和結(jié)束坐標(biāo)剪切畫布,這是整個(gè)繪制核心,一旦剪切等下調(diào)用darwText()方法就只會(huì)繪制剪切的這部分
- 獲取文字矩形區(qū)域,通過調(diào)用paint.getTextBounds()這個(gè)方法就能拿到我們繪制文本的區(qū)域
- 獲取文字的度量指標(biāo),計(jì)算出基線的位置
- 調(diào)用畫布的drawText()去繪制我們的文本
5,效果如下,對(duì)算法不理解的需要自行去搜索getTextBounds(),getFontMetrics()這兩個(gè)方法的作用及其屬性變量的作用,到這里,一個(gè)漸變色的TextView就出來了,最后容我埋下一個(gè)bug
代碼實(shí)現(xiàn)指示器
@RequiresApi(Build.VERSION_CODES.Q) class MyIndicator : LinearLayout, ViewPager.OnPageChangeListener { var mTextScale = 0.7f constructor(context: Context) : this(context, null) constructor(context: Context, attributeSet: AttributeSet?) : this(context, attributeSet, 0) constructor(context: Context, attributeSet: AttributeSet?, defStyleAttr: Int) : super( context, attributeSet, defStyleAttr ) /** * 添加多個(gè)tab */ fun addTabs(texts: List<String>) { texts.forEach { addTab(it) } //選中第一個(gè) val customTextView = getChildAt(0) as CustomTextView customTextView.mScrollToLeft = false customTextView.mScrollProcess = 1f customTextView.mTextScale = 1f customTextView.invalidate() } /** * 添加tab */ fun addTab(text: String) { val layoutParams = LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT) layoutParams.weight = 1f val customTextView = CustomTextView(context) customTextView.textSize = 21f customTextView.gravity = Gravity.CENTER customTextView.text = text customTextView.mScrollProcess = 0f customTextView.mTextScale = 0.7f customTextView.layoutParams = layoutParams addView(customTextView) } /** * 關(guān)聯(lián)ViewPage */ fun relationViewPage(viewPage: ViewPager) { viewPage.addOnPageChangeListener(this) } /** * 滑動(dòng)回調(diào) */ override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) { if (positionOffset > 0) { val tabView = getChildAt(position) as CustomTextView tabView.mScrollToLeft = false tabView.mScrollProcess = 1 - positionOffset tabView.mTextScale = if ((1 - positionOffset) > mTextScale) 1 - positionOffset else mTextScale tabView.invalidate() val rightTabView = getChildAt(position + 1) as CustomTextView rightTabView.mScrollToLeft = true rightTabView.mScrollProcess = positionOffset rightTabView.mTextScale = if (positionOffset > mTextScale) positionOffset else mTextScale rightTabView.invalidate() } } /** * 選中某個(gè)item回調(diào) */ override fun onPageSelected(position: Int) { } /** * 滑動(dòng)狀態(tài)改變回調(diào) */ override fun onPageScrollStateChanged(state: Int) { } }
1,循環(huán)添加多個(gè)顏色漸變的CustomTextView,默認(rèn)選中第一個(gè)
2,關(guān)聯(lián)ViewPage,給ViewPage設(shè)置一個(gè)OnPageChangeListener監(jiān)聽器,監(jiān)聽其滑動(dòng)距離,根據(jù)滑動(dòng)百分比計(jì)算出CustomTextView的滑動(dòng)比例,CustomTextView的文字縮放比例
3,效果如下,如有不理解的版代碼過去自行改改參數(shù)就理解其中奧秘了,動(dòng)起來
基線計(jì)算方式
在自定義View的過程中canvas.drawText(mText,0,y,mPaint);很容易出現(xiàn)字體不能完全漏出的問題,y的值其實(shí)不是距離畫布的距離,這個(gè)y是基準(zhǔn)線的距離,所以在繪制的過程中一定要求得正確的基準(zhǔn)線。所以在draw的過程中首先要計(jì)算好基準(zhǔn)線的y
Paint.FontMetricsInt fontMetrics = p.getFontMetricsInt();
p.descent, //底部文本的最低點(diǎn)距離基準(zhǔn)線的y值(正數(shù))
p.ascent, //頂部文本的最高點(diǎn)距離及基準(zhǔn)線的y值(負(fù)數(shù))
到此這篇關(guān)于Android自定義超級(jí)炫酷的ViewPage指示器的文章就介紹到這了,更多相關(guān)Android ViewPage內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Android ViewPager自定義輪播圖并解決播放沖突
- Android自定義引導(dǎo)玩轉(zhuǎn)ViewPager的方法詳解
- Android自定義ViewPager實(shí)現(xiàn)縱向滑動(dòng)翻頁效果
- Android使用自定義PageTransformer實(shí)現(xiàn)個(gè)性的ViewPager動(dòng)畫切換效果
- android自定義ViewPager水平滑動(dòng)彈性效果
- Android 自定義布局豎向的ViewPager的實(shí)現(xiàn)
- Android自定義ViewPager指示器
- Android自定義ViewPager實(shí)現(xiàn)個(gè)性化的圖片切換效果
- Android自定義ViewPager實(shí)例
相關(guān)文章
AndroidStudio中AVD虛擬機(jī)設(shè)備空間不足調(diào)試過程出現(xiàn)的黑屏問題及解決方案
這篇文章主要介紹了解決AndroidStudio中AVD虛擬機(jī)設(shè)備空間不足調(diào)試過程出現(xiàn)的黑屏問題,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-04-04Android實(shí)現(xiàn)可瀏覽和搜索的聯(lián)系人列表
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)可瀏覽和搜索的聯(lián)系人列表的相關(guān)代碼,瀏覽所有聯(lián)系人和根據(jù)名稱搜索聯(lián)系人,感興趣的小伙伴們可以參考一下2016-07-07Android滑動(dòng)動(dòng)態(tài)分頁實(shí)現(xiàn)方法
這篇文章主要介紹了Android滑動(dòng)動(dòng)態(tài)分頁實(shí)現(xiàn)方法,結(jié)合實(shí)例形式分析了Android實(shí)現(xiàn)滑動(dòng)動(dòng)態(tài)分頁的操作步驟與核心實(shí)現(xiàn)代碼,需要的朋友可以參考下2016-10-10Android studio實(shí)現(xiàn)菜單效果
這篇文章主要為大家詳細(xì)介紹了Android studio實(shí)現(xiàn)菜單效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-10-10Android自定義View onDraw()方法會(huì)調(diào)用兩次的問題解決
這篇文章主要介紹了Android自定義View onDraw()方法會(huì)調(diào)用兩次的問題解決,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2024-01-01android實(shí)現(xiàn)拍照或從相冊(cè)選取圖片
這篇文章主要為大家詳細(xì)介紹了android實(shí)現(xiàn)拍照或從相冊(cè)選取圖片,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-03-03