README.md

July 4, 2025 ยท View on GitHub

FLUTTER INTRO SLIDER

Flutter Intro Slider is a flutter plugin that helps you make a cool intro for your app. Create intro has never been easier and faster

Table of Contents


Installing

Add to pubspec.yaml file

dependencies:
  intro_slider: ^4.2.5

Import

import 'package:intro_slider/intro_slider.dart';

Demo

default custom 1 custom 2


Code example


Default config

default config image

Code example (click to expand)
class IntroScreenDefaultState extends State<IntroScreenDefault> {
  List<ContentConfig> listContentConfig = [];

  @override
  void initState() {
    super.initState();

    listContentConfig.add(
      const ContentConfig(
        title: "ERASER",
        description:
            "Allow miles wound place the leave had. To sitting subject no improve studied limited",
        pathImage: "images/photo_eraser.png",
        backgroundColor: Color(0xfff5a623),
      ),
    );
    listContentConfig.add(
      const ContentConfig(
        title: "PENCIL",
        description:
            "Ye indulgence unreserved connection alteration appearance",
        pathImage: "images/photo_pencil.png",
        backgroundColor: Color(0xff203152),
      ),
    );
    listContentConfig.add(
      const ContentConfig(
        title: "RULER",
        description:
            "Much evil soon high in hope do view. Out may few northward believing attempted. Yet timed being songs marry one defer men our. Although finished blessing do of",
        pathImage: "images/photo_ruler.png",
        backgroundColor: Color(0xff9932CC),
      ),
    );
  }

  void onDonePress() {
    log("End of slides");
  }

  @override
  Widget build(BuildContext context) {
    return IntroSlider(
      listContentConfig: listContentConfig,
      onDonePress: onDonePress,
    );
  }
}

Custom config

custom config image

Code example (click to expand)
class IntroScreenCustomConfigState extends State<IntroScreenCustomConfig> {
  List<ContentConfig> listContentConfig = [];
  Color activeColor = const Color(0xff0BEEF9);
  Color inactiveColor = const Color(0xff03838b);
  double sizeIndicator = 20;

  @override
  void initState() {
    super.initState();

    listContentConfig.add(
      ContentConfig(
        title:
            "A VERY LONG TITLE A VERY LONG TITLE A VERY LONG TITLE A VERY LONG TITLE A VERY LONG TITLE A VERY LONG TITLE A VERY LONG TITLE A VERY LONG TITLE A VERY LONG TITLE",
        maxLineTitle: 2,
        styleTitle: const TextStyle(
          color: Colors.white,
          fontSize: 30.0,
          fontWeight: FontWeight.bold,
          fontFamily: 'RobotoMono',
        ),
        description:
            "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. Cras dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. Aenean leo ligula, porttitor eu, consequat vitae, eleifend ac, enim. Aliquam lorem ante, dapibus in, viverra quis, feugiat a, tellus. Phasellus viverra nulla ut metus varius laoreet. Quisque rutrum. Aenean imperdiet. Etiam ultricies nisi vel augue. Curabitur ullamcorper ultricies nisi. Nam eget dui. Etiam rhoncus. Maecenas tempus, tellus eget condimentum rhoncus, sem quam semper libero, sit amet adipiscing sem neque sed ipsum. Nam quam nunc, blandit vel, luctus pulvinar, hendrerit id, lorem. Maecenas nec odio et ante tincidunt tempus. Donec vitae sapien ut libero venenatis faucibus. Nullam quis ante. Etiam sit amet orci eget eros faucibus tincidunt. Duis leo. Sed fringilla mauris sit amet nibh. Donec sodales sagittis magna. Sed consequat, leo eget bibendum sodales, augue velit cursus nunc,",
        styleDescription: const TextStyle(
          color: Colors.white,
          fontSize: 20.0,
          fontStyle: FontStyle.italic,
          fontFamily: 'Raleway',
        ),
        marginDescription: const EdgeInsets.only(
          left: 20.0,
          right: 20.0,
          top: 20.0,
          bottom: 70.0,
        ),
        centerWidget: const Text(
          "Replace this with a custom widget",
          style: TextStyle(color: Colors.white),
        ),
        backgroundNetworkImage: "https://picsum.photos/600/900",
        backgroundFilterOpacity: 0.5,
        backgroundFilterColor: Colors.redAccent,
        onCenterItemPress: () {},
      ),
    );
    listContentConfig.add(
      const ContentConfig(
        title: "CITY",
        styleTitle: TextStyle(
          color: Color(0xff7FFFD4),
          fontSize: 30.0,
          fontWeight: FontWeight.bold,
          fontFamily: 'RobotoMono',
        ),
        description:
            "Ye indulgence unreserved connection alteration appearance",
        styleDescription: TextStyle(
          color: Color(0xff7FFFD4),
          fontSize: 20.0,
          fontStyle: FontStyle.italic,
          fontFamily: 'Raleway',
        ),
        colorBegin: Color(0xff89D4CF),
        colorEnd: Color(0xff734AE8),
        directionColorBegin: Alignment.topRight,
        directionColorEnd: Alignment.bottomLeft,
      ),
    );
    listContentConfig.add(
      const ContentConfig(
        title: "BEACH",
        styleTitle: TextStyle(
          color: Color(0xffFFDAB9),
          fontSize: 30.0,
          fontWeight: FontWeight.bold,
          fontFamily: 'RobotoMono',
        ),
        description:
            "Much evil soon high in hope do view. Out may few northward believing attempted. Yet timed being songs marry one defer men our. Although finished blessing do of",
        styleDescription: TextStyle(
          color: Color(0xffFFDAB9),
          fontSize: 20.0,
          fontStyle: FontStyle.italic,
          fontFamily: 'Raleway',
        ),
        backgroundImage: "images/beach.jpeg",
        maxLineTextDescription: 3,
      ),
    );
  }

  void onSwipeCompleted(int prevIndex, int currentIndex, String direction) {
    log("onSwipeCompleted caught prevIndex: $prevIndex, currentIndex: $currentIndex, direction: $direction");
  }

  void onDonePress() {
    log("onDonePress caught");
  }

  void onNextPress(int index) {
    log("onNextPress caught $index");
  }

  void onSwipeBeyondEnd() {
    log("onSwipeBeyondEnd caught - User swiped beyond the last slide!");
  }

  Widget renderNextBtn() {
    return const Icon(
      Icons.navigate_next,
      size: 25,
    );
  }

  Widget renderDoneBtn() {
    return const Icon(
      Icons.done,
      size: 25,
    );
  }

  Widget renderSkipBtn() {
    return const Icon(
      Icons.skip_next,
      size: 25,
    );
  }

  ButtonStyle myButtonStyle() {
    return ButtonStyle(
      shape: WidgetStateProperty.all<OutlinedBorder>(const StadiumBorder()),
      foregroundColor: WidgetStateProperty.all<Color>(activeColor),
      backgroundColor: WidgetStateProperty.all<Color>(inactiveColor),
    );
  }

  @override
  Widget build(BuildContext context) {
    return IntroSlider(
      // Content config
      listContentConfig: listContentConfig,
      backgroundColorAllTabs: Colors.grey,

      // Skip button
      renderSkipBtn: renderSkipBtn(),
      skipButtonStyle: myButtonStyle(),

      // Next button
      renderNextBtn: renderNextBtn(),
      onNextPress: onNextPress,
      nextButtonStyle: myButtonStyle(),

      // Done button
      renderDoneBtn: renderDoneBtn(),
      onDonePress: onDonePress,
      doneButtonStyle: myButtonStyle(),

      // Indicator
      indicatorConfig: IndicatorConfig(
        sizeIndicator: sizeIndicator,
        indicatorWidget: Container(
          width: sizeIndicator,
          height: 10,
          decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(4), color: inactiveColor),
        ),
        activeIndicatorWidget: Container(
          width: sizeIndicator,
          height: 10,
          decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(4), color: activeColor),
        ),
        spaceBetweenIndicator: 10,
        typeIndicatorAnimation: TypeIndicatorAnimation.sliding,
      ),

      // Navigation bar
      navigationBarConfig: NavigationBarConfig(
        navPosition: NavPosition.bottom,
        padding: EdgeInsets.only(
          top: MediaQuery.of(context).viewPadding.top > 0 ? 20 : 10,
          bottom: MediaQuery.of(context).viewPadding.bottom > 0 ? 20 : 10,
        ),
        backgroundColor: Colors.black.withValues(alpha: 0.5),
      ),

      // Scroll behavior
      isAutoScroll: false,
      isLoopAutoScroll: true,
      curveScroll: Curves.bounceIn,
      onSwipeCompleted: onSwipeCompleted,
      onSwipeBeyondEnd: onSwipeBeyondEnd,
      swipeBeyondEndThreshold: 100.0,
    );
  }
}

Custom layout

custom config image

Code example (click to expand)
class IntroScreenCustomLayoutState extends State<IntroScreenCustomLayout> {
  late Function goToTab;

  Color primaryColor = const Color(0xffffcc5c);
  Color secondColor = const Color(0xff3da4ab);

  void onDonePress() {
    goToTab(0);
  }

  void onTabChangeCompleted(index) {
    log("onTabChangeCompleted, index: $index");
  }

  Widget renderNextBtn() {
    return Icon(
      Icons.navigate_next,
      color: primaryColor,
      size: 35.0,
    );
  }

  Widget renderDoneBtn() {
    return Icon(
      Icons.done,
      color: primaryColor,
    );
  }

  Widget renderSkipBtn() {
    return Icon(
      Icons.skip_next,
      color: primaryColor,
    );
  }

  ButtonStyle myButtonStyle() {
    return ButtonStyle(
      shape: MaterialStateProperty.all<OutlinedBorder>(const StadiumBorder()),
      backgroundColor:
          MaterialStateProperty.all<Color>(const Color(0x33ffcc5c)),
      overlayColor: MaterialStateProperty.all<Color>(const Color(0x33ffcc5c)),
    );
  }

  List<Widget> generateListCustomTabs() {
    return List.generate(
      3,
      (index) => Container(
        color: Colors.black26,
        width: double.infinity,
        height: double.infinity,
        child: ListView(
          children: <Widget>[
            const SizedBox(height: 20),
            Center(
              child: DropdownButton<String>(
                value: index.toString(),
                icon: Icon(Icons.arrow_downward, color: secondColor, size: 20),
                elevation: 16,
                style: TextStyle(color: primaryColor),
                underline: Container(
                  height: 2,
                  color: secondColor,
                ),
                onChanged: (String? value) {},
                items: ["0", "1", "2"]
                    .map<DropdownMenuItem<String>>((String value) {
                  return DropdownMenuItem<String>(
                    value: value,
                    child: Text(value,
                        style: TextStyle(color: secondColor, fontSize: 20)),
                  );
                }).toList(),
              ),
            ),
            const SizedBox(height: 20),
            Image.network(
              "https://picsum.photos/${300 + index}",
              width: 300.0,
              height: 300.0,
            ),
            const SizedBox(height: 20),
            Container(
              margin: const EdgeInsets.symmetric(vertical: 20, horizontal: 16),
              child: Text(
                "Title at index $index",
                textAlign: TextAlign.center,
                style: TextStyle(
                  color: secondColor,
                  fontSize: 30.0,
                  fontWeight: FontWeight.bold,
                  fontFamily: 'RobotoMono',
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return IntroSlider(
      // Skip button
      renderSkipBtn: renderSkipBtn(),
      skipButtonStyle: myButtonStyle(),

      // Next button
      renderNextBtn: renderNextBtn(),
      nextButtonStyle: myButtonStyle(),

      // Done button
      renderDoneBtn: renderDoneBtn(),
      onDonePress: onDonePress,
      doneButtonStyle: myButtonStyle(),

      // Indicator
      indicatorConfig: const IndicatorConfig(
        colorIndicator: Color(0xffffcc5c),
        sizeIndicator: 13.0,
        typeIndicatorAnimation: TypeIndicatorAnimation.sizeTransition,
      ),

      // Custom tabs
      listCustomTabs: generateListCustomTabs(),
      backgroundColorAllTabs: Colors.white,
      refFuncGoToTab: (refFunc) {
        goToTab = refFunc;
      },

      // Behavior
      scrollPhysics: const BouncingScrollPhysics(),
      onTabChangeCompleted: onTabChangeCompleted,
    );
  }
}



IntroSlider parameter

NameTypeDefaultDescription
Tab
keyKey?Assign a unique key to the IntroSlider widget
listContentConfigList<ContentConfig>?View detailsList of ContentConfig objects defining slide content. Required if listCustomTabs not defined
listCustomTabsList<Widget>?Required if listContentConfig not definedCustom widget list for slides (allows you to put your own widgets into the prebuilt frame)
refFuncGoToTabvoid Function(Function function)?Do nothingProvides reference to navigation function, enabling programmatic navigation to any tab index
onTabChangeCompletedvoid Function(int index)?Do nothingCallback fired when tab change is completed, returns the current tab's index
backgroundColorAllTabsColor?TransparentBackground color for all tabs (used when backgroundColor is not set in individual tabs)
Skip Button
renderSkipBtnWidget?Text("SKIP")Render your own custom SKIP button widget
skipButtonStyleButtonStyle?ButtonStyle()Style configuration for the SKIP button
onSkipPressvoid Function()?Go to last page + call your function if defineFires when SKIP button is pressed. Goes to last page and calls your custom function if defined
isShowSkipBtnbool?trueShow or hide the SKIP button
skipButtonKeyKey?Assign a unique key to the SKIP button
Previous Button
renderPrevBtnWidget?Text("PREV")Render your own custom PREV button widget
prevButtonStyleButtonStyle?ButtonStyle()Style configuration for the PREV button
onPrevPressvoid Function(int index)?Go to prev page + call your function if defineFires when PREV button is pressed. Goes to previous page and calls your custom function if defined
isShowPrevBtnbool?falseShow or hide the PREV button. Note: set isShowSkipBtn to false first if you want to show this button
prevButtonKeyKey?Assign a unique key to the PREV button
Done Button
renderDoneBtnWidget?Text("DONE")Render your own custom DONE button widget
doneButtonStyleButtonStyle?ButtonStyle()Style configuration for the DONE button
onDonePressvoid Function()?Do nothingFires when DONE button is pressed
isShowDoneBtnbool?trueShow or hide the DONE button
doneButtonKeyKey?Assign a unique key to the DONE button
Next Button
renderNextBtnWidget?Text("NEXT")Render your own custom NEXT button widget
nextButtonStyleButtonStyle?ButtonStyle()Style configuration for the NEXT button
onNextPressvoid Function(int index)?Go to next page + call your function if defineFires when NEXT button is pressed. Goes to next page and calls your custom function if defined
isShowNextBtnbool?trueShow or hide the NEXT button
nextButtonKeyKey?Assign a unique key to the NEXT button
Indicator
indicatorConfigIndicatorConfig?View detailsConfiguration for customizing the slide indicator appearance and behavior
Navigation bar
navigationBarConfigNavigationBarConfig?View detailsConfiguration for customizing the navigation bar position and styling
Scroll behavior
isScrollablebool?trueWhether the slider is scrollable (or controlled only by buttons)
curveScrollCurve?Curves.easeAnimation curve for slide transitions (also affects indicator animation)
scrollPhysicsScrollPhysics?ScrollPhysics()Physics behavior for horizontal scrolling of the slides
isAutoScrollbool?falseEnable automatic scrolling of slides
isLoopAutoScrollbool?falseLoop back to first slide when reaching the end (for auto-scroll)
isPauseAutoPlayOnTouchbool?truePause auto-scroll when user touches the slide
autoScrollIntervalDuration?Duration(seconds: 4)Time interval between automatic slide transitions
onSwipeCompletedvoid Function(int previousIndex, int currentIndex, String direction)?Fires when user completes a swipe gesture
onSwipeBeyondEndvoid Function()?Fire when user swipes beyond the last slide (left swipe on final slide). Useful for navigating to next screen
swipeBeyondEndThresholddouble?50.0Minimum swipe distance (in pixels) required to trigger onSwipeBeyondEnd. Higher values = harder to trigger

ContentConfig parameter

NameTypeDefaultDescription
Title
titleString?""Text content for the title at the top of the slide
widgetTitleWidget?nullCustom widget to use as the title (overrides title if both are defined)
maxLineTitleint?1Maximum number of lines for the title text
styleTitleTextStyle?White color, bold and font size is 30.0TextStyle configuration for the title text
textAlignTitleTextAlign?TextAlign.centerText alignment for the title
textOverFlowTitleTextOverflow?TextOverflow.ellipsisText overflow behavior for the title
marginTitleEdgeInsets?top: 70.0, bottom: 50.0Margin spacing around the title
Image
pathImageString?""File path to your local image
widthImagedouble?250.0Width of the image
heightImagedouble?250.0Height of the image
foregroundImageFitBoxFit?BoxFit.containHow the foreground image should fit within its bounds
Center widget
centerWidgetWidget?nullYour custom widget to display in the center
onCenterItemPressFunction()?Do nothingFires when the center image/widget is pressed
Description
descriptionString?""Text content for the description at the bottom of the slide
widgetDescriptionWidget?nullCustom widget to use as the description (overrides description if both are defined)
maxLineTextDescriptionint?100Maximum number of lines for the description text
styleDescriptionTextStyle?White and font size is 18.0TextStyle configuration for the description text
textAlignDescriptionTextAlign?TextAlign.centerText alignment for the description
textOverFlowDescriptionTextOverflow?TextOverflow.ellipsisText overflow behavior for the description
marginDescriptionEdgeInsets?left, right = 20.0, top, bottom = 50.0Margin spacing around the description
Background Color
backgroundColorColor?Colors.amberAccentSolid background color for the slide (if set, gradient properties below will be ignored)
colorBeginColor?Colors.amberAccentStarting color for the gradient background
colorEndColor?Colors.amberAccentEnding color for the gradient background
directionColorBeginAlignmentGeometry?Alignment.topLeftStarting direction/position for the gradient
directionColorEndAlignmentGeometry?Alignment.bottomRightEnding direction/position for the gradient
Background Image
backgroundImageString?nullLocal image file path for the background (if set, all Background Color parameters above will be ignored)
backgroundNetworkImageString?nullNetwork URL for the background image
backgroundImageFitBoxFit?BoxFit.coverHow the background image should fit within its bounds
backgroundFilterColorColor?Colors.blackColor filter to apply over the background image
backgroundFilterOpacitydouble?0.5Opacity level for the backgroundFilterColor
backgroundBlendModeBlendMode?BlendMode.darkenBlend mode for combining the background image with the filter color
Others
verticalScrollbarBehaviorenum ScrollbarBehavior?ScrollbarBehavior.HIDESpecifies how the vertical scrollbar should behave
(scroll enabled when content length exceeds screen length)

IndicatorConfig parameter

NameTypeDefaultDescription
isShowIndicatorbool?trueShow or hide the slide indicator
colorIndicatorColor?Colors.black54Color for inactive indicators (ignored if using custom indicator widgets)
colorActiveIndicatorColor?value of colorIndicatorColor for the active (current) indicator (ignored if using custom indicator widgets)
sizeIndicatordouble?8.0Size of each indicator dot
spaceBetweenIndicatordouble?The same value of sizeIndicatorSpace between each indicator dot
typeIndicatorAnimationenum TypeIndicatorAnimation?TypeIndicatorAnimation.slidingType of animation for indicator transitions
indicatorWidgetWidget?Default dotCustom widget for inactive indicators
activeIndicatorWidgetWidget?Default dotCustom widget for the active indicator
(ignored when using TypeIndicatorAnimation.sizeTransition)

NameTypeDefaultDescription
paddingEdgeInsetsEdgeInsets.symmetric(vertical: 10)Padding around the navigation bar
navPositionNavPositionNavPosition.bottomPosition of the navigation bar (top or bottom of the page)
backgroundColorColorColors.transparentBackground color for the navigation bar

Pull request and feedback are always appreciated