Android基础控件——HorizontalScrollView的自定义,完美模仿抖音等短视频拍摄底部切换Tab控件

前言

最近在项目中需要用到跟抖音同样的控件效果,找了几个开源的TabLayout控件,要么功能很复杂,要么要自己拓展功能,还要去阅读别人代码,实在是没这个时间折腾。每次遇到找不到第三方的控件时候,就开始撸一个简单的控件,好维护又好拓展,功能也不差,做出来体验也很好

抖音原效果

在这里插入图片描述

模仿效果

在这里插入图片描述

简单使用

在布局上,是用底部Tab控件带动ViewPager的切换,中间的白点只是一个固定的图片而已,不会有任何作用

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <com.remo.mobile.framework.widget.UnScrollViewPager
            android:id="@+id/vp_record"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

        <!--底部Tab控件-->
        <com.remo.mobile.smallvideo.widget.horScrollerIndication.ScrollerSelectIndicationTextView
            android:id="@+id/ssitv_tab"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true" />

    </RelativeLayout>

    <!--中间白点-->
    <ImageView
        android:layout_width="4dp"
        android:layout_height="4dp"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="6dp"
        android:src="@drawable/scroller_textview_indication" />
</RelativeLayout>

从代码上,监听滚动和点击接口后,设置当前的ViewPager界面

ssitv_tab?.setOnPageSelectListenter(object : ScrollerSelectIndication.OnScrollerListener {
    override fun onPageSelect(position: Int) {
        vp_record.setCurrentItem(position, false)
    }
})

功能分析

出于简单考虑,并不会跟系统一样采用View的方式去画出来,而是采用组合View的形式去完成,此处分为两个步骤

  • HorizontalScrollView组合TextView部分
  • 自定义HorizontalScrollView部分

1、HorizontalScrollView组合TextView部分

  • 处理横向滚动组件和TextView之间的关系
  • 巧用Space控件来做空白区域的填充

2、自定义HorizontalScrollView部分

  • Tab的点击
  • 监听Tab的滑动
  • 控制Tab的滑动速度
  • Tab滑动落点的边界判断

实现分析

1、HorizontalScrollView组合TextView部分

此处只是简单的控件,包含HorizontalScrollView和TextView,也是最终外部使用的控件

class ScrollerSelectIndicationTextView @JvmOverloads constructor(
        context: Context,
        attrs: AttributeSet? = null,
        defStyleAttr: Int = 0
) : LinearLayout(context, attrs, defStyleAttr) {

    companion object {
        const val TAG = "[视频服务-ScrollerSelectIndicationTextView]"
    }

    init {
        initView(context)
    }

    private fun initView(context: Context) {
        LayoutInflater.from(context).inflate(R.layout.layout_scroller_select_indication, this)
    }

    fun setOnPageSelectListenter(listener: ScrollerSelectIndication.OnScrollerListener) {
        ssi_indication?.onPageSelectListener = listener
    }
}

layout_scroller_select_indication布局包含自定义的HorizontalScrollViewTextView,而Space则是填补前面一段空白的位置,前后各有一段

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="50dp"
    tools:background="#40000000">

    <com.remo.mobile.smallvideo.widget.horScrollerIndication.ScrollerSelectIndication
        android:id="@+id/ssi_indication"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:gravity="center_vertical">

            <Space
                android:layout_width="250dp"
                android:layout_height="wrap_content" />

            <TextView
                android:id="@+id/tv_album"
                android:layout_width="80dp"
                android:layout_height="wrap_content"
                android:gravity="center"
                android:text="Album"
                android:textColor="#40ffffff"
                android:textSize="14dp" />

            <TextView
                android:id="@+id/tv_photo"
                android:layout_width="80dp"
                android:layout_height="wrap_content"
                android:gravity="center"
                android:text="Photo"
                android:textColor="#40ffffff"
                android:textSize="14dp" />

            <TextView
                android:id="@+id/tv_video"
                android:layout_width="80dp"
                android:layout_height="wrap_content"
                android:gravity="center"
                android:text="Video"
                android:textColor="#40ffffff"
                android:textSize="14dp" />

            <TextView
                android:id="@+id/tv_templates"
                android:layout_width="80dp"
                android:layout_height="wrap_content"
                android:gravity="center"
                android:text="Templates"
                android:textColor="#40ffffff"
                android:textSize="14dp" />

            <Space
                android:layout_width="250dp"
                android:layout_height="wrap_content" />

        </LinearLayout>
    </com.remo.mobile.smallvideo.widget.horScrollerIndication.ScrollerSelectIndication>
</RelativeLayout>

2、自定义HorizontalScrollView部分

自定义HorizontalScrollView部分要实现好几个功能,和滑动位置的计算,这块也不是特别复杂,主要包含

  • onSizeChanged获取所有Tab的点和TextView
  • 监听滑动的方案和落点的采集方案
  • 对命中Tab的距离做计算,并移动到Tab的准确位置上
  • 控制滚动的滑动速度

1、定义变量

class ScrollerSelectIndication @JvmOverloads constructor(
        context: Context,
        attrs: AttributeSet? = null,
        defStyleAttr: Int = 0
) : HorizontalScrollView(context, attrs, defStyleAttr) {

    var count = 0 //记录当前Tab的个数
    var tabWidth = 0 //当前Tab的宽度
    var tabSelectPoint = 0 //当前Tab的命中点位置
    
    var selectPoint = mutableListOf<Int>() //记录每个Tab命中的点
    var selectTextView = mutableListOf<TextView>() //记录每个TextView
    
    var leftSpace = 0 //当前文本最左边的距离
    var rightSpace = 0 //当前文本最右边的距离
    var currentX = -9999 //记录当前滚动的距离
    var scrollType = ScrollType.IDLE //当前滚动状态
    
    var currentSelected = 0 //当前命中位置,从0开始
    var onPageSelectListener: OnScrollerListener? = null
    
}

2、获取大小

由于我们一开始定义好了是SpaceTextView的配合,那么就可以直接知道它的布局结构,如果后续要拓展成ImageView也是可以的

override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
    super.onSizeChanged(w, h, oldw, oldh)

    selectPoint.clear() //避免缓存多次利用
    tabSelectPoint = measuredWidth / 2 //命中的落点是在控件的中间

    var layout = getChildAt(0) as LinearLayout

    Log.i(TAG, "---------------------------------------------")
    for (i in 0..layout.childCount) {
        var text = layout.getChildAt(i)

        if (text is TextView) {
            var textWidth = text.layoutParams.width
            tabWidth = textWidth
            selectPoint.add(leftSpace + textWidth / 2 + count++ * textWidth) //记录每个Tab命中的点
            selectTextView.add(text) //记录每个TextView
        } else if (text is Space) {
            if (leftSpace == 0) leftSpace = text.layoutParams.width //第一个肯定是左边的Space
            else if (rightSpace == 0) rightSpace = leftSpace + count * tabWidth //第二个自然是右边的Space
        }
    }
    Log.i(TAG, "当前所有命中Tab的点 = $selectPoint")
    Log.i(TAG, "当前可见宽度 = $measuredWidth,当前Tab的宽度 = $tabWidth")
    Log.i(TAG, "当前文本最左边的距离 = $leftSpace,当前文本最右边的距离 = $rightSpace")
    Log.i(TAG, "---------------------------------------------")
}

3、监听滑动松手后的落点

这里采用了网上的方案,通过Handler一直获取点的变化,当发现点不再移动的时候则判定为滑动停止

enum class ScrollType {
    IDLE, TOUCH_SCROLL, FLING
}

@SuppressLint("LongLogTag")
override fun onTouchEvent(ev: MotionEvent?): Boolean {
    when (ev?.action) {
        MotionEvent.ACTION_MOVE -> {
            scrollType = ScrollType.TOUCH_SCROLL
            handler.removeCallbacks(scrollRunnable)
        }
        MotionEvent.ACTION_UP -> {
            handler.post(scrollRunnable)
        }
        MotionEvent.ACTION_DOWN -> {
        }
    }
    return super.onTouchEvent(ev)
}

@SuppressLint("LongLogTag")
var scrollRunnable: Runnable = object : Runnable {
    override fun run() {
        if (scrollX == currentX) {
            scrollType = ScrollType.IDLE
            for (i in 0 until selectPoint.size) {
                var selectPointWidth = selectPoint[i]
                // 计算当前点和命中点的距离,如果在某个Tab的一半距离内,那么就自动命中那个Tab
                if (abs(scrollX + tabSelectPoint - selectPointWidth) <= tabWidth / 2) {
                    Log.i(TAG, "当前命中 = $i")
                    smoothScrollToPosition(selectPoint[i] - tabSelectPoint, i)
                    break
                } else if (scrollX + tabSelectPoint <= leftSpace) { //左边界计算
                    Log.i(TAG, "当前命中最左边")
                    smoothScrollToPosition(selectPoint[0] - tabSelectPoint, 0)
                    break
                } else if (scrollX + tabSelectPoint >= rightSpace) { //右边界计算
                    Log.i(TAG, "当前命中最右边")
                    smoothScrollToPosition(selectPoint[count - 1] - tabSelectPoint, count - 1)
                    break
                }
            }
            handler.removeCallbacks(this)
            return
        } else {
            scrollType = ScrollType.FLING
        }
        currentX = scrollX
        handler.postDelayed(this, 50)
    }
}

private fun scrollToPosition(scrollX: Int, currentSelected: Int) {
    this.currentSelected = currentSelected
    scrollTo(scrollX, 0)
    updateTextView(currentSelected)
    onPageSelectListener?.onPageSelect(currentSelected)
}

private fun smoothScrollToPosition(scrollX: Int, currentSelected: Int) {
    this.currentSelected = currentSelected
    smoothScrollTo(scrollX, 0)
    updateTextView(currentSelected)
    onPageSelectListener?.onPageSelect(currentSelected)
}

private fun updateTextView(currentSelected: Int) {
    for (i in 0 until selectTextView.size) {
        var textView = selectTextView[i]
        if (currentSelected == i) {
            textView.alpha = 1.0f
            textView.setTextColor(Color.parseColor("#FFFFFF"))
        } else {
            textView.alpha = 0.4f
            textView.setTextColor(Color.parseColor("#FFFFFF"))
        }
    }
}

interface OnScrollerListener {
    fun onPageSelect(position: Int)
}

4、点击事件

这里直接在获取大小后直接设置点击事件和初始化位置

@SuppressLint1("LongLogTag")
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
    super.onSizeChanged(w, h, oldw, oldh)

    ......

    for (i in 0 until selectTextView.size) {
        selectTextView[i].setOnClickListener {
            smoothScrollToPosition(selectPoint[i] - tabSelectPoint, i)
        }
    }

    postDelayed({
        scrollToPosition(selectPoint[currentSelected] - tabSelectPoint, currentSelected)
    }, 20)
}

5、控制滑动速度

当我们做完后发现横向滚动特别快,从其他竞品上看滑动的速度还是比较人性化,有点阻力的感觉,通过设置下面属性增加滑动阻力

override fun fling(velocityX: Int) {
    super.fling(velocityX / 5)
}

6、源码

package com.remo.mobile.smallvideo.widget.horScrollerIndication

import android.content.Context
import android.graphics.Color
import android.util.AttributeSet
import android.util.Log
import android.view.MotionEvent
import android.widget.HorizontalScrollView
import android.widget.LinearLayout
import android.widget.Space
import android.widget.TextView
import kotlin.math.abs
import android.annotation.SuppressLint as SuppressLint1


class ScrollerSelectIndication @JvmOverloads constructor(
        context: Context,
        attrs: AttributeSet? = null,
        defStyleAttr: Int = 0
) : HorizontalScrollView(context, attrs, defStyleAttr) {

    var count = 0 //记录当前Tab的个数
    var tabWidth = 0 //当前Tab的宽度
    var tabSelectPoint = 0 //当前Tab的命中点位置

    var selectPoint = mutableListOf<Int>() //记录每个Tab命中的点
    var selectTextView = mutableListOf<TextView>() //记录每个TextView

    var leftSpace = 0 //当前文本最左边的距离
    var rightSpace = 0 //当前文本最右边的距离
    var currentX = -9999 //记录当前滚动的距离
    var scrollType = ScrollType.IDLE //当前滚动状态

    var currentSelected = 0 //当前命中位置,从0开始
    var onPageSelectListener: OnScrollerListener? = null

    companion object {
        const val TAG = "[视频服务-ScrollerSelectIndicationTextView]"
    }

    @SuppressLint1("LongLogTag")
    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)

        selectPoint.clear()
        tabSelectPoint = measuredWidth / 2

        var layout = getChildAt(0) as LinearLayout

        Log.i(TAG, "---------------------------------------------")
        for (i in 0..layout.childCount) {
            var text = layout.getChildAt(i)

            if (text is TextView) {
                var textWidth = text.layoutParams.width
                tabWidth = textWidth
                selectPoint.add(leftSpace + textWidth / 2 + count++ * textWidth)
                selectTextView.add(text)
            } else if (text is Space) {
                if (leftSpace == 0) leftSpace = text.layoutParams.width
                else if (rightSpace == 0) rightSpace = leftSpace + count * tabWidth
            }
        }
        Log.i(TAG, "当前所有命中Tab的点 = $selectPoint")
        Log.i(TAG, "当前可见宽度 = $measuredWidth,当前Tab的宽度 = $tabWidth")
        Log.i(TAG, "当前文本最左边的距离 = $leftSpace,当前文本最右边的距离 = $rightSpace")
        Log.i(TAG, "---------------------------------------------")

        for (i in 0 until selectTextView.size) {
            selectTextView[i].setOnClickListener {
                smoothScrollToPosition(selectPoint[i] - tabSelectPoint, i)
            }
        }

        postDelayed({
            scrollToPosition(selectPoint[currentSelected] - tabSelectPoint, currentSelected)
        }, 20)
    }

    override fun fling(velocityX: Int) {
        super.fling(velocityX / 5)
    }

    @SuppressLint1("LongLogTag")
    override fun onTouchEvent(ev: MotionEvent?): Boolean {
        when (ev?.action) {
            MotionEvent.ACTION_MOVE -> {
                scrollType = ScrollType.TOUCH_SCROLL
                handler.removeCallbacks(scrollRunnable)
            }
            MotionEvent.ACTION_UP -> {
                handler.post(scrollRunnable)
            }
            MotionEvent.ACTION_DOWN -> {
            }
        }
        return super.onTouchEvent(ev)
    }

    enum class ScrollType {
        IDLE, TOUCH_SCROLL, FLING
    }

    @SuppressLint1("LongLogTag")
    var scrollRunnable: Runnable = object : Runnable {
        override fun run() {
            if (scrollX == currentX) {
                scrollType = ScrollType.IDLE
                for (i in 0 until selectPoint.size) {
                    var selectPointWidth = selectPoint[i]
                    if (abs(scrollX + tabSelectPoint - selectPointWidth) <= tabWidth / 2) {
                        Log.i(TAG, "当前命中 = $i")
                        smoothScrollToPosition(selectPoint[i] - tabSelectPoint, i)
                        break
                    } else if (scrollX + tabSelectPoint <= leftSpace) {
                        Log.i(TAG, "当前命中最左边")
                        smoothScrollToPosition(selectPoint[0] - tabSelectPoint, 0)
                        break
                    } else if (scrollX + tabSelectPoint >= rightSpace) {
                        Log.i(TAG, "当前命中最右边")
                        smoothScrollToPosition(selectPoint[count - 1] - tabSelectPoint, count - 1)
                        break
                    }
                }
                handler.removeCallbacks(this)
                return
            } else {
                scrollType = ScrollType.FLING
            }
            currentX = scrollX
            handler.postDelayed(this, 50)
        }
    }

    private fun scrollToPosition(scrollX: Int, currentSelected: Int) {
        this.currentSelected = currentSelected
        scrollTo(scrollX, 0)
        updateTextView(currentSelected)
        onPageSelectListener?.onPageSelect(currentSelected)
    }

    private fun smoothScrollToPosition(scrollX: Int, currentSelected: Int) {
        this.currentSelected = currentSelected
        smoothScrollTo(scrollX, 0)
        updateTextView(currentSelected)
        onPageSelectListener?.onPageSelect(currentSelected)
    }

    private fun updateTextView(currentSelected: Int) {
        for (i in 0 until selectTextView.size) {
            var textView = selectTextView[i]
            if (currentSelected == i) {
                textView.alpha = 1.0f
                textView.setTextColor(Color.parseColor("#FFFFFF"))
            } else {
                textView.alpha = 0.4f
                textView.setTextColor(Color.parseColor("#FFFFFF"))
            }
        }
    }

    interface OnScrollerListener {
        fun onPageSelect(position: Int)
    }
}

后续优化

后续让这个控件能实现底部可配置化,将xml布局改造成代码的形式去添加,这样可以减少一层嵌套,这样使用起来更简单一些

1、使用代码的形式

先创建根布局

<RelativeLayout
    android:id="@+id/ly_indication"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true" />

通过代码的形式,动态添加布局,在参数textList填多少个都能够适配底部Tab的个数

indication = ScrollerSelectIndication(this,textList = mutableListOf("Album", "Photo"))
indication?.onPageSelectListener = object : ScrollerSelectIndication.OnScrollerListener {
    override fun onPageSelect(position: Int) {
        pageSelect_Type1(position)
    }
}
ly_indication = findViewById(R.id.ly_indication)
ly_indication?.addView(indication)

2、源码动态生成布局

在源码中,通过代码的形式,将我们一开始的布局转换成代码,让其适配多个Tab的使用

class ScrollerSelectIndication @JvmOverloads constructor(
        context: Context,
        attrs: AttributeSet? = null,
        defStyleAttr: Int = 0,
        textList: List<String>
) : HorizontalScrollView(context, attrs, defStyleAttr) {

    var count = 0 //记录当前Tab的个数
    var tabWidth = 0 //当前Tab的宽度
    var tabSelectPoint = 0 //当前Tab的命中点位置

    var selectPoint = mutableListOf<Int>() //记录每个Tab命中的点
    var selectTextView = mutableListOf<TextView>() //记录每个TextView

    var leftSpace = 0 //当前文本最左边的距离
    var rightSpace = 0 //当前文本最右边的距离
    var currentX = -9999 //记录当前滚动的距离
    var scrollType = ScrollType.IDLE //当前滚动状态

    var currentSelected = 0 //当前命中位置,从0开始
    var onPageSelectListener: OnScrollerListener? = null

    companion object {
        const val TAG = "[视频服务-ScrollerSelectIndicationTextView]"
    }

    init {
        layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 42.dp2px)
        setBackgroundColor(Color.parseColor("#40000000"))

        var root = LinearLayout(context)
        var rootParams = LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)

        var leftSpace = Space(context)
        var leftSpaceParams = ViewGroup.LayoutParams(250.dp2px, ViewGroup.LayoutParams.MATCH_PARENT)
        root.addView(leftSpace, leftSpaceParams)

        for (text in textList) {
            var textView = TextView(context)
            textView.text = text
            textView.setTextColor(Color.parseColor("#40ffffff"))
            textView.textSize = 16f
            textView.gravity = Gravity.CENTER
            var textViewParams = ViewGroup.LayoutParams(80.dp2px, ViewGroup.LayoutParams.MATCH_PARENT)
            root.addView(textView, textViewParams)
        }

        var rightSpace = Space(context)
        var rightSpaceParams = ViewGroup.LayoutParams(250.dp2px, ViewGroup.LayoutParams.MATCH_PARENT)
        root.addView(rightSpace, rightSpaceParams)

        addView(root, rootParams)
    }

    @SuppressLint("LongLogTag")
    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)

        selectPoint.clear()
        tabSelectPoint = measuredWidth / 2

        var layout = getChildAt(0) as LinearLayout

        Log.i(TAG, "---------------------------------------------")
        for (i in 0..layout.childCount) {
            var text = layout.getChildAt(i)

            if (text is TextView) {
                var textWidth = text.layoutParams.width
                tabWidth = textWidth
                selectPoint.add(leftSpace + textWidth / 2 + count++ * textWidth)
                selectTextView.add(text)
            } else if (text is Space) {
                if (leftSpace == 0) leftSpace = text.layoutParams.width
                else if (rightSpace == 0) rightSpace = leftSpace + count * tabWidth
            }
        }
        Log.i(TAG, "当前所有命中Tab的点 = $selectPoint")
        Log.i(TAG, "当前可见宽度 = $measuredWidth,当前Tab的宽度 = $tabWidth")
        Log.i(TAG, "当前文本最左边的距离 = $leftSpace,当前文本最右边的距离 = $rightSpace")
        Log.i(TAG, "---------------------------------------------")

        for (i in 0 until selectTextView.size) {
            selectTextView[i].setOnClickListener {
                smoothScrollToPosition(selectPoint[i] - tabSelectPoint, i)
            }
        }

        postDelayed({
            scrollToPosition(selectPoint[currentSelected] - tabSelectPoint, currentSelected)
        }, 20)
    }

    override fun fling(velocityX: Int) {
        super.fling(velocityX / 5)
    }

    @SuppressLint("LongLogTag")
    override fun onTouchEvent(ev: MotionEvent?): Boolean {
        when (ev?.action) {
            MotionEvent.ACTION_MOVE -> {
                scrollType = ScrollType.TOUCH_SCROLL
                handler.removeCallbacks(scrollRunnable)
            }
            MotionEvent.ACTION_UP -> {
                handler.post(scrollRunnable)
            }
            MotionEvent.ACTION_DOWN -> {
            }
        }
        return super.onTouchEvent(ev)
    }

    enum class ScrollType {
        IDLE, TOUCH_SCROLL, FLING
    }

    @SuppressLint("LongLogTag")
    var scrollRunnable: Runnable = object : Runnable {
        override fun run() {
            if (scrollX == currentX) {
                scrollType = ScrollType.IDLE
                for (i in 0 until selectPoint.size) {
                    var selectPointWidth = selectPoint[i]
                    if (abs(scrollX + tabSelectPoint - selectPointWidth) <= tabWidth / 2) {
                        Log.i(TAG, "当前命中 = $i")
                        smoothScrollToPosition(selectPoint[i] - tabSelectPoint, i)
                        break
                    } else if (scrollX + tabSelectPoint <= leftSpace) {
                        Log.i(TAG, "当前命中最左边")
                        smoothScrollToPosition(selectPoint[0] - tabSelectPoint, 0)
                        break
                    } else if (scrollX + tabSelectPoint >= rightSpace) {
                        Log.i(TAG, "当前命中最右边")
                        smoothScrollToPosition(selectPoint[count - 1] - tabSelectPoint, count - 1)
                        break
                    }
                }
                handler.removeCallbacks(this)
                return
            } else {
                scrollType = ScrollType.FLING
            }
            currentX = scrollX
            handler.postDelayed(this, 50)
        }
    }

    private fun scrollToPosition(scrollX: Int, currentSelected: Int) {
        this.currentSelected = currentSelected
        scrollTo(scrollX, 0)
        updateTextView(currentSelected)
        onPageSelectListener?.onPageSelect(currentSelected)
    }

    private fun smoothScrollToPosition(scrollX: Int, currentSelected: Int) {
        this.currentSelected = currentSelected
        smoothScrollTo(scrollX, 0)
        updateTextView(currentSelected)
        onPageSelectListener?.onPageSelect(currentSelected)
    }

    private fun updateTextView(currentSelected: Int) {
        for (i in 0 until selectTextView.size) {
            var textView = selectTextView[i]
            if (currentSelected == i) {
                textView.alpha = 1.0f
                textView.setTextColor(Color.parseColor("#FFFFFF"))
            } else {
                textView.alpha = 0.4f
                textView.setTextColor(Color.parseColor("#FFFFFF"))
            }
        }
    }

    interface OnScrollerListener {
        fun onPageSelect(position: Int)
    }
}
  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

许英俊潇洒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值