0

I draw a rectangle, but the bottom edge looks thicker. How to fix this?

Box.kt

import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.Rect
import android.util.AttributeSet
import android.view.View

class Box : View
{
    var BoxBounds = Rect();
    private var BoxPaint: Paint? = null
    val BarHeight = 96;

    constructor(context: Context?) : super(context)
    {
        init();
    }

    constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
    {
        init();
    }

    private fun init()
    {
        BoxPaint = Paint(Paint.ANTI_ALIAS_FLAG);
        BoxPaint?.color = Color.GRAY;
        BoxPaint?.strokeWidth = 16f;
        BoxPaint?.style = Paint.Style.STROKE;
    }

    override fun onDraw(canvas: Canvas?)
    {
        super.onDraw(canvas)

        BoxPaint?.color = Color.GRAY;
        BoxPaint?.style = Paint.Style.STROKE;
        canvas?.drawRect(BoxBounds, BoxPaint)
    }

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int)
    {
        super.onSizeChanged(w, h, oldw, oldh)
        BoxBounds = Rect(0, 0, w, BarHeight);
    }
}

Fragment

<com.loser.Box
    android:layout_width="match_parent"
    android:layout_height="100dp"
    android:layout_margin="8dp"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintBottom_toBottomOf="parent"/>

enter image description here

Damn Vegetables
  • 11,484
  • 13
  • 80
  • 135

1 Answers1

1

As Damn Vegetables pointed out the problem was he was drawing outside the bounds of the view.

Here is my updated answer in which i have added an offset to counter that:

class Box : View {

    private val rect = Rect()
    private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
    private val density = resources.displayMetrics.density

    constructor(context: Context?) : this(context, null)
    constructor(context: Context?, attrs: AttributeSet?) : this(context, attrs, 0)
    constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
    // here you can do all your initialisation and retrieve custom styled attributes

        val strokeWidth = 2f  // this can be a style attribute we retrieve from xml if we get it from xml we don't need to use the density we will automaticly get the pixel size of the dimension and the system will make the conversion
        val color = Color.GRAY // this can be a style attribute we retrieve from xml

        paint.strokeWidth = strokeWidth * density
        paint.color = color
        paint.style = Paint.Style.STROKE

        // the init function is already in kotlin so if you what use an init function i suggest you call it something else
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        // this will get called everytime the size change so out dimensions will be right
        // if our view does not have special requirements regarding size we just call super but at this point we can get the actual size of the view so we will set the size of our box to match the size of the view

        val offset = paint.strokeWidth / 2f // offset used to keep the edges inside the visible rect

        rect.top = paddingTop + offset
        rect.left = paddingStart + offset
        rect.right = measuredWidth - paddingEnd - offset
        rect.bottom = measuredHeight - paddingBottom - offset
    }

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)

        canvas?.drawRect(rect, paint)
    }
}

To learn more about custom views checkout this article.

Mihai
  • 420
  • 6
  • 9
  • I used [this](https://stackoverflow.com/a/41689559/455796) to convert DP to float, and I changed RectF to Rect. But still, the bottom edge is thicker. I tried 1,2, and 4 with dipToPixels(). But the bottom is still thicker. Please see the image I will add to the OP. – Damn Vegetables Dec 23 '17 at 16:07
  • Do you do anything to the canvas (scale, translate, etc) , is this drawing on a bitmap off screen or inside a view (inside onDraw method). – Mihai Dec 23 '17 at 17:28
  • I do not think I did something unusual. I have updated the question with the complete source code that can reproduce the problem. Please have a look at that. – Damn Vegetables Dec 23 '17 at 17:47
  • Thank you. It seems that the problem was that other than the bottom edge, all other edges were clipped out, because part of the edges were drawn outside the visible view. And thank you also for other tips for implementing a custom view. – Damn Vegetables Dec 24 '17 at 02:53
  • Please demonstrate in your answer why It's solved the issue. –  Dec 24 '17 at 13:59
  • You are right i have updated my answer to reflect that (added offsets for the stroke width), i also added a link to a great article about custom views. – Mihai Dec 24 '17 at 14:03