My app includes a filled rect which must move left and right one pixel at a time. The simplistic way to move it is to call fillRect with background color and call it again with new coordinates and foreground color. That is slow and causes flicker. A better way is to redraw only the pixels which must change. Call drawFastVLine for the leading edge in foreground color and call it again for the trailing edge in background color. It's efficient and prevents flicker. I call it differential animation.

I also have a filled circle to move, but that's more complex. You might think to call drawCircleHelper for a semicircle at the trailing edge in background color and call it again for a shifted semicircle in foreground color. But that doesn't quite work because the trailing semicircle removes too many edge pixels in the upper and lower octants. One fix is to draw a shifted full circle in foreground color to restore the edges. That looks good but it really draws about twice as many pixels as needed. An optimal solution is to draw leading and trailing semicircles, but replace the horizontal line segments with only endpoints.

Here's the code, adapted from drawCircleHelper. I also pulled the first segments out of the loop and combined them to cover the left and right edges completely. I hope someone will find it useful.

Code:

// Shift a filled circle left or right by 1 pixel. Draws only leading and trailing edge pixels.
// Adapted from ILI9341_t3::drawCircleHelper
void shiftCircle( int16_t x0, int16_t y0, int16_t r, uint16_t lcol, uint16_t rcol) {
int16_t f = 1 - r;
int16_t ddFx = 1;
int16_t ddFy = -2 * r;
int16_t x = 0;
int16_t y = r;
int xold;
xold = x;
while (f<0) {
x++;
ddFx += 2;
f += ddFx;
} // draw first line segments
tft.drawFastVLine(x0+y+1, y0-x, x-xold+x-xold+1, rcol);
tft.drawPixel(x0+x+1, y0+y, rcol);
tft.drawPixel(x0+x+1, y0-y, rcol);
tft.drawPixel(x0-x, y0+y, lcol);
tft.drawPixel(x0-x, y0-y, lcol);
tft.drawFastVLine(x0-y, y0-x, x-xold+x-xold+1, lcol);
xold = x;
while (x<y) {
if (f >= 0) {
y--;
ddFy += 2;
f += ddFy;
}
x++;
ddFx += 2;
f += ddFx;
if (f >= 0 || x == y) { // time to draw the next line segments
tft.drawPixel(x0+x+1, y0+y, rcol);
tft.drawFastVLine(x0+y+1, y0+xold+1, x-xold, rcol);
tft.drawPixel(x0+x+1, y0-y, rcol);
tft.drawFastVLine(x0+y+1, y0-x, x-xold, rcol);
tft.drawFastVLine(x0-y, y0+xold+1, x-xold, lcol);
tft.drawPixel(x0-x, y0+y, lcol);
tft.drawFastVLine(x0-y, y0-x, x-xold, lcol);
tft.drawPixel(x0-x, y0-y, lcol);
xold = x;
}
}
}