skip to Main Content

should not be turned more than 90 degrees from above and below. Currently, the bottom part is working as expected, but the top part is lagging behind before. it should be fixed, that is, the upper part should be the same as the lower part.[enter image description here](https://i.sstatic.net/0bZ5H33C.png)

import 'package:flip_widget_flutter/flip_widget_flutter.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'dart:math' as math;

class BookPages extends StatefulWidget {
  final String url;
  final String title;

  const BookPages({Key? key, required this.url, required this.title})
      : super(key: key);

  @override
  State<BookPages> createState() => _BookPageState();
}

class _BookPageState extends State<BookPages> {
  final List<String> pages = [
    'Page 1',
    'Page 2',
    'Page 3',
    // Add more pages as needed
  ];

  double _minNumber = 0.008;
  int currentPage = 0;
  GlobalKey<FlipWidgetState> _flipKey = GlobalKey();
  Offset _oldPosition = Offset.zero;
  bool _isFlipping = false;

  double _clampMin(double v) {
    if (v < _minNumber && v > -_minNumber) {
      if (v >= 0) {
        v = _minNumber;
      } else {
        v = -_minNumber;
      }
    }
    return v;
  }

  @override
  Widget build(BuildContext context) {
    Size size = Size(256, 256);
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: GestureDetector(
        child: FlipWidget(
          key: _flipKey,
          textureSize: size * 6,
          child: Stack(
            children: [
              _buildPage(currentPage),
              _buildPage(currentPage + 1),
            ],
          ),
        ),
        onHorizontalDragStart: (details) {
          if (!_isFlipping) {
            _oldPosition = details.globalPosition;
            _flipKey.currentState?.startFlip();
          }
        },
        onHorizontalDragUpdate: (details) {
          if (!_isFlipping) {
            Offset off = details.globalPosition - _oldPosition;
            double tilt = 1 / _clampMin((-off.dy + 20) / 100);
            double percent = math.max(0, -off.dx / (size.width * 1.4));
            percent = math.min(1.0, percent);
            percent = percent - percent / 2 * (1 - 1 / tilt);

            // Ensure the flip does not exceed 90 degrees on either side
            double maxFlipAngle = 90 / 90; // 90 degrees in radians
            if (percent > maxFlipAngle) {
              percent = maxFlipAngle;
            }

            _flipKey.currentState?.flip(percent, tilt);
          }
        },
        onHorizontalDragEnd: (details) {
          _completeFlip(details.velocity.pixelsPerSecond.dx);
        },
        onHorizontalDragCancel: () {
          if (!_isFlipping) {
            _flipKey.currentState?.stopFlip();
          }
        },
      ),
    );
  }

  Widget _buildPage(int index) {
    if (index >= pages.length) {
      return Container(color: Colors.transparent);
    }
    return Container(
      color: Colors.white,
      child: Center(
        child: Text(
          pages[index],
          style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
        ),
      ),
    );
  }

  void _completeFlip(double velocity) {
    if (!_isFlipping) {
      _isFlipping = true;
      if (velocity.abs() > 500) {
        if (velocity > 0 && currentPage > 0) {
          setState(() {
            currentPage--;
          });
        } else if (velocity < 0 && currentPage < pages.length - 1) {
          setState(() {
            currentPage++;
          });
        }
      }
      _flipKey.currentState?.stopFlip();
      Future.delayed(Duration(milliseconds: 300), () {
        setState(() {
          _isFlipping = false;
        });
      });
    }
  }

}

2

Answers


    • the tilt and flip percentage calculations take the upper limit into
      account ?!
    • the flip does not exceed 90 degrees on either side by clamping the
      tilt and percent values ?!

    I added checks to ensure that the percent variable, which controls the flipping angle, does not exceed 90 degrees (both positive and negative). This ensures that the flip does not go beyond the intended angle range, making the upper part behave as expected.

    import 'package:flip_widget_flutter/flip_widget_flutter.dart';
    import 'package:flutter/gestures.dart';
    import 'package:flutter/material.dart';
    import 'dart:math' as math;
    
    class BookPages extends StatefulWidget {
      final String url;
      final String title;
    
      const BookPages({Key? key, required this.url, required this.title})
          : super(key: key);
    
      @override
      State<BookPages> createState() => _BookPageState();
    }
    
    class _BookPageState extends State<BookPages> {
      final List<String> pages = [
        'Page 1',
        'Page 2',
        'Page 3',
        ///more
      ];
    
      double _minNumber = 0.008;
      int currentPage = 0;
      GlobalKey<FlipWidgetState> _flipKey = GlobalKey();
      Offset _oldPosition = Offset.zero;
      bool _isFlipping = false;
    
      double _clampMin(double v) {
        if (v < _minNumber && v > -_minNumber) {
          if (v >= 0) {
            v = _minNumber;
          } else {
            v = -_minNumber;
          }
        }
        return v;
      }
    
      @override
      Widget build(BuildContext context) {
        Size size = Size(256, 256);
        return Scaffold(
          appBar: AppBar(
            title: Text(widget.title),
          ),
          body: GestureDetector(
            child: FlipWidget(
              key: _flipKey,
              textureSize: size * 6,
              child: Stack(
                children: [
                  _buildPage(currentPage),
                  _buildPage(currentPage + 1),
                ],
              ),
            ),
            onHorizontalDragStart: (details) {
              if (!_isFlipping) {
                _oldPosition = details.globalPosition;
                _flipKey.currentState?.startFlip();
              }
            },
            onHorizontalDragUpdate: (details) {
              if (!_isFlipping) {
                Offset off = details.globalPosition - _oldPosition;
                double tilt = 1 / _clampMin((-off.dy + 20) / 100);
                double percent = math.max(0, -off.dx / (size.width * 1.4));
                percent = math.min(1.0, percent);
                percent = percent - percent / 2 * (1 - 1 / tilt);
    
                // Ensure the flip does not exceed 90 degrees on either side
                double maxFlipAngle = math.pi / 2; // 90 degrees in radians
                if (percent > maxFlipAngle) {
                  percent = maxFlipAngle;
                }
                if (percent < -maxFlipAngle) {
                  percent = -maxFlipAngle;
                }
    
                _flipKey.currentState?.flip(percent, tilt);
              }
            },
            onHorizontalDragEnd: (details) {
              _completeFlip(details.velocity.pixelsPerSecond.dx);
            },
            onHorizontalDragCancel: () {
              if (!_isFlipping) {
                _flipKey.currentState?.stopFlip();
              }
            },
          ),
        );
      }
    
      Widget _buildPage(int index) {
        if (index >= pages.length) {
          return Container(color: Colors.transparent);
        }
        return Container(
          color: Colors.white,
          child: Center(
            child: Text(
              pages[index],
              style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
            ),
          ),
        );
      }
    
      void _completeFlip(double velocity) {
        if (!_isFlipping) {
          _isFlipping = true;
          if (velocity.abs() > 500) {
            if (velocity > 0 && currentPage > 0) {
              setState(() {
                currentPage--;
              });
            } else if (velocity < 0 && currentPage < pages.length - 1) {
              setState(() {
                currentPage++;
              });
            }
          }
          _flipKey.currentState?.stopFlip();
          Future.delayed(Duration(milliseconds: 300), () {
            setState(() {
              _isFlipping = false;
            });
          });
        }
      }
    }
    
    Login or Signup to reply.
  1. You can use this plugin to do this, but it does not provide English documentation, so you need to use Google Translate to see how to use it.
    bookfx

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search