Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to provide Infinite Scroll #1

Open
AkankshaKS opened this issue Dec 14, 2022 · 3 comments
Open

How to provide Infinite Scroll #1

AkankshaKS opened this issue Dec 14, 2022 · 3 comments
Labels
enhancement New feature or request good first issue Good for newcomers

Comments

@AkankshaKS
Copy link

Library works fine, I want to provide infinite smooth scroll also, how to do that?

@delwar36 delwar36 added the enhancement New feature or request label Jan 24, 2023
@Ultranmus
Copy link

will i tried to do that and was successful but there arise the problem that transition between first and last is not smooth. I possible can you suggest how to do that?

Below is my code : -

import 'package:flutter/material.dart';

import '../screens/card.dart';

class MyCarousel extends StatefulWidget {
final List widgets;
final Function(int) onClicked;
final int? currentIndex;

const MyCarousel(
{super.key,
required this.widgets,
required this.onClicked,
this.currentIndex});

@OverRide
State createState() => _MyCarouselState();
}

class _MyCarouselState extends State {
double currentIndex = 0;
double index = 0;

@OverRide
void initState() {
if (widget.currentIndex != null) {
currentIndex = widget.currentIndex!.toDouble();
}
super.initState();
}

@OverRide
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 40.0),
child: Expanded(
child: LayoutBuilder(
builder: (context, constraints) {
return GestureDetector(
onPanUpdate: (details) {
setState(() {
index = currentIndex - details.delta.dx * 0.01;
if (index >= 0 && index <= widget.widgets.length - 1) {
currentIndex = currentIndex - details.delta.dx * 0.02;
} else if (index < 0) {
currentIndex =
widget.widgets.length - 1 + details.delta.dx * 0.02;
} else if (index > widget.widgets.length - 1) {
currentIndex = 0 - details.delta.dx * 0.02;
}
});
},
onPanEnd: (details) {
setState(() {
currentIndex = currentIndex.roundToDouble();
});
},
child: OverlappedCarouselCardItems(
cards: List.generate(
widget.widgets.length,
(index) => CardModel(
id: index,
child: widget.widgets[index],
),
),
centerIndex: currentIndex,
maxWidth: constraints.maxWidth,
maxHeight: constraints.maxHeight,
onClicked: widget.onClicked,
),
);
},
),
),
);
}
}

class OverlappedCarouselCardItems extends StatelessWidget {
final List cards;
final Function(int) onClicked;
final double centerIndex;
final double maxHeight;
final double maxWidth;

const OverlappedCarouselCardItems({
super.key,
required this.cards,
required this.centerIndex,
required this.maxHeight,
required this.maxWidth,
required this.onClicked,
});

double getCardPosition(int index) {
final double center = maxWidth / 2.5;
final double centerWidgetWidth = maxWidth / 4;
final double basePosition = center - centerWidgetWidth / 2 - 12;
final distance = centerIndex - index;

final double nearWidgetWidth = centerWidgetWidth / 5 * 4;
final double farWidgetWidth = centerWidgetWidth / 5 * 3;

if (distance == 0) {
  return basePosition;
} else if (distance.abs() > 0.0 && distance.abs() <= 1.0) {
  if (distance > 0) {
    return basePosition - nearWidgetWidth * distance.abs();
  } else {
    return basePosition + nearWidgetWidth * distance.abs();
  }
} else if (distance.abs() >= 1.0 && distance.abs() <= 2.0) {
  if (distance > 0) {
    return (basePosition - nearWidgetWidth) -
        farWidgetWidth * (distance.abs() - 1);
  } else {
    return (basePosition + centerWidgetWidth + nearWidgetWidth) +
        farWidgetWidth * (distance.abs() - 2) -
        (nearWidgetWidth - farWidgetWidth) *
            ((distance - distance.floor()));
  }
} else {
  if (distance > 0) {
    return (basePosition - nearWidgetWidth) -
        farWidgetWidth * (distance.abs() - 1);
  }
  return -((basePosition + centerWidgetWidth + nearWidgetWidth) -
      farWidgetWidth * (distance.abs() - 2) -
      (nearWidgetWidth - farWidgetWidth) * ((distance - distance.floor())) +
      (farWidgetWidth * 2));
}

}

double getCardWidth(int index) {
final double centerWidgetWidth =
(maxWidth / 2) - (maxWidth / 3.5) * 0.01 * (centerIndex - index).abs();

return centerWidgetWidth;

}

Matrix4 getTransform(int index) {
final distance = centerIndex - index;

var transform = Matrix4.identity()
  ..setEntry(3, 2, 0.007)
  // ..rotateY(-0.25 * distance)
  ..scale(1.25, 1.25, 1.25);
if (index == centerIndex) transform.scale(1.05, 1.05, 1.05);
return transform;

}

Widget _buildItem(CardModel item, int cardCount) {
final int index = item.id;
final width = getCardWidth(index);
double dist = (index - centerIndex).abs();
if (dist > cardCount ~/ 2) {
dist = cardCount - dist;
}
final verticalPadding = width * 0.01 * dist.toDouble();

return Positioned(
  left: getCardPosition(index),
  child: Transform(
    transform: getTransform(index),
    alignment: FractionalOffset.center,
    child: Container(
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(15.0),
      ),
      width: width.toDouble(),
      padding: EdgeInsets.symmetric(vertical: verticalPadding),
      height: maxHeight,
      child: item.child,
    ),
  ),
);

}

List _sortedStackWidgets(List widgets) {
final int centerIndexInt = centerIndex.round().toInt();
final int cardCount = widgets.length;

for (int i = 0; i < widgets.length; i++) {
  int distance = (i - centerIndexInt).abs();
  if (distance > cardCount ~/ 2) {
    distance = cardCount - distance;
  }
  widgets[i].zIndex = -distance.toDouble();
}
widgets.sort((a, b) => a.zIndex.compareTo(b.zIndex));
return widgets.map((e) {
  double distance = (centerIndex - e.id).abs();

  if (distance > 3 && e.id < 3) {
    e.id += widgets.length;
  }

  return _buildItem(e, widgets.length);
}).toList();

}

@OverRide
Widget build(BuildContext context) {
return Center(
child: Stack(
alignment: AlignmentDirectional.center,
clipBehavior: Clip.none,
children: _sortedStackWidgets(cards),
),
);
}
}

@Ultranmus
Copy link

Everyone can check out the whole code on my repo https://github.com/Ultranmus/Infinite-Overlapping-Carousel/tree/master.
If there is any advice please tell me.

@delwar36
Copy link
Owner

delwar36 commented Sep 16, 2023

APOLOGY!!! Due to some busy schedules I am not being able to update and resolve the issues. I appreciate if anyone contributes to resolve the issues. Waiting for the PRs.

@delwar36 delwar36 added the good first issue Good for newcomers label Sep 16, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request good first issue Good for newcomers
Projects
None yet
Development

No branches or pull requests

3 participants