Skip to content

[syncfusion_flutter_pdfviewer] PdfViewerController.zoomLevel stays frozen during a live two-finger pinch gesture causing custom overlays to drift #2554

Description

@qusaiialkhalili-cyber

Bug Description

I am building a custom drawing/annotation layer (CustomPaint) that sits visually on top of SfPdfViewer, driven by PdfViewerController.scrollOffset and PdfViewerController.zoomLevel to keep the overlay aligned with the rendered PDF page during pan/zoom.

  • PdfViewerController.scrollOffset updates live, every frame, during a gesture.
  • PdfViewerController.zoomLevel, however, does not update during an active two-finger pinch gesture. It stays frozen at its pre-gesture value and is only updated once synchronously when the gesture ends.

Because there is no public way to read the live scale factor while a pinch gesture is in progress, any external widget that needs to stay visually locked to the PDF's current zoom level (annotations, custom markers, etc.) has no ground-truth scale to read mid-gesture. This causes visible misalignment/drift between the PDF layer and the overlay layer for the duration of the gesture.

Requested fix: Expose the live scale factor during an active gesture (e.g., updating zoomLevel continuously or adding an onZoomLevelChanging stream) so external overlays can stay pixel-locked mid-gesture.


Steps to Reproduce

  1. Run the minimal reproduction code below on a physical device (not an emulator).
  2. Perform a two-finger pinch-zoom (in or out) on the PDF.
  3. Keep your fingers on the screen (mid-gesture) and look at the live HUD overlay.
  4. Observe: The Scroll Offset updates instantly, but the Zoom Level stays completely frozen until you lift your fingers.

Minimal Repro Code:

import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_pdfviewer/pdfviewer.dart';

void main() => runApp(const MaterialApp(home: ZoomIssueRepro()));

class ZoomIssueRepro extends StatefulWidget {
  const ZoomIssueRepro({Key? key}) : super(key: key);

  @override
  State<ZoomIssueRepro> createState() => _ZoomIssueReproState();
}

class _ZoomIssueReproState extends State<ZoomIssueRepro> with SingleTickerProviderStateMixin {
  final PdfViewerController _pdfViewerController = PdfViewerController();
  late AnimationController _ticker;
  
  double _currentZoom = 1.0;
  Offset _currentScroll = Offset.zero;

  @override
  void initState() {
    super.initState();
    _ticker = AnimationController(vsync: this, duration: const Duration(seconds: 1))
      ..addListener(() {
        if (mounted) {
          setState(() {
            _currentZoom = _pdfViewerController.zoomLevel;
            _currentScroll = _pdfViewerController.scrollOffset;
          });
        }
      })
      ..repeat();
  }

  @override
  void dispose() {
    _ticker.dispose();
    _pdfViewerController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Zoom Level Frozen Repro')),
      body: Stack(
        children: [
          SfPdfViewer.network(
            '[https://cdn.syncfusion.com/content/PDFViewer/flutter-succinctly.pdf](https://cdn.syncfusion.com/content/PDFViewer/flutter-succinctly.pdf)',
            controller: _pdfViewerController,
            canShowScrollHead: false,
          ),
          Positioned(
            top: 20,
            left: 20,
            child: Container(
              padding: const EdgeInsets.all(12),
              decoration: BoxDecoration(
                color: Colors.black87,
                borderRadius: BorderRadius.circular(8),
              ),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  const Text('Live Controller Values (Every Frame):', style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold)),
                  const SizedBox(height: 8),
                  Text('Scroll Offset: ${_currentScroll.dx.toStringAsFixed(1)},${_currentScroll.dy.toStringAsFixed(1)}', style: const TextStyle(color: Colors.greenAccent, fontSize: 16)),
                  Text('Zoom Level: ${_currentZoom.toStringAsFixed(3)}', style: const TextStyle(color: Colors.redAccent, fontSize: 16)),
                  const SizedBox(height: 12),
                  const Text('Try two-finger pinch zoom.\nNotice the Zoom Level freezes mid-gesture!', style: TextStyle(color: Colors.white70, fontSize: 12)),
                ],
              ),
            ),
          ),
        ],
      ),
    );
  }
}

https://github.com/user-attachments/assets/baf938b1-0469-4df8-bef8-fe24a43935bb

Metadata

Metadata

Assignees

No one assigned

    Labels

    pdf viewerPDF viewer componentsolvedSolved the query using existing solutionswaiting for customer responseCannot make further progress until the customer responds.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions