Question

I have a custom view which is basically a circle that is either drawn with a fill paint or a stroke paint depending on a column from a database, thus making a filled circle or a ring.

My activity contains a grid of these circles, populated from the database, using a cursor adapter. In the bindView for the adapter, I set up properties on the custom view such as what color to make the circle and a boolean flag for whether or not to draw as a 'filled' circle or a ring.

public void bindView(View view, Context context, Cursor cursor) {
    CustomCircle circle = (CustomCircle) view.findViewById(R.id.custom_circle);

    // Set up the color of the Circle
    int index = cursor.getColumnIndex("Color");
    String colorString = "#" + cursor.getString(index);
    int color = Color.parseColor(colorString);
    circle.setFillColor(color);        

    // Set up the layout of the circle
    index = cursor.getColumnIndex("count");
    int totalCount = cursor.getInt(index);
    if (totalCount > 0)
    {
        circle.setFillInCircle(true);
    }
}

Inside the onSizeChanged for the custom view I have to modify the diameter to adjust for the stroke size because stroke width grows in an equal distance toward and away from the center of the circle.

On the initial OnCreateView call I set up the cursor adapter with a call to get all elements in order by color. This initially looks fine as all elements are marked to draw as rings as default. However, the problem starts occurring once I modify one of the circle elements on the top row or bottom row of the grid view (one of these rows will be out of view when the other is in view due to the size of the screen) to be 'filled'.

Now, erratically, I see behavior where some of the elements on either end will be drawn as filled circles but with the small diameter intended for the stroke style. This includes both custom views with the fill turned on and custom views next to them that are not turned on. You can scroll up and back down and they circles will have a different configuration!

Breakpoints in the onDraw call reveal scenarios where the reported radius is the smaller style but the flag for filling is turned on (when it should be off).

So I'm trying to figure out what is happening during the scroll. What I assumed was that the cursor adapter will lazily re-bind elements, thus updating all the necessary properties, and then onSizeChanged will be called, thus ensuring my logic is sound. Unfortunately, it appears onSizeChanged is firing only sometimes.

What, in terms of view binding, onSizeChanged, and onDraw, is expected to occur during scroll of a grid mapped to data with a cursor adapter?

Was it helpful?

Solution

I found the solution - it was two problems.

First, there is no guarantee of onSizeChanged executing while scrolling. I moved the logic to onMeasure and ensured I was calling requestLayout() to get the proper diameter.

Second, adapters re-use visuals. This means you have to update every property to ensure they're correct; you have no guarantee of class defaults being true. In my case I updated the above method to read as such:

public void bindView(View view, Context context, Cursor cursor) {
    CustomCircle circle = (CustomCircle) view.findViewById(R.id.custom_circle);

    // Set up the color of the Circle
    int index = cursor.getColumnIndex("Color");
    String colorString = "#" + cursor.getString(index);
    int color = Color.parseColor(colorString);
    circle.setFillColor(color);        

    // Set up the layout of the circle
    index = cursor.getColumnIndex("count");
    int totalCount = cursor.getInt(index);
    if (totalCount > 0)
    {
        circle.setFillInCircle(true);
    }
    else
    {
        circle.setFillInCircle(false);
    }
}

These combined solved the problem.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top