美文网首页
View自定义边框-Android

View自定义边框-Android

作者: 呵呵先森 | 来源:发表于2019-10-29 14:19 被阅读0次

    Android开发中最烦的事,就是不停的定义不同角度不同颜色不同样式的边框,不仅很难重复使用,也很难命名管理

    现有的样式实现方式大体分为以下几类

    1.图片背景代替 (缺点:图片命名难以管理,且适配会存在变形)
    2.drawable (缺点:命名难以管理,难以复用)
    3.自定义view(缺点:太烦)
    4.第三方框架(PS: 实现思路基本还是第三种,缺点:太烦)

    需求场景

      需要一个只有一个右上圆弧为3dp的红色背景
      需要一个只有一个左上圆弧为3dp的蓝色背景
      需要一个只有一个右上左上圆弧为5dp的灰色背景
      右上左上圆弧为3dp蓝色背景
      等等等等....

    想实现的效果

    最近学iOS,对iOS上实现这个功能的简单羡慕不已,Android想实现以下的效果

    view.setRadius(strokeWidth = 10f,strokeColor = R.color.redF45265,backgroundColor = R.color.color999999,leftBottomRadius = 10,leftTopRadius = 40,rightBottomRadius = 20,rightTopRadius = 30)
    view.setRadius(strokeWidth = 0.6f, strokeColor = R.color.colorCCCCCC, radius = 3)
    view1.setRadius(strokeWidth = 0.6f, strokeColor = R.color.colorCCCCCC, radius = 3)
    view1.setShadow(shadowColor = R.color.redF45265,shadowWidth = 4f)
    
    效果图.jpg
    代码实现

    自定义一个Drawable类,在里面重写部分代码,边框这些用paint画出来(canvas小白,又更好的办法,欢迎指出)

    class CustomDrawable(val view: View) : Drawable() {
    
       private var leftTopRadius = 0f
       private var rightTopRadius = 0f
       private var leftBottomRadius = 0f
       private var rightBottomRadius = 0f
       private var radiusArray = floatArrayOf()
    
       private var shadowColor: Int = R.color.colorPrimaryDark.getColor()
       private var shadowRectF = RectF()         // 阴影部分的背景颜色
       private var shadowWidth = 0f              // 阴影宽度单位为dp  0为不需要阴影
    
       private var strokeWidth = 0f
       private var strokeColor: Int = R.color.color999999.getColor()
    
       private var backGroundColor: Int = R.color.white.getColor()    // 背景颜色
       private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
    
       /**
        * 设置圆角
        * @param backGroundColor  背景色
        * @param leftTopRadius     左上角
        * @param leftBottomRadius  左下角
        * @param rightBottomRadius 右下角
        * @param rightTopRadius    右上角
        * @param strokeWidth 边框宽度 dp f
        * @param strokeColor 边框颜色
        */
       fun setRadius(
           backGroundColor: Int = R.color.white,
           strokeWidth: Float = 0f,
           strokeColor: Int = R.color.colorB3B3B3,
           leftTopRadius: Int = 0,
           rightTopRadius: Int = 0,
           rightBottomRadius: Int = 0,
           leftBottomRadius: Int = 0
       ) {
           clearColorFilter()
           this.leftBottomRadius = leftBottomRadius.dp2px.toFloat()
           this.leftTopRadius = leftTopRadius.dp2px.toFloat()
           this.rightTopRadius = rightTopRadius.dp2px.toFloat()
           this.rightBottomRadius = rightBottomRadius.dp2px.toFloat()
           this.strokeWidth = Screen.dp2Px(strokeWidth).toFloat()
           this.strokeColor = strokeColor.getColor()
           this.backGroundColor = backGroundColor.getColor()
       }
    
       /**
        * 设置阴影
        * @param shadowWidth 阴影宽度 dp f
        * @param shadowColor 阴影颜色
        */
       fun setShadow(
           shadowWidth: Float = 0f,
           shadowColor: Int = R.color.colorB3B3B3
       ) {
           this.shadowWidth = Screen.dp2Px(shadowWidth).toFloat()
           this.shadowColor = shadowColor.getColor()
       }
    
       fun invalidate() {
           invalidateSelf()
       }
    
       override fun draw(canvas: Canvas) {
           getRadius()
           setDraw(canvas)
       }
    
       private fun setDraw(canvas: Canvas) {
           paint.color = strokeColor
           paint.isAntiAlias = true
           paint.style = Paint.Style.STROKE
           paint.strokeWidth = strokeWidth + if (backGroundColor != strokeColor) strokeWidth else 0f
           paint.setShadowLayer(shadowWidth, 0f, 0f, shadowColor)
    
           val path = Path()
           path.addRoundRect(shadowRectF, radiusArray, Path.Direction.CW)
           canvas.drawPath(path, paint)
    
           // 渲染内部
           paint.reset()
           paint.color = backGroundColor
           paint.isAntiAlias = true
           paint.style = Paint.Style.FILL
           paint.strokeWidth = strokeWidth
    
           path.reset()
           path.addRoundRect(shadowRectF, radiusArray, Path.Direction.CW)
           canvas.drawPath(path, paint)
       }
    
       /**
        * 计算圆角等值
        */
       private fun getRadius() {
    
           radiusArray = floatArrayOf(
               leftTopRadius, leftTopRadius,
               rightTopRadius, rightTopRadius,
               rightBottomRadius, rightBottomRadius,
               leftBottomRadius, leftBottomRadius
           )
    
           shadowRectF = RectF(
               shadowWidth + strokeWidth,
               shadowWidth + strokeWidth,
               view.width - shadowWidth - strokeWidth,
               view.height - shadowWidth - strokeWidth
           )
    
       }
    
       override fun setAlpha(alpha: Int) {
       }
    
       override fun setColorFilter(colorFilter: ColorFilter?) {
       }
    
       override fun getOpacity(): Int {
           return PixelFormat.TRANSLUCENT
       }
    
    }
    

    至此自定义部分已经完成了,接下来看调用

    fun View.setShadow(
        shadowWidth: Float = 0f,
        shadowColor: Int = R.color.colorB3B3B3
    ) {
    
       if (this is CustomImageView) {
            setImageViewShadow(shadowWidth,shadowColor)
            return
        }
    
        var newDrawable: CustomDrawable? = null
        // 如果类型是自定义类型drawable 直接修改
        if (backgroundDrawable != null && backgroundDrawable is CustomDrawable) {
            newDrawable = backgroundDrawable as CustomDrawable
        }
        
        // drawable类型不是自定义的CustomDrawable类型,则修改为CustomDrawable
        if (newDrawable == null) {
            newDrawable = CustomDrawable(this)
        }
        
        newDrawable.setShadow(shadowWidth, shadowColor)
        newDrawable.invalidate()
        background = newDrawable
    }
    
    
    fun View.setRadius(
        backgroundColor: Int = R.color.white,
        strokeWidth: Float = 0f,
        strokeColor: Int = R.color.colorB3B3B3,
        leftTopRadius: Int = 0,
        rightTopRadius: Int = 0,
        leftBottomRadius: Int = 0,
        rightBottomRadius: Int = 0
    ) {
    
     if (this is CustomImageView) {
            setImageViewRadius(
                backGroundColor = backgroundColor,
                strokeWidth = strokeWidth,
                strokeColor = strokeColor,
                leftTopRadius = leftTopRadius,
                rightTopRadius = rightTopRadius,
                leftBottomRadius = leftBottomRadius,
                rightBottomRadius = rightBottomRadius
            )
            return
        }
    
        var newDrawable: CustomDrawable? = null
        val oldDrawable = backgroundDrawable
    
        if (backgroundDrawable != null && oldDrawable is CustomDrawable) {
            newDrawable = oldDrawable
        }
    
        if (newDrawable == null) {
            newDrawable = CustomDrawable(this)
        }
    
        newDrawable.setRadius(
            backgroundColor,
            strokeWidth,
            strokeColor,
            leftTopRadius,
            rightTopRadius,
            rightBottomRadius,
            leftBottomRadius
        )
        newDrawable.invalidate()
    
        // 重新渲染 防止颜色叠加
        requestLayout()
        background = newDrawable
    }
    
    /**
     * 添加圆角
     */
    fun View.setRadius(
        backgroundColor: Int = R.color.white,
        strokeWidth: Float = 0f,
        strokeColor: Int = backgroundColor,
        radius: Int = 0
    ) {
    
       // iamgeView 图层比较特殊,是浮在drawable之上,需要特殊处理 也可以直接调用
       if (this is CustomImageView) {
            setImageViewRadius(
                backGroundColor = backgroundColor,
                strokeWidth = strokeWidth,
                strokeColor = strokeColor,
                leftTopRadius = leftTopRadius,
                rightTopRadius = rightTopRadius,
                leftBottomRadius = leftBottomRadius,
                rightBottomRadius = rightBottomRadius
            )
            return
        }
    
        setRadius(
            backgroundColor = backgroundColor,
            strokeWidth = strokeWidth,
            strokeColor = strokeColor,
            leftTopRadius = radius,
            rightTopRadius = radius,
            leftBottomRadius = radius,
            rightBottomRadius = radius
        )
    }
    
    

    自定义边框各圆角的imageView

    
    class CustomImageView: ImageView {
    
        private var leftTopRadius = 0f
        private var rightTopRadius = 0f
        private var leftBottomRadius = 0f
        private var rightBottomRadius = 0f
        private var radiusArray = floatArrayOf()
    
        private var shadowColor: Int = R.color.colorPrimaryDark.getColor()
        private var shadowRectF = RectF()         // 阴影部分的背景颜色
        private var shadowWidth = 0f              // 阴影宽度单位为dp  0为不需要阴影
    
        private var strokeWidth = 0f
        private var strokeColor: Int = R.color.color999999.getColor()
    
        private var backGroundColor: Int = R.color.white.getColor()    // 背景颜色
        private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
        
        constructor(context: Context) : super(context)
        constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
        constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle)
    
        /**
         * 设置圆角
         * @param backGroundColor  背景色
         * @param leftTopRadius     左上角
         * @param leftBottomRadius  左下角
         * @param rightBottomRadius 右下角
         * @param rightTopRadius    右上角
         * @param strokeWidth 边框宽度 dp f
         * @param strokeColor 边框颜色
         */
        fun setImageViewRadius(
            backGroundColor: Int = R.color.white,
            strokeWidth: Float = 0f,
            strokeColor: Int = R.color.colorB3B3B3,
            leftTopRadius: Int = 0,
            rightTopRadius: Int = 0,
            rightBottomRadius: Int = 0,
            leftBottomRadius: Int = 0
        ) {
            clearColorFilter()
            this.leftBottomRadius = leftBottomRadius.dp2px.toFloat()
            this.leftTopRadius = leftTopRadius.dp2px.toFloat()
            this.rightTopRadius = rightTopRadius.dp2px.toFloat()
            this.rightBottomRadius = rightBottomRadius.dp2px.toFloat()
            this.strokeWidth = Screen.dp2Px(strokeWidth).toFloat()
            this.strokeColor = strokeColor.getColor()
            this.backGroundColor = backGroundColor.getColor()
        }
    
        /**
         * 设置阴影
         * @param shadowWidth 阴影宽度 dp f
         * @param shadowColor 阴影颜色
         */
        fun setImageViewShadow(
            shadowWidth: Float = 0f,
            shadowColor: Int = R.color.colorB3B3B3
        ) {
            this.shadowWidth = Screen.dp2Px(shadowWidth).toFloat()
            this.shadowColor = shadowColor.getColor()
        }
    
        override fun onDraw(canvas: Canvas?) {
            getRadius()
            setDraw(canvas)
            super.onDraw(canvas)
        }
    
        private fun setDraw(canvas: Canvas?) {
            paint.color = strokeColor
            paint.isAntiAlias = true
            paint.style = Paint.Style.STROKE
            paint.strokeWidth = strokeWidth + if (backGroundColor != strokeColor) strokeWidth else 0f
            paint.setShadowLayer(shadowWidth, 0f, 0f, shadowColor)
    
            val path = Path()
            path.addRoundRect(shadowRectF, radiusArray, Path.Direction.CW)
            canvas?.drawPath(path, paint)
            canvas?.clipPath(path)
        }
    
        /**
         * 计算圆角等值
         */
        private fun getRadius() {
            radiusArray = floatArrayOf(
                leftTopRadius, leftTopRadius,
                rightTopRadius, rightTopRadius,
                rightBottomRadius, rightBottomRadius,
                leftBottomRadius, leftBottomRadius
            )
            shadowRectF = RectF(
                shadowWidth + strokeWidth,
                shadowWidth + strokeWidth,
                width - shadowWidth - strokeWidth,
                height - shadowWidth - strokeWidth
            )
        }
    
    }
    
    使用及效果
     <Button
                android:id="@+id/button"
                android:layout_width="200dp"
                android:layout_marginTop="20dp"
                android:text="button"
                android:gravity="center"
                android:layout_height="wrap_content"/>
    
    
        <com.wdslove.book.view.CustomImageView
                android:id="@+id/imageView"
                android:layout_width="200dp"
                android:text="customImageView"
                android:gravity="center"
                android:src="@mipmap/empty_loading"
                android:layout_marginTop="20dp"
                android:layout_height="200dp"/>
    
        <TextView
                android:id="@+id/textView"
                android:layout_width="200dp"
                android:text="textView"
                android:gravity="center"
                android:layout_marginTop="20dp"
                android:layout_height="40dp"/>
    
        <LinearLayout
                android:layout_width="200dp"
                android:id="@+id/linearLayout"
                android:layout_height="50dp"
                android:layout_marginTop="@dimen/rc_dimen_size_50"
                android:orientation="horizontal" />
    
    // 使用
    button.setRadius(strokeWidth = 10f,strokeColor = R.color.redF45265,backgroundColor = R.color.color999999,leftBottomRadius = 10,leftTopRadius = 40,rightBottomRadius = 20,rightTopRadius = 30)
    imageView.setRadius(strokeWidth = 2f,strokeColor = R.color.redF45265,backgroundColor = R.color.color999999,leftBottomRadius = 10,leftTopRadius = 40,rightBottomRadius = 100,rightTopRadius = 30)
    imageView.setShadow(shadowColor = R.color.color333333,shadowWidth = 5f)
    textView.setRadius(strokeWidth = 0.6f, strokeColor = R.color.colorCCCCCC, radius = 3)
    textView.setShadow(shadowColor = R.color.redF45265,shadowWidth = 4f)
    linearLayout.setRadius(strokeWidth = 0.6f, strokeColor = R.color.colorCCCCCC, radius = 3)
    linearLayout.setShadow(shadowColor = R.color.redF45265,shadowWidth = 4f)
    
    效果图.png

    不创建大量的drawable,也不用为太多的背景图命名烦恼,基本能满足开发的大部分需求, 欢迎指出问题和改进。

    相关文章

      网友评论

          本文标题:View自定义边框-Android

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