Skip to content

关于动态切换滚动效果 #16

@SX-Code

Description

@SX-Code

目前的滚动模式有两种:水平和垂直,考虑到切换过程中边距等样式或者itemBuilder中额外信息的构建需要自定义,由用户根据scrollType切换ReadView也可行。
水平滚动模式有两种效果,分别是覆盖和水平滑动,这个的切换可以是动态的。
以下给出动态切换的一种方案,由于我的代码做了部其他修改,这里直接使用issue的方式给出:
将代码定位到read_page_view.dart文件的282行:

// Overlay swipe
// 覆盖滑动
class _FillViewportRenderObjectWidget extends SliverMultiBoxAdaptorWidget {
  final ScrollType scrollType;

  const _FillViewportRenderObjectWidget({
    required this.scrollType,
    required super.delegate,
  });

  @override
  void updateRenderObject(
    BuildContext context,
    _DynamicRenderSliver renderObject,
  ) {
    renderObject.scrollType = scrollType; // 动态更新模式
  }

  @override
  RenderSliverMultiBoxAdaptor createRenderObject(BuildContext context) {
    return _DynamicRenderSliver(
        scrollType: scrollType,
        childManager: context as SliverMultiBoxAdaptorElement);
  }
}

class _DynamicRenderSliver extends RenderSliverFixedExtentBoxAdaptor {
  ScrollType _scrollType;

  _DynamicRenderSliver({
    required ScrollType scrollType,
    required super.childManager,
  }) : _scrollType = scrollType;

  set scrollType(ScrollType newType) {
    if (_scrollType != newType) {
      _scrollType = newType;
      markNeedsLayout(); // 触发重新布局
    }
  }

  @override
  double get itemExtent => constraints.viewportMainAxisExtent;

  @override
  void paint(PaintingContext context, Offset offset) {
    if (_scrollType == ScrollType.smooth) {
      super.paint(context, offset);
      return;
    }
    if (firstChild == null) {
      return;
    }
    const Offset mainAxisUnit = Offset(1.0, 0.0);
    const Offset crossAxisUnit = Offset(0.0, 1.0);
    final Offset originOffset = offset;
    void draw(RenderBox child) {
      final double mainAxisDelta = childMainAxisPosition(child);
      final double crossAxisDelta = childCrossAxisPosition(child);
      Offset childOffset = Offset(
        originOffset.dx +
            mainAxisUnit.dx * mainAxisDelta +
            crossAxisUnit.dx * crossAxisDelta,
        originOffset.dy +
            mainAxisUnit.dy * mainAxisDelta +
            crossAxisUnit.dy * crossAxisDelta,
      );
      if (child != firstChild) {
        childOffset = Offset.zero;
      }
      if (mainAxisDelta < constraints.remainingPaintExtent &&
          mainAxisDelta + paintExtentOf(child) > 0) {
        context.paintChild(child, childOffset);
      }
    }

    RenderBox child = firstChild!;
    RenderBox? next = childAfter(child);
    if (next != null) {
      draw(next);
    }
    draw(child);
  }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions