Eliminate stroke commit flicker with pending path overlay
When the pen lifts, the in-progress path was cleared immediately but the completed stroke didn't appear on the backing bitmap until the async DB save completed — creating a visible flash where the stroke vanished for several frames. Fix: transfer the completed path to a "pending" overlay that stays visible in the dynamic layer until addCompletedStroke() confirms the stroke is on the backing bitmap. The stroke is now visible continuously from pen-down through commit with no gap. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -58,6 +58,12 @@ class PadCanvasView(context: Context) : View(context) {
|
|||||||
private var currentPaint: Paint? = null
|
private var currentPaint: Paint? = null
|
||||||
private val currentPoints = mutableListOf<Float>()
|
private val currentPoints = mutableListOf<Float>()
|
||||||
|
|
||||||
|
// --- Pending stroke: keeps the last completed stroke visible until
|
||||||
|
// the backing bitmap confirms it, preventing the flash where the
|
||||||
|
// stroke disappears between pen-up and DB save completion ---
|
||||||
|
private var pendingPath: Path? = null
|
||||||
|
private var pendingPaint: Paint? = null
|
||||||
|
|
||||||
// --- Line snap ---
|
// --- Line snap ---
|
||||||
private var strokeOriginX = 0f
|
private var strokeOriginX = 0f
|
||||||
private var strokeOriginY = 0f
|
private var strokeOriginY = 0f
|
||||||
@@ -255,6 +261,9 @@ class PadCanvasView(context: Context) : View(context) {
|
|||||||
} else {
|
} else {
|
||||||
bitmapDirty = true
|
bitmapDirty = true
|
||||||
}
|
}
|
||||||
|
// Stroke is now on the backing bitmap — clear the pending overlay
|
||||||
|
pendingPath = null
|
||||||
|
pendingPaint = null
|
||||||
invalidate()
|
invalidate()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -310,6 +319,13 @@ class PadCanvasView(context: Context) : View(context) {
|
|||||||
|
|
||||||
// Dynamic elements
|
// Dynamic elements
|
||||||
c.withMatrix(viewMatrix) {
|
c.withMatrix(viewMatrix) {
|
||||||
|
// Pending stroke (visible until backing bitmap confirms it)
|
||||||
|
pendingPath?.let { path ->
|
||||||
|
pendingPaint?.let { paint ->
|
||||||
|
drawPath(path, paint)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// In-progress stroke
|
||||||
currentPath?.let { path ->
|
currentPath?.let { path ->
|
||||||
currentPaint?.let { paint ->
|
currentPaint?.let { paint ->
|
||||||
drawPath(path, paint)
|
drawPath(path, paint)
|
||||||
@@ -581,6 +597,10 @@ class PadCanvasView(context: Context) : View(context) {
|
|||||||
isSnappedToLine = false
|
isSnappedToLine = false
|
||||||
if (currentPoints.size >= 4) {
|
if (currentPoints.size >= 4) {
|
||||||
val points = currentPoints.toFloatArray()
|
val points = currentPoints.toFloatArray()
|
||||||
|
// Keep the path visible as "pending" until the backing
|
||||||
|
// bitmap confirms the stroke (prevents flash on commit)
|
||||||
|
pendingPath = currentPath
|
||||||
|
pendingPaint = currentPaint
|
||||||
onStrokeCompleted?.invoke(canvasState.penWidthPt, Color.BLACK, points, Stroke.STYLE_PLAIN)
|
onStrokeCompleted?.invoke(canvasState.penWidthPt, Color.BLACK, points, Stroke.STYLE_PLAIN)
|
||||||
}
|
}
|
||||||
currentPath = null
|
currentPath = null
|
||||||
|
|||||||
Reference in New Issue
Block a user