material-calendarview
material-calendarview copied to clipboard
Selection circle flickers
When setting the height and width of the tile to be different, and then calling invalidateDecorators, the selected date's background circle will 'flicker'. It will at first appear to be sized as an oval shape, before correctly resizing itself to be a circle.
This is most easily replicable in the Custom tile width/height example.
- Open CustomTileDimensions.java
- set an onDateChangedListener to the widget.
- In the onDateSelected method of the listener call
widget.invalidateDecorators()
- Launch the app and navigate to the example
- Change the tile height from the default, but leave the width alone
- Note that upon selecting a new date, the selection circle will now 'flicker'
may be are you creating a new circle every time?
@pavelaizen Invalidating decorators does indeed trigger a new Drawable to be created. More specifically when the decorators are invalidated, eventually the DayView are as well, which triggers DayView.regenerateBackground(), which in turn generates a new Drawable that is then set to the background.
The issue is that when that drawable is set to the background, it's bounds are not also immediately set, causing it to appear stretched for several frames, even though the DayView.onDraw(Canvas canvas) does explicitly set the bounds. While doing some investigation into the issue, I noted that even inserting calls to setBounds
inside of regenerateBackground
has no effect, i.e. the drawable still appears stretched for several frames before the new bounds take effect.
While the root issue of why the bounds do not immediately take effect requires more research, a temporary fix could be to set the alpha of the drawable to 0 in regenerateBackground
and then in onDraw
set it to 255. There will be a slight delay of several frames before the background updates, which may be preferable to the current flickering behavior.
Yes! I also meet this issue? how do you fix it?need help !!
The issue seems to be that View#drawBackground
automatically sets the bounds of the background drawable to fill the view. However, this only happens when the internal flag mBackgroundSizeChanged
is true
. So on the first drawing pass, View#drawBackground
sets the bounds of mCircleView
to fill the view, overwriting the value set in DayView#onDraw
. On the next drawing pass, mBackgroundSizeChanged
is now false
, so the bounds value set in DayView#onDraw
sticks.
One potential fix is to have DayView#generateCircleDrawable
return an InsetDrawable
with the appropriate insets generated from circleDrawableRect
. Then you don't need to call mCircleDrawable.setBounds(circleDrawableRect)
at all.
One additional thing to note from the docs: View#setBackground
sets the view's padding to the background's padding. So after calling View#setBackgroundDrawable
in DayView#regenerateBackground
, you need to call this.setPadding(0,0,0,0);
to clear the padding that was applied to the DayView, otherwise the day text will be off center.
@jmarr can you explain this ? for code example what i can do?
@jrafaelahmedov
code like this as @mogren1158 it works !
@Override protected void onDraw(@NonNull Canvas canvas) { if (customBackground != null) { customBackground.setBounds(tempRect); customBackground.setState(getDrawableState()); customBackground.draw(canvas); } mCircleDrawable.setBounds(circleDrawableRect); mCircleDrawable.setAlpha(255); super.onDraw(canvas); }
private void regenerateBackground() {
if (selectionDrawable != null) {
mCircleDrawable.setAlpha(0);
setBackground(selectionDrawable);
} else {
mCircleDrawable = generateBackground(selectionColor, fadeTime, circleDrawableRect);
mCircleDrawable.setAlpha(0);
setBackground(mCircleDrawable);
}
}