I've got a chinese 1.44" TFT - very similar to AdaFruit's. In fact, I think it's the same and the Adafruit ST7735 library works great with it right away.
But I have a problem: the screen is too slow to update and flickers too much. Even if I only update it once per second the flickering is still very noticeable and prevents me from achieving visual smoothness, which I will need for my project.
Upon some googling I came across the PDQ GFX library, it claims to be a drop-in replacement for Adafruit's but much better optimized. So I use that in my sketch now. I thing it's a bit better with this library, but not much.
Here's my sketch code for the moment.
#define TFT_RST 0  // you can also connect this to the Arduino reset, in which case, set this #define pin to 0!
#include "PDQ_ST7735_config.h"
#include <PDQ_FastPin.h>
#include <PDQ_ST7735.h>
#include <gfxfont.h>
#include <PDQ_GFX.h>
#include <TimerOne.h>
#include <StandardCplusplus.h>
#include <SPI.h>
#include <algorithm>
#include <math.h>
#define analogInPin A0
uint16_t sample = 0, maxSampleValue = 0;
#ifndef _PDQ_ST7735H_
Adafruit_ST7735 tft = Adafruit_ST7735(ST7735_CS_PIN,  ST7735_DC_PIN, TFT_RST);
#else
PDQ_ST7735 tft;
#endif
void setup() {
  // initialize serial communications at 9600 bps:
  Serial.begin(9600);
  while (!Serial);
  // Use this initializer if you're using a 1.8" TFT
  //tft.initR(INITR_BLACKTAB);   // initialize a ST7735S chip, black tab
  // Use this initializer (uncomment) if you're using a 1.44" TFT
  tft.initR(ST7735_INITR_144GREENTAB);   // initialize a ST7735S chip, black tab
  tft.setTextSize(3);
  tft.fillScreen(ST7735_BLACK);
  Timer1.initialize(100L * 1000L); // initialize timer1, 1/30th sec period
  Timer1.attachInterrupt(updateScreen);
  Serial.println("Initialized");
}
template <typename T> void printNumber(T number, uint16_t color, bool newLineAfter = false)
{
  tft.setTextColor(color);
  if (newLineAfter)
    tft.println(number);
  else
    tft.print(number);  
}
inline uint16_t RGB888_to_565(uint8_t R, uint8_t G, uint8_t B)
{
  return
    (((R >> 3) & 0x1f) << 11) |
    (((G >> 2) & 0x3f) <<  6) |
    (((B >> 3) & 0x1f)      );
}
void loop() {
  // read the analog in value:
  sample = analogRead(analogInPin);
  maxSampleValue = std::max(maxSampleValue, sample);
  // print the results to the serial monitor:
  Serial.print("sensor = ");
  Serial.println(maxSampleValue);
  delay(1);
}
void updateScreen()
{
  tft.fillRect(0, 0, 100, 40, ST7735_BLACK);
  static const auto textColor1 = RGB888_to_565(255, 235, 0);
  static const auto textColor2 = RGB888_to_565(255, 0, 200);
  
  tft.setTextSize(3);
  tft.setCursor(0, 0);
  printNumber(sample, textColor1);
  tft.setTextSize(2);
  tft.setCursor(0, 25);
  tft.print("Max: ");
  printNumber(maxSampleValue, textColor2);
}
Note that I have set up a timer using the TimerOne library, it's currently set for 100 ms = 10 FPS. But as I said, the code speed is not the problem, I can get higher FPS. It's flickering that's the problem.
I have then tried to bring down the amount of pixels re-painted in updateScreen() even further. I did two things differently here: moved the static "Max:" label out of the update routine, and instead of clearing the previous contents with fillRect() I just draw the same number in black. That did not bring any improvement to speak of.
You can view the updated code in this gist or in the following code section:
#define TFT_RST 0  // you can also connect this to the Arduino reset, in which case, set this #define pin to 0!
#include "PDQ_ST7735_config.h"
#include <PDQ_FastPin.h>
#include <PDQ_ST7735.h>
#include <gfxfont.h>
#include <PDQ_GFX.h>
#include <TimerOne.h>
#include <StandardCplusplus.h>
#include <SPI.h>
#include <algorithm>
#include <math.h>
#define analogInPin A0
uint16_t sample = 0, maxSampleValue = 0;
#ifndef _PDQ_ST7735H_
Adafruit_ST7735 tft = Adafruit_ST7735(ST7735_CS_PIN,  ST7735_DC_PIN, TFT_RST);
#else
PDQ_ST7735 tft;
#endif
void setup() {
  // initialize serial communications at 9600 bps:
  Serial.begin(9600);
  while (!Serial);
  // Use this initializer if you're using a 1.8" TFT
  //tft.initR(INITR_BLACKTAB);   // initialize a ST7735S chip, black tab
  // Use this initializer (uncomment) if you're using a 1.44" TFT
  tft.initR(ST7735_INITR_144GREENTAB);   // initialize a ST7735S chip, black tab
  tft.setTextSize(3);
  tft.fillScreen(ST7735_BLACK);
  tft.setCursor(0, 25);
  tft.setTextSize(2);
  tft.print("Max: ");
  Timer1.initialize(100L * 1000L); // initialize timer1, 1/30th sec period
  Timer1.attachInterrupt(updateScreen);
  Serial.println("Initialized");
}
template <typename T> void printNumber(T number, uint16_t color, bool newLineAfter = false)
{
  tft.setTextColor(color);
  if (newLineAfter)
    tft.println(number);
  else
    tft.print(number);  
}
inline uint16_t RGB888_to_565(uint8_t R, uint8_t G, uint8_t B)
{
  return
    (((R >> 3) & 0x1f) << 11) |
    (((G >> 2) & 0x3f) <<  6) |
    (((B >> 3) & 0x1f)      );
}
void loop() {
  // read the analog in value:
  sample = analogRead(analogInPin);
  maxSampleValue = std::max(maxSampleValue, sample);
  // print the results to the serial monitor:
  Serial.print("sensor = ");
  Serial.println(maxSampleValue);
  delay(1);
}
const auto textColor1 = RGB888_to_565(255, 235, 0);
const auto textColor2 = RGB888_to_565(255, 0, 200);
void updateScreen()
{  
  tft.setTextSize(3);
  tft.setCursor(0, 0);
  printNumber(10, 0);
  tft.setCursor(0, 0);
  printNumber(10, textColor1);
  tft.setTextSize(2);
  tft.setCursor(70, 30);
  printNumber(20, 0);
  tft.setCursor(70, 30);
  printNumber(20, textColor2);
}
What can I do to improve the perceived smoothness of this screen's re-draw? Guess I'll have to shoot 60 FPS video of the screen to see what exactly it's doing, but it looks like it goes to black for significant amount of time before drawing the new contents. It's as if fillRect() is carried out extra fast, and then it takes a long while for the numbers to show up.
Note that my project requires drawing complex geometry across the whole screen, and optimizing its re-draw (e. g. only updating the pixels that actually changed) will not be feasible because Arduino Uno lacks the RAM required for that (calculating diff between two frames, even in 1-bit color).
What I'm aiming to achieve in the end is this (note how smooth it is): Arduino simple audio spectrum analyzer on OLED SSD1306 display - YouTube
Granted, that's an OLED display and a different controller. But is it really not doable with a TFT?
The sketch and all the required libraries are on Github in case you care to fiddle with it: GitHub - VioletGiraffe/ArduinoAudioSpectrumAnalyzer