美文网首页Android开发
仿IOS标题切换控件

仿IOS标题切换控件

作者: 43d60efa37c7 | 来源:发表于2017-11-27 12:01 被阅读181次
    • 再次更新
      使用中发现因为每个矩形都是左右两个小的拼成的,有时候中间会出现重叠的现象,也就是1px宽,考虑是使用RectF的原因,把RectF修改为Rect

    • 更新
      圆角矩形边框效果不好,像是被切了一般,原因是画笔有一定宽度,画到外面去了,就还剩一半,修改了一下
    //画圆角矩形边框
            mPaint.reset()
            mPaint.color = textColor
            mPaint.style = Paint.Style.STROKE
            mPaint.strokeWidth = Utils.dp2px(context, 1f)
            mPaint.isAntiAlias = true
            rectF.left = rectF.left + mPaint.strokeWidth / 2
            rectF.top = rectF.top + mPaint.strokeWidth / 2
            rectF.right = rectF.right - mPaint.strokeWidth / 2
            rectF.bottom = rectF.bottom - mPaint.strokeWidth / 2
            canvas.drawRoundRect(rectF, corner, corner, mPaint)
    

    修改之后的效果.png

    每次都设计成ios原生控件的效果,android开发真是难。之前写过一次这个效果,在布局文件里写的,真的很麻烦。这次又有这个需求,写一个自定义view,以后再用就方便多了,记录一下。


    ios.jpg

    自定义view代码

    class IOSTab(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : View(context, attrs, defStyleAttr) {
    
        private var mTabs: Array<String> = arrayOf("")
        private var selectedPosition = 0
        private var mWidth = 0
        private var mHeight = 0
        private var corner = Utils.dp2px(context, 5f)
        private val mPaint = Paint()
    
        //字号
        private var textSize = Utils.dp2px(context,15)
        //主色调
        private var mainColor = context.resources.getColor(R.color.colorPrimary)
        //字的颜色
        private var textColor = context.resources.getColor(R.color.white)
        //选中的颜色
        private var selectColor = Color.parseColor("#ccffffff")
    
        constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
        constructor(context: Context) : this(context, null)
    
        init {
            val typedArray = context.obtainStyledAttributes(attrs, R.styleable.IOSTab)
            mainColor = typedArray.getColor(R.styleable.IOSTab_tabMainColor,context.resources.getColor(R.color.colorPrimary))
            textColor = typedArray.getColor(R.styleable.IOSTab_tabTextColor,context.resources.getColor(R.color.white))
            selectColor = typedArray.getColor(R.styleable.IOSTab_tabSelectColor,Color.parseColor("#ccffffff"))
            textSize = typedArray.getDimension(R.styleable.IOSTab_tabTextSize,Utils.dp2px(context,15))
        }
    
        override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec)
            mWidth = MeasureSpec.getSize(widthMeasureSpec)
            mHeight = MeasureSpec.getSize(heightMeasureSpec)
        }
    
        override fun onDraw(canvas: Canvas?) {
            super.onDraw(canvas)
    
            val rectF = RectF(0f, 0f, mWidth.toFloat(), mHeight.toFloat())
            //画背景
            mPaint.isAntiAlias = true
            mPaint.color = mainColor
            mPaint.style = Paint.Style.FILL
            canvas!!.drawRoundRect(rectF, corner, corner, mPaint)
            //画圆角矩形边框
            mPaint.reset()
            mPaint.color = textColor
            mPaint.style = Paint.Style.STROKE
            mPaint.strokeWidth = Utils.dp2px(context, 1f)
            mPaint.isAntiAlias = true
            canvas!!.drawRoundRect(rectF, corner, corner, mPaint)
    
            //画每一个字
            mPaint.reset()
            mPaint.color = textColor
            mPaint.isAntiAlias = true
            mPaint.textSize = textSize
    
            val count = mTabs.size
            if (count == 0) {
                return
            } else {
                //画字
                for (i in mTabs.indices){
                    drawText(i,canvas,mPaint)
                }
            }
            //每个item的宽度
            val itemWidth = mWidth / mTabs.size .toFloat()
            //画分隔线
            mPaint.strokeWidth = Utils.dp2px(context,0.5f)
            mTabs.indices
                    .filter { it != 0 }
                    .forEach {
                        canvas.drawLine(it * itemWidth,0f, it * itemWidth, mHeight.toFloat(),mPaint)
                    }
    
    
            mPaint.reset()
            mPaint.color = selectColor
    //        mPaint.alpha = 0xcc
            mPaint.style = Paint.Style.FILL
    
            //画选中状态
            if (count == 0 || count == 1){
                return
            }else{
                if (selectedPosition == 0){
                    //第一个被选中,把左半边画上圆角
                    canvas.save()
                    //只画左半边
                    canvas.clipRect(RectF(0f,0f,itemWidth /2,mHeight.toFloat()))
                    //圆角矩形
                    val rectF = RectF(0f,0f,itemWidth,mHeight.toFloat())
                    canvas.drawRoundRect(rectF, corner, corner, mPaint)
                    canvas.restore()
    
                    canvas.drawRect(RectF(itemWidth /2,0f,itemWidth, mHeight.toFloat()),mPaint)
                }else if (selectedPosition == count -1){
                    //最后一个被选中,右半边画上圆角
                    canvas.save()
                    //只画右半边
                    canvas.clipRect(RectF((selectedPosition + 0.5f)* itemWidth,0f,count * itemWidth,mHeight.toFloat()))
                    //圆角矩形
                    val rectF = RectF(selectedPosition* itemWidth,0f,count* itemWidth,mHeight.toFloat())
                    canvas.drawRoundRect(rectF, corner, corner, mPaint)
                    canvas.restore()
                    canvas.drawRect(RectF(selectedPosition* itemWidth,0f,(selectedPosition + 0.5f)* itemWidth, mHeight.toFloat()),mPaint)
                }else{
                    //选中中间的
                    val rect = Rect((itemWidth * selectedPosition).toInt()
                            , 0
                            , (itemWidth*(selectedPosition+1)).toInt()
                            , mHeight)
                    canvas.drawRect(rect,mPaint)
                }
    
            }
    
            //画选中的条目的文字
            mPaint.reset()
            mPaint.color = mainColor
            mPaint.isAntiAlias = true
            mPaint.textSize = textSize
            drawText(selectedPosition,canvas,mPaint)
    
        }
    
        private fun drawText(position: Int, canvas: Canvas, paint: Paint) {
            val text = mTabs[position]
            val textWidth = paint.measureText(text)
            val itemWidth = mWidth / mTabs.size
            //X起始坐标,X轴居中
            val startX = (itemWidth - textWidth) / 2 + itemWidth * position
            //Y起始坐标,Y轴居中
            val startY = mHeight / 2 + (Math.abs(mPaint.fontMetrics.ascent) - mPaint.fontMetrics.descent) / 2
    
            canvas.drawText(text, startX, startY, paint)
        }
    
        override fun onTouchEvent(event: MotionEvent?): Boolean {
            if (event!!.action == MotionEvent.ACTION_DOWN){
                if (mTabs.isNotEmpty()){
                    selectedPosition = (event.x / (mWidth / mTabs.size)).toInt()
                    invalidate()
                    if (listener != null)
                        listener!!.onChange(selectedPosition)
                }
            }
            return super.onTouchEvent(event)
        }
    
        private var  listener: IOSTab.OnSelectedItemChange? = null
    
        //设置切换监听
        fun setOnSelectedItemChange(listener: OnSelectedItemChange){
            this.listener = listener
        }
    
        fun setTabs(tabs: Array<String>) {
            mTabs = tabs
            invalidate()
        }
    
        interface OnSelectedItemChange {
            fun onChange(select: Int)
        }
    }
    

    attrs文件中添加

    <declare-styleable name="IOSTab">
            <!-- 主色调,未被选中的条目背景色,选中条目的文字颜色-->
            <attr name="tabMainColor" format="color"/>
            <!-- 未被选中的条目的文字颜色,外围圆角边框颜色-->
            <attr name="tabTextColor" format="color"/>
            <!-- 被选中条目的背景色 -->
            <attr name="tabSelectColor" format="color"/>
            <!-- 文字大小 -->
            <attr name="tabTextSize" format="dimension"/>
        </declare-styleable>
    

    使用

    在布局文件中

    <com.test.www.test.view.IOSTab
                android:id="@+id/ios_tab"
                android:layout_width="200dp"
                android:layout_height="29dp"
                android:layout_gravity="center"
                app:tabSelectColor="#ccffffff"
                />
    

    在activity或者fragment中

    val tabs = arrayOf("标题一","标题二","标题三")
    ios_tab.setTabs(tabs)
    ios_tab.setOnSelectedItemChange(object : IOSTab.OnSelectedItemChange{
                override fun onChange(select: Int) {
                    //在这里处理切换
                }
            })
    

    效果


    效果.png

    相关文章

      网友评论

        本文标题:仿IOS标题切换控件

        本文链接:https://www.haomeiwen.com/subject/pdirbxtx.html