turnable_page 0.0.1 copy "turnable_page: ^0.0.1" to clipboard
turnable_page: ^0.0.1 copied to clipboard

Realistic page-flipping widget for Flutter with smooth animations and responsive layout.

Turnable Page #

A Flutter package that provides a realistic page-flipping effect for digital books, magazines, catalogs, and other multi-page content in Flutter applications.

Features #

Realistic Physics: Advanced flip animations with proper physics and shadows
Touch Support: Full touch and gesture support for mobile devices
Multiple Orientations: Automatic portrait/landscape orientation handling
Widget Support: Use any Flutter widget as page content
Customizable: Extensive configuration options
Performance: Hardware-accelerated rendering for smooth 60fps animations
Events: Rich event system for interaction handling
Responsive: Auto-sizing and responsive layout support
Cross-Platform: Supports Mobile, Web, and Windows

Note: Widgets inside book pages are currently non-interactive (taps/gestures inside a page are not forwarded to child widgets).

Demo (GIF) #

Animated GIF previews below. On pub.dev, demo assets under videos/ are excluded to reduce package size; view them on GitHub.

Desktop flipping #

[Desktop flipping]

Mobile flipping #

[Mobile flipping]

Responsiveness #

[Responsiveness]

Installation #

Add this to your package's pubspec.yaml file:

dependencies:
  turnable_page: ^0.0.1

Then run:

flutter pub get

Basic Usage #

Simple Widget-Based Book #

import 'package:flutter/material.dart';
import 'package:turnable_page/turnable_page.dart';

class MyBook extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: SizedBox(
          width: 400,
          height: 600,
          child: TurnablePage(
            pageCount: 6,
            pageBuilder: (index, constraints) {
              return Container(
                decoration: BoxDecoration(
                  color: Colors.white,
                  border: Border.all(color: Colors.grey),
                ),
                child: Center(
                  child: Text(
                    'Page ${index + 1}',
                    style: TextStyle(fontSize: 24),
                  ),
                ),
              );
            },
          ),
        ),
      ),
    );
  }
}

With Controller and Events #

class BookWithController extends StatefulWidget {
  @override
  _BookWithControllerState createState() => _BookWithControllerState();
}

class _BookWithControllerState extends State<BookWithController> {
  late PageFlipController _controller;
  int _currentPage = 0;

  @override
  void initState() {
    super.initState();
    _controller = PageFlipController();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Page ${_currentPage + 1}'),
        actions: [
          IconButton(
            icon: Icon(Icons.arrow_back),
            onPressed: _controller.hasPreviousPage 
              ? () => _controller.previousPage() 
              : null,
          ),
          IconButton(
            icon: Icon(Icons.arrow_forward),
            onPressed: _controller.hasNextPage 
              ? () => _controller.nextPage() 
              : null,
          ),
        ],
      ),
      body: TurnablePage(
        controller: _controller,
        pageCount: 10,
        onPageChanged: (leftIndex, rightIndex) {
          setState(() {
            _currentPage = leftIndex;
          });
        },
        pageBuilder: (index, constraints) {
          return Container(
            color: Colors.primaries[index % Colors.primaries.length],
            child: Center(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  Text(
                    'Page ${index + 1}',
                    style: TextStyle(fontSize: 32, color: Colors.white),
                  ),
                  SizedBox(height: 20),
                  Icon(
                    Icons.book,
                    size: 64,
                    color: Colors.white,
                  ),
                ],
              ),
            ),
          );
        },
      ),
    );
  }
}

Advanced Configuration #

TurnablePage(
  pageCount: 20,
  pageBuilder: pageBuilder,
  controller: controller,
  onPageChanged: onPageChanged,
  
  // Visual appearance
  pageViewMode: PageViewMode.single, // or PageViewMode.double
  pixelRatio: 3.0,
  aspectRatio: 2/3, // Custom aspect ratio
  autoResponseSize: true,
  paperBoundaryDecoration: PaperBoundaryDecoration.vintage,
  
  // Flip settings
  settings: FlipSettings(
    // Page positioning
    startPageIndex: 0,
    
    // Size configuration
    size: SizeType.fixed, // or SizeType.stretch
    width: 400.0,
    height: 600.0,
    
    // Visual effects
    drawShadow: true,
    maxShadowOpacity: 1.0,
    showPageCorners: true,
    
    // Animation
    flippingTime: 700, // milliseconds
    
    // Behavior
    usePortrait: true,
    showCover: false,
    mobileScrollSupport: true,
    clickEventForward: false,
    swipeDistance: 100.0,
    disableFlipByClick: false,
  ),
)

API Reference #

TurnablePage Widget #

The main widget for creating a page-flipping book interface.

Constructor

TurnablePage({
  Key? key,
  PageFlipController? controller,
  double? aspectRatio,
  required TurnableBuilder pageBuilder,
  required int pageCount,
  TurnablePageCallback? onPageChanged,
  PageViewMode pageViewMode = PageViewMode.single,
  double pixelRatio = 3.0,
  bool autoResponseSize = true,
  PaperBoundaryDecoration paperBoundaryDecoration = PaperBoundaryDecoration.vintage,
  FlipSettings? settings,
})

Parameters

  • controller - Optional controller for programmatic page control
  • pageBuilder - Builder function that creates widget content for each page
  • pageCount - Total number of pages in the book
  • onPageChanged - Callback fired when page changes
  • pageViewMode - Display mode: single page or double page spread
  • pixelRatio - Rendering pixel ratio for quality
  • autoResponseSize - Whether to automatically adjust size to container
  • aspectRatio - Custom aspect ratio for the book
  • paperBoundaryDecoration - Visual style for page boundaries
  • settings - Detailed flip behavior configuration

PageFlipController #

Controller class for programmatic page manipulation.

Methods

  • nextPage() - Turn to the next page (without animation)
  • previousPage() - Turn to the previous page (without animation)
  • goToPage(int pageIndex) - Jump to a specific page (without animation)
  • flipNext([FlipCorner corner]) - Flip to next page with animation
  • flipPrev([FlipCorner corner]) - Flip to previous page with animation
  • flipToPage(int pageIndex, [FlipCorner corner]) - Flip to specific page with animation

Properties

  • currentPageIndex - Get current page index (0-based)
  • pageCount - Get total number of pages
  • hasNextPage - Check if next page is available
  • hasPreviousPage - Check if previous page is available
  • canFlipNext - Check if can flip to next page
  • canFlipPrev - Check if can flip to previous page

FlipSettings Configuration #

Configuration object for customizing flip behavior and appearance.

Constructor Parameters

Parameter Type Default Description
startPageIndex int 0 Initial page to display (0-based index)
size SizeType SizeType.fixed Size calculation: fixed dimensions or stretch to fit
width double 0 Width of the book in pixels
height double 0 Height of the book in pixels
drawShadow bool true Whether to draw realistic shadow effects
flippingTime int 700 Duration of flip animation in milliseconds
usePortrait bool true Portrait mode (single page) vs landscape (two-page spread)
maxShadowOpacity double 1.0 Maximum opacity for shadow effects (0.0 to 1.0)
showCover bool false Whether the book has a front/back cover
mobileScrollSupport bool true Enable touch scrolling on mobile devices
clickEventForward bool false Whether click events propagate to parent widgets
swipeDistance double 100.0 Minimum distance in pixels for swipe gesture
showPageCorners bool true Show interactive corner highlighting on hover
disableFlipByClick bool false Disable page flipping via click (drag only)

PageViewMode

  • PageViewMode.single - Single page view (portrait orientation)
  • PageViewMode.double - Double page spread (landscape orientation)

SizeType

  • SizeType.fixed - Fixed dimensions specified by width/height
  • SizeType.stretch - Stretch to fit parent container

FlipCorner

  • FlipCorner.topLeft - Flip from top-left corner
  • FlipCorner.topRight - Flip from top-right corner
  • FlipCorner.bottomLeft - Flip from bottom-left corner
  • FlipCorner.bottomRight - Flip from bottom-right corner

PaperBoundaryDecoration

  • PaperBoundaryDecoration.vintage - Vintage paper styling
  • PaperBoundaryDecoration.modern - Modern clean styling
  • PaperBoundaryDecoration.parchment - Parchment-style textured paper with warm, aged tones

Examples #

Note: Image-based examples inside the book have been temporarily removed and will be added in a future update.

Basic Book Reader with Navigation #

class BookReader extends StatefulWidget {
  @override
  _BookReaderState createState() => _BookReaderState();
}

class _BookReaderState extends State<BookReader> {
  late PageFlipController _controller;
  int _currentPage = 0;
  
  final List<Color> _pageColors = [
    Colors.red,
    Colors.blue,
    Colors.green,
    Colors.orange,
    Colors.purple,
    Colors.teal,
  ];
  
  @override
  void initState() {
    super.initState();
    _controller = PageFlipController();
  }
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Book Reader'),
        actions: [
          IconButton(
            icon: Icon(Icons.first_page),
            onPressed: () => _controller.goToPage(0),
          ),
          IconButton(
            icon: Icon(Icons.arrow_back),
            onPressed: _controller.hasPreviousPage 
              ? () => _controller.flipPrev() 
              : null,
          ),
          Container(
            padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
            child: Center(
              child: Text('${_currentPage + 1} / ${_pageColors.length}'),
            ),
          ),
          IconButton(
            icon: Icon(Icons.arrow_forward),
            onPressed: _controller.hasNextPage 
              ? () => _controller.flipNext() 
              : null,
          ),
          IconButton(
            icon: Icon(Icons.last_page),
            onPressed: () => _controller.goToPage(_pageColors.length - 1),
          ),
        ],
      ),
      body: TurnablePage(
        controller: _controller,
        pageCount: _pageColors.length,
        onPageChanged: (leftIndex, rightIndex) {
          setState(() {
            _currentPage = leftIndex;
          });
        },
        settings: FlipSettings(
          showCover: true,
          drawShadow: true,
          flippingTime: 600,
        ),
        pageBuilder: (index, constraints) {
          return Container(
            decoration: BoxDecoration(
              color: _pageColors[index % _pageColors.length],
              borderRadius: BorderRadius.circular(8),
              boxShadow: [
                BoxShadow(
                  color: Colors.black26,
                  blurRadius: 4,
                  offset: Offset(2, 2),
                ),
              ],
            ),
            child: Center(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  Icon(
                    Icons.auto_stories,
                    size: 64,
                    color: Colors.white,
                  ),
                  SizedBox(height: 20),
                  Text(
                    'Page ${index + 1}',
                    style: TextStyle(
                      fontSize: 32,
                      fontWeight: FontWeight.bold,
                      color: Colors.white,
                    ),
                  ),
                  SizedBox(height: 10),
                  Text(
                    'This is the content of page ${index + 1}',
                    style: TextStyle(
                      fontSize: 16,
                      color: Colors.white70,
                    ),
                    textAlign: TextAlign.center,
                  ),
                ],
              ),
            ),
          );
        },
      ),
    );
  }
}

Architecture #

This package provides the following architecture:

Core Components #

  1. TurnablePage - Main widget that provides the page-flipping interface
  2. TurnablePageView - Internal view that handles rendering and animations
  3. PageFlipController - Controller for programmatic page management
  4. PageFlip - Core logic engine that handles flip calculations and state
  5. FlipSettings - Configuration object for customizing behavior

Key Features #

  • Widget-Based Pages: Use any Flutter widget as page content through the pageBuilder function
  • Hardware Acceleration: Leverages Flutter's rendering engine for smooth animations
  • Responsive Design: Automatic adaptation between portrait and landscape modes
  • Touch Gestures: Full support for swipe, drag, and tap interactions
  • Event System: Comprehensive callbacks for page change events
  • Customizable Styling: Extensive configuration options for appearance and behavior

Performance Tips #

  1. Optimize Page Content: Keep page widgets lightweight and avoid heavy computations in pageBuilder
  2. Use Appropriate Pixel Ratio: Higher values improve quality but impact performance
  3. Limit Page Count: Very large books may impact memory usage
  4. Efficient Assets: Keep media lightweight; image-based page examples will be added in a future update

Responsive Design #

// Automatic responsive behavior
TurnablePage(
  autoResponseSize: true,      // Adapts to device size only in single mode
  pageViewMode: PageViewMode.single, // Switches based on screen size
  // ...
)

Custom Page Layouts #

Widget buildCustomPage(int index, BoxConstraints constraints) {
  return Container(
    padding: EdgeInsets.all(16),
    child: Column(
      children: [
        // Header
        Container(
          height: 60,
          child: Text('Chapter $index'),
        ),
        
        // Content area
        Expanded(
          child: YourContentWidget(pageIndex: index),
        ),
        
        // Footer
        Container(
          height: 40,
          child: Text('Page ${index + 1}'),
        ),
      ],
    ),
  );
}

Troubleshooting #

Common Issues #

Pages not rendering correctly:

  • Ensure pageCount matches your actual content
  • Check that pageBuilder returns valid widgets for all indices
  • Verify container constraints are properly set

Performance issues:

  • Reduce pixelRatio if animations are choppy
  • Optimize page widget complexity
  • Consider lazy loading for large content

Touch gestures not working:

  • Ensure mobileScrollSupport is enabled
  • Check swipeDistance threshold
  • Verify no conflicting gesture detectors in parent widgets

Layout issues on different screen sizes:

  • Use autoResponseSize: true for automatic adaptation
  • Test on various screen sizes and orientations
  • Consider using LayoutBuilder for custom responsive behavior

Roadmap #

  • ✅ Core page flipping logic
  • ✅ Widget-based pages
  • ✅ Touch/gesture handling
  • ✅ Event system and callbacks
  • ✅ Hardware-accelerated rendering
  • ✅ Responsive design support
  • ✅ Portrait/landscape orientation
  • ✅ Customizable animations and effects
  • ❌ PDF document support
  • ❌ Enhanced accessibility features
  • ❌ Advanced gesture recognition
  • ❌ Bookmark and navigation features

Contributing #

Contributions are welcome! Feel free to open issues and PRs to improve the package.

Development Setup #

  1. Clone the repository:
git clone https://github.com/saeedahmed725/turnable_page.git
cd turnable_page
  1. Install dependencies:
flutter pub get
  1. Run the example:
cd example
flutter run

Guidelines #

  • Keep the public API stable when possible and document any changes
  • Follow Flutter development best practices
  • Include tests for new features
  • Update documentation for any API changes
  • Ensure backward compatibility

License #

This project is distributed under the Turnable Page Proprietary License (TPPL). Usage, redistribution, and modification are not permitted except via approved pull requests in the official GitHub repository. See the LICENSE file for full terms.

Credits #

  • Built with ❤️ for the Flutter community

Support #

If you find this package helpful, please:

  • ⭐ Star the repository on GitHub
  • 🐛 Report issues on GitHub Issues
  • 💡 Suggest features and improvements
  • 📖 Contribute to documentation

For support and questions, please use GitHub Issues or start a discussion in the repository.

32
likes
0
points
132
downloads

Publisher

unverified uploader

Weekly Downloads

Realistic page-flipping widget for Flutter with smooth animations and responsive layout.

Homepage
Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

flutter

More

Packages that depend on turnable_page