├── .gitignore ├── .idea ├── codeStyles │ └── Project.xml ├── libraries │ ├── Dart_Packages.xml │ ├── Dart_SDK.xml │ └── Flutter_Plugins.xml ├── misc.xml ├── modules.xml ├── vcs.xml └── workspace.xml ├── .travis.yml ├── CHANGELOG-ZH.md ├── CHANGELOG.md ├── LICENSE ├── README-ZH.md ├── README.md ├── ROADMAP.md ├── banner.jpg ├── dev └── bots │ ├── travis_install.sh │ └── travis_script.sh ├── example ├── .gitignore ├── .idea │ ├── codeStyles │ │ └── Project.xml │ ├── libraries │ │ ├── Dart_Packages.xml │ │ ├── Dart_SDK.xml │ │ ├── Flutter_Plugins.xml │ │ └── Flutter_for_Android.xml │ ├── misc.xml │ ├── modules.xml │ ├── runConfigurations │ │ └── main_dart.xml │ └── workspace.xml ├── .metadata ├── README.md ├── android │ ├── .gitignore │ ├── app │ │ ├── build.gradle │ │ └── src │ │ │ └── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── java │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── example │ │ │ │ └── MainActivity.java │ │ │ └── res │ │ │ ├── drawable │ │ │ └── launch_background.xml │ │ │ ├── mipmap-hdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxxhdpi │ │ │ └── ic_launcher.png │ │ │ └── values │ │ │ └── styles.xml │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ └── settings.gradle ├── example.iml ├── example_android.iml ├── images │ ├── 1.png │ ├── 2.png │ ├── 3.png │ ├── bg.jpeg │ ├── bg0.jpeg │ ├── bg1.jpeg │ └── bg2.jpeg ├── ios │ ├── .gitignore │ ├── Flutter │ │ ├── AppFrameworkInfo.plist │ │ ├── Debug.xcconfig │ │ └── Release.xcconfig │ ├── MyLaunch.jpg │ ├── Runner.xcodeproj │ │ ├── project.pbxproj │ │ ├── project.xcworkspace │ │ │ └── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── Runner.xcscheme │ ├── Runner.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ └── WorkspaceSettings.xcsettings │ └── Runner │ │ ├── AppDelegate.h │ │ ├── AppDelegate.m │ │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ ├── Icon-App-20x20@1x.png │ │ │ ├── Icon-App-20x20@2x.png │ │ │ ├── Icon-App-20x20@3x.png │ │ │ ├── Icon-App-29x29@1x.png │ │ │ ├── Icon-App-29x29@2x.png │ │ │ ├── Icon-App-29x29@3x.png │ │ │ ├── Icon-App-40x40@1x.png │ │ │ ├── Icon-App-40x40@2x.png │ │ │ ├── Icon-App-40x40@3x.png │ │ │ ├── Icon-App-60x60@2x.png │ │ │ ├── Icon-App-60x60@3x.png │ │ │ ├── Icon-App-76x76@1x.png │ │ │ ├── Icon-App-76x76@2x.png │ │ │ └── Icon-App-83.5x83.5@2x.png │ │ └── LaunchImage.imageset │ │ │ ├── Contents.json │ │ │ ├── LaunchImage.png │ │ │ ├── LaunchImage@2x.png │ │ │ ├── LaunchImage@3x.png │ │ │ └── README.md │ │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ │ ├── Info.plist │ │ └── main.m ├── lib │ ├── InnerSwiper.dart │ ├── listener_test.dart │ ├── main.dart │ └── src │ │ ├── ExampleCustom.dart │ │ ├── ExampleSwiperInScrollView.dart │ │ ├── config.dart │ │ └── forms │ │ └── form_widget.dart ├── pubspec.lock ├── pubspec.yaml ├── res │ ├── 1.gif │ ├── 2.gif │ ├── 3.gif │ ├── 4.gif │ └── 5.gif └── test │ └── widget_test.dart ├── flutter_swiper.iml ├── lib ├── flutter_swiper.dart └── src │ ├── custom_layout.dart │ ├── swiper.dart │ ├── swiper_control.dart │ ├── swiper_controller.dart │ ├── swiper_pagination.dart │ └── swiper_plugin.dart ├── pubspec.lock ├── pubspec.yaml └── test ├── control_test.dart ├── flutter_swiper_test.dart ├── layout_test.dart └── pagination_test.dart /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .dart_tool/ 3 | 4 | .packages 5 | .pub/ 6 | 7 | build/ 8 | ios/.generated/ 9 | ios/Flutter/Generated.xcconfig 10 | ios/Runner/GeneratedPluginRegistrant.* 11 | coverage/lcov.info 12 | -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 15 | 16 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /.idea/libraries/Dart_Packages.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | -------------------------------------------------------------------------------- /.idea/libraries/Dart_SDK.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /.idea/libraries/Flutter_Plugins.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: dart 2 | env: 3 | - SHARD=dartfmt 4 | - SHARD=test 5 | install: 6 | - ./dev/bots/travis_install.sh 7 | script: 8 | - ./dev/bots/travis_script.sh 9 | after_success: 10 | - coveralls-lcov coverage/lcov.info -------------------------------------------------------------------------------- /CHANGELOG-ZH.md: -------------------------------------------------------------------------------- 1 | ## [1.1.1] - [2018/09/20] 2 | * 修复自动集成测试错误 3 | 4 | ## [1.1.0] - [2018/09/20] 5 | * 修复index的bug ,见 #11 6 | * 增加 `autoplayDisableOnInteraction` 选项, 如果设置为true,那么在用户滑动的时候停止自动播放,滑动之后重新自动播放 7 | 8 | 9 | ## [1.0.7] - [2018/09/02] 10 | * 在Swiper dispose的时候不调用Controller的dispose. 11 | 12 | ## [1.0.6] - [2018/08/28] 13 | * `TINDER` 和 `STACK` 这两种布局方式实现垂直滚动, #9 14 | 15 | ## [1.0.5] - [2018/08/09] 16 | * viewportFraction<1.0增加fade参数 17 | 18 | ## [1.0.4] - [2018/07/18] 19 | * 修复一些错别字,感谢[csharad](https://github.com/csharad) 20 | 21 | ## [1.0.3] - [2018/07/18] 22 | * 根据#5 ,用new来创建对象 23 | 24 | ## [1.0.2] - [2018/07/16] 25 | * 修复 #4 26 | 27 | ## [1.0.1] - [2018/07/11] 28 | * 支持布局方式(CUSTOM),你可以定制你自己的布局 29 | 30 | ## [1.0.0] - [2018/07/08] 31 | * 增加布局方式( DEFAULT,STACK,TINDER ) 32 | * 可以将分页指示器放在容器外面 33 | 34 | ## [0.0.9] - [2018/06/10] 35 | * 增加CI 36 | * 增加测试用例 37 | 38 | ## [0.0.8] - [2018/06/07] 39 | * 新增中文文档 40 | * 更新依赖包:infinity_page_view 版本到 1.0.0 41 | 42 | ## [0.0.7] - [2018/05/24] 43 | * The default color of pagination is ThemeData.scaffoldBackgroundColor and ThemeData.primaryColor 44 | * The default color of control buttons is ThemeData.primaryColor and ThemeData.disabledColor 45 | * The alignment of pagination is Alignment.bottomCenter by default when scrollDirection== Axis.horizontal, Alignment.centerRight by default when scrollDirection== Axis.vertical 46 | * Change default value of `autoplay` to false 47 | 48 | ## [0.0.6] - [2018/05/24] 49 | * Fix index bug 50 | 51 | ## [0.0.5] - [2018/05/24] 52 | * Fix zero itemCount bug 53 | 54 | ## [0.0.4] - [2018/05/20] 55 | * Update README 56 | 57 | ## [0.0.3] - [2018/05/20] 58 | * Update README 59 | * Support none loop mode 60 | * Add more examples 61 | 62 | ## [0.0.2] - [2018/05/20] 63 | * Autoplay 64 | * Plugins support 65 | * Examples 66 | 67 | ## [0.0.1] - [2018/05/20] 68 | * Infinite loop 69 | * Control buttons 70 | * Pagination 71 | * Custom control buttons 72 | * Custom pagination 73 | * Controler -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | ## [1.1.5] - [2019/03/10] 3 | 4 | * Fix findRenderObject is null 5 | 6 | 7 | ## [1.1.4] - [2018/10/18] 8 | 9 | ## [1.1.2] - [2018/10/10] 10 | * Fix #7 11 | * Support layout for pagination. 12 | 13 | ## [1.1.1] - [2018/09/20] 14 | * Fix `test` failure. 15 | 16 | ## [1.1.0] - [2018/09/20] 17 | * Fix index bug ,See #11 18 | * Enable `autoplayDisableOnInteraction` property, if set `true`,disable autoplay when user swipes. 19 | 20 | ## [1.0.7] - [2018/09/02] 21 | * Don't call SwiperController's dispose when `Swiper` dispose. 22 | 23 | ## [1.0.6] - [2018/08/28] 24 | * Implement vertical scroll direction for `TINDER` and `STACK` layout, see #9 25 | 26 | ## [1.0.5] - [2018/08/09] 27 | * Add feature : support fade for `viewportFraction` 28 | 29 | ## [1.0.4] - [2018/07/18] 30 | * Fix some typo,thanks to [csharad](https://github.com/csharad) 31 | 32 | ## [1.0.3] - [2018/07/18] 33 | * Use new to create everything. See #5 34 | 35 | ## [1.0.2] - [2018/07/16] 36 | * Fix #4 37 | 38 | ## [1.0.1] - [2018/07/11] 39 | * Add layout (CUSTOM) so that you can create your own layout 40 | 41 | ## [1.0.0] - [2018/07/08] 42 | * Add layouts ( DEFAULT,STACK,TINDER ) 43 | * Allow to put pagination outer of the swiper container. 44 | 45 | ## [0.0.9] - [2018/06/10] 46 | * Add ci 47 | * Add testcase 48 | 49 | ## [0.0.8] - [2018/06/07] 50 | * And chinese document 51 | * Update infinity_page_view version to 1.0.0 52 | 53 | ## [0.0.7] - [2018/05/24] 54 | * The default color of pagination is ThemeData.scaffoldBackgroundColor and ThemeData.primaryColor 55 | * The default color of control buttons is ThemeData.primaryColor and ThemeData.disabledColor 56 | * The alignment of pagination is Alignment.bottomCenter by default when scrollDirection== Axis.horizontal, Alignment.centerRight by default when scrollDirection== Axis.vertical 57 | * Change default value of `autoplay` to false 58 | 59 | ## [0.0.6] - [2018/05/24] 60 | * Fix index bug 61 | 62 | ## [0.0.5] - [2018/05/24] 63 | * Fix zero itemCount bug 64 | 65 | ## [0.0.4] - [2018/05/20] 66 | * Update README 67 | 68 | ## [0.0.3] - [2018/05/20] 69 | * Update README 70 | * Support none loop mode 71 | * Add more examples 72 | 73 | ## [0.0.2] - [2018/05/20] 74 | * Autoplay 75 | * Plugins support 76 | * Examples 77 | 78 | ## [0.0.1] - [2018/05/20] 79 | * Infinite loop 80 | * Control buttons 81 | * Pagination 82 | * Custom control buttons 83 | * Custom pagination 84 | * Controler -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Xueliang Ren 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README-ZH.md: -------------------------------------------------------------------------------- 1 | ![Logo](banner.jpg) 2 | 3 |

4 | 5 | Build Status 6 | 7 | 8 | Coverage Status 9 | 10 | 11 | PRs Welcome 12 | 13 | 14 | pub package 15 | 16 | best-flutter 17 |

18 |

19 | 20 | 英文说明 21 | 22 |

23 | 24 | 25 | # flutter_swiper 26 | 27 | flutter最强大的siwiper, 多种布局方式,无限轮播,Android和IOS双端适配. 28 | 29 | # :sparkles::sparkles: New Features: 分页组件 30 | 31 | 正在使用这个项目作为分页: [flutter_page_indicator](https://github.com/best-flutter/flutter_page_indicator) . 32 | 33 | # :sparkles::sparkles: New Features: 视差 34 | 35 | 我们在 Swiper 中也像android一样支持了 `PageTransformer`, 只要给Swiper设置一下 `transformer` 属性就行, 36 | 这里返回一个被转换的组件给Swiper. 目前仅仅支持 `DEFAULT`布局. 37 | 感谢 @FlutterRocks ,棒棒哒 👏. 38 | 39 | 正在使用这个项目作为视差 [transformer_page_view](https://github.com/best-flutter/transformer_page_view) . 40 | 41 | 42 | 43 | # :sparkles::sparkles: 新功能 44 | 45 | 46 | ![](https://github.com/jzoom/images/raw/master/layout1.gif) 47 | 48 | ![](https://github.com/jzoom/images/raw/master/layout2.gif) 49 | 50 | ![](https://github.com/jzoom/images/raw/master/layout3.gif) 51 | 52 | [更多](#内建的布局) 53 | 54 | 55 | # 截图 56 | 57 | ![Horizontal](https://github.com/jzoom/flutter_swiper/raw/master/example/res/1.gif) 58 | 59 | ![Vertical](https://github.com/jzoom/flutter_swiper/raw/master/example/res/2.gif) 60 | 61 | ![Custom Pagination](https://github.com/jzoom/flutter_swiper/raw/master/example/res/3.gif) 62 | 63 | ![Custom Pagination](https://github.com/jzoom/flutter_swiper/raw/master/example/res/4.gif) 64 | 65 | ![Phone](https://github.com/jzoom/flutter_swiper/raw/master/example/res/5.gif) 66 | 67 | ![Example](https://github.com/jzoom/images/raw/master/swiper-example.gif) 68 | 69 | [更多](#代码) 70 | 71 | ## 功能路线 72 | 73 | 1.x.x 功能实现: 74 | 75 | - [x] 无限循环轮播 76 | - [x] 控制按钮 77 | - [x] 分页指示器 78 | - [x] 非无限循环模式 79 | - [x] 单元测试 80 | - [x] 例子 81 | - [x] 滚动方向 82 | - [x] 可定制控制按钮 83 | - [x] 可定制分页 84 | - [x] 自动播放 85 | - [x] 控制器 86 | - [x] 外部分页指示器 87 | - [ ] 更多布局方式 88 | 89 | 90 | ## 更新日志 91 | 92 | >参考:[CHANGELOG.md](https://github.com/jzoom/flutter_swiper/blob/master/CHANGELOG-ZH.md) 93 | 94 | ## 目录 95 | 96 | - [安装](#安装) 97 | - [基本使用](#基本使用) 98 | - [构建](#构建) 99 | + [基本构造函数](#基本构造函数) 100 | + [分页指示器](#分页指示器) 101 | + [控制按钮](#控制按钮) 102 | + [控制器](#控制器) 103 | + [自动播放](#自动播放) 104 | + [内建的布局](#内建的布局) 105 | + [一些常用代码示例](#代码) 106 | 107 | ### 安装 108 | 109 | 增加 110 | 111 | ```bash 112 | 113 | flutter_swiper : ^lastest_version 114 | 115 | ``` 116 | 到项目根目录下的 pubspec.yaml ,并且根目录运行命令行 117 | 118 | ```bash 119 | flutter packages get 120 | ``` 121 | 122 | 123 | ### 基本使用 124 | 125 | 使用命令行创建一个新项目: 126 | 127 | ``` 128 | flutter create myapp 129 | ``` 130 | 131 | 编辑 lib/main.dart: 132 | 133 | ``` 134 | 135 | import 'package:flutter/material.dart'; 136 | 137 | import 'package:flutter_swiper/flutter_swiper.dart'; 138 | 139 | void main() => runApp(new MyApp()); 140 | 141 | class MyApp extends StatelessWidget { 142 | @override 143 | Widget build(BuildContext context) { 144 | return new MaterialApp( 145 | title: 'Flutter Demo', 146 | theme: new ThemeData( 147 | primarySwatch: Colors.blue, 148 | ), 149 | home: new MyHomePage(title: 'Flutter Demo Home Page'), 150 | ); 151 | } 152 | } 153 | 154 | class MyHomePage extends StatefulWidget { 155 | MyHomePage({Key key, this.title}) : super(key: key); 156 | 157 | final String title; 158 | 159 | @override 160 | _MyHomePageState createState() => new _MyHomePageState(); 161 | } 162 | 163 | class _MyHomePageState extends State { 164 | 165 | @override 166 | Widget build(BuildContext context) { 167 | return new Scaffold( 168 | appBar: new AppBar( 169 | title: new Text(widget.title), 170 | ), 171 | body: new Swiper( 172 | itemBuilder: (BuildContext context,int index){ 173 | return new Image.network("http://via.placeholder.com/350x150",fit: BoxFit.fill,); 174 | }, 175 | itemCount: 3, 176 | pagination: new SwiperPagination(), 177 | control: new SwiperControl(), 178 | ), 179 | ); 180 | } 181 | } 182 | 183 | ``` 184 | 185 | 186 | 187 | ### 构建 188 | 189 | 190 | #### 基本参数 191 | 192 | | 参数 | 默认值 | 描述 | 193 | | :-------------- |:-----------------:| :------------------------| 194 | | scrollDirection | Axis.horizontal |滚动方向,设置为Axis.vertical如果需要垂直滚动 | 195 | | loop | true |无限轮播模式开关 | 196 | | index | 0 |初始的时候下标位置 | 197 | | autoplay | false |自动播放开关. | 198 | | onIndexChanged | void onIndexChanged(int index) | 当用户手动拖拽或者自动播放引起下标改变的时候调用 | 199 | | onTap | void onTap(int index) | 当用户点击某个轮播的时候调用 | 200 | | duration | 300.0 | 动画时间,单位是毫秒 | 201 | | pagination | null | 设置 `new SwiperPagination()` 展示默认分页指示器 202 | | control | null | 设置 `new SwiperControl()` 展示默认分页按钮 203 | 204 | 205 | #### 分页指示器 206 | 207 | 分页指示器继承自 `SwiperPlugin`,`SwiperPlugin` 为 `Swiper` 提供额外的界面.设置为`new SwiperPagination()` 展示默认分页. 208 | 209 | 210 | | 参数 | 默认值 | 描述 | 211 | | :------------ |:---------------:| :-----| 212 | | alignment | Alignment.bottomCenter | 如果要将分页指示器放到其他位置,那么可以修改这个参数 | 213 | | margin | const EdgeInsets.all(10.0) | 分页指示器与容器边框的距离 | 214 | | builder | SwiperPagination.dots | 目前已经定义了两个默认的分页指示器样式: `SwiperPagination.dots` 、 `SwiperPagination.fraction`,都可以做进一步的自定义. | 215 | 216 | 如果需要定制自己的分页指示器,那么可以这样写: 217 | 218 | ``` 219 | new Swiper( 220 | ..., 221 | pagination:new SwiperCustomPagination( 222 | builder:(BuildContext context, SwiperPluginConfig config){ 223 | return new YourOwnPaginatipon(); 224 | } 225 | ) 226 | ); 227 | 228 | ``` 229 | 230 | 231 | 232 | #### 控制按钮 233 | 234 | 控制按钮组件也是继承自 `SwiperPlugin`,设置 `new SwiperControl()` 展示默认控制按钮. 235 | 236 | 237 | | 参数 | 默认值 | 描述 | 238 | | :------------ |:---------------:| :-----| 239 | | iconPrevious | Icons.arrow_back_ios | 上一页的IconData | 240 | | iconNext | Icons.arrow_forward_ios | 下一页的IconData | 241 | | color | Theme.of(context).primaryColor | 控制按钮颜色 | 242 | | size | 30.0 | 控制按钮的大小 | 243 | | padding | const EdgeInsets.all(5.0) | 控制按钮与容器的距离 | 244 | 245 | 246 | #### 控制器(SwiperController) 247 | 248 | `SwiperController` 用于控制 Swiper的`index`属性, 停止和开始自动播放. 通过 `new SwiperController()` 创建一个SwiperController实例,并保存,以便将来能使用。 249 | 250 | 251 | | 方法 | 描述 | 252 | | :------------ |:-----| 253 | | void move(int index, {bool animation: true}) | 移动到指定下标,设置是否播放动画| 254 | | void next({bool animation: true}) | 下一页 | 255 | | void previous({bool animation: true}) | 上一页 | 256 | | void startAutoplay() | 开始自动播放 | 257 | | void stopAutoplay() | 停止自动播放 | 258 | 259 | 260 | 261 | #### 自动播放 262 | 263 | | 参数 | 默认值 | 描述 | 264 | | :------------ |:---------------:| :-----| 265 | | autoplayDely | 3000 | 自动播放延迟毫秒数. | 266 | | autoplayDisableOnInteraction | true | 当用户拖拽的时候,是否停止自动播放. | 267 | 268 | 269 | 270 | ## 内建的布局 271 | ![](https://github.com/jzoom/images/raw/master/layout1.gif) 272 | 273 | ``` 274 | new Swiper( 275 | itemBuilder: (BuildContext context, int index) { 276 | return new Image.network( 277 | "http://via.placeholder.com/288x188", 278 | fit: BoxFit.fill, 279 | ); 280 | }, 281 | itemCount: 10, 282 | viewportFraction: 0.8, 283 | scale: 0.9, 284 | ) 285 | 286 | ``` 287 | 288 | 289 | 290 | ![](https://github.com/jzoom/images/raw/master/layout2.gif) 291 | 292 | ``` 293 | new Swiper( 294 | itemBuilder: (BuildContext context, int index) { 295 | return new Image.network( 296 | "http://via.placeholder.com/288x188", 297 | fit: BoxFit.fill, 298 | ); 299 | }, 300 | itemCount: 10, 301 | itemWidth: 300.0, 302 | layout: SwiperLayout.STACK, 303 | ) 304 | ``` 305 | 306 | ![](https://github.com/jzoom/images/raw/master/layout3.gif) 307 | 308 | ``` 309 | new Swiper( 310 | itemBuilder: (BuildContext context, int index) { 311 | return new Image.network( 312 | "http://via.placeholder.com/288x188", 313 | fit: BoxFit.fill, 314 | ); 315 | }, 316 | itemCount: 10, 317 | itemWidth: 300.0, 318 | itemHeight: 400.0, 319 | layout: SwiperLayout.TINDER, 320 | ) 321 | ``` 322 | 323 | 324 | 325 | ![](https://github.com/jzoom/images/raw/master/layout4.gif) 326 | 327 | 构建你自己的动画十分简单: 328 | ``` 329 | 330 | new Swiper( 331 | layout: SwiperLayout.CUSTOM, 332 | customLayoutOption: new CustomLayoutOption( 333 | startIndex: -1, 334 | stateCount: 3 335 | ).addRotate([ 336 | -45.0/180, 337 | 0.0, 338 | 45.0/180 339 | ]).addTranslate([ 340 | new Offset(-370.0, -40.0), 341 | new Offset(0.0, 0.0), 342 | new Offset(370.0, -40.0) 343 | ]), 344 | itemWidth: 300.0, 345 | itemHeight: 200.0, 346 | itemBuilder: (context, index) { 347 | return new Container( 348 | color: Colors.grey, 349 | child: new Center( 350 | child: new Text("$index"), 351 | ), 352 | ); 353 | }, 354 | itemCount: 10) 355 | 356 | ``` 357 | 358 | `CustomLayoutOption` 被设计用来描述布局和动画,很简单的可以指定每一个元素的状态. 359 | 360 | ``` 361 | new CustomLayoutOption( 362 | startIndex: -1, /// 开始下标 363 | stateCount: 3 /// 下面的数组长度 364 | ).addRotate([ // 每个元素的角度 365 | -45.0/180, 366 | 0.0, 367 | 45.0/180 368 | ]).addTranslate([ /// 每个元素的偏移 369 | new Offset(-370.0, -40.0), 370 | new Offset(0.0, 0.0), 371 | new Offset(370.0, -40.0) 372 | ]) 373 | 374 | ``` 375 | 376 | ## 代码 377 | 378 | 379 | ![Example](https://github.com/jzoom/images/raw/master/swiper-example.gif) 380 | 381 | ``` 382 | new ConstrainedBox( 383 | child: new Swiper( 384 | outer:false, 385 | itemBuilder: (c, i) { 386 | return new Wrap( 387 | runSpacing: 6.0, 388 | children: [0,1,2,3,4,5,6,7,8,9].map((i){ 389 | return new SizedBox( 390 | width: MediaQuery.of(context).size.width/5, 391 | child: new Column( 392 | mainAxisSize: MainAxisSize.min, 393 | children: [ 394 | new SizedBox( 395 | child: new Container( 396 | child: new Image.network("https://fuss10.elemecdn.com/c/db/d20d49e5029281b9b73db1c5ec6f9jpeg.jpeg%3FimageMogr/format/webp/thumbnail/!90x90r/gravity/Center/crop/90x90"), 397 | ), 398 | height: MediaQuery.of(context).size.width * 0.12, 399 | width: MediaQuery.of(context).size.width * 0.12, 400 | ), 401 | new Padding(padding: new EdgeInsets.only(top:6.0),child: new Text("$i"),) 402 | ], 403 | ), 404 | ); 405 | }).toList(), 406 | ); 407 | }, 408 | pagination: new SwiperPagination( 409 | margin: new EdgeInsets.all(5.0) 410 | ), 411 | itemCount: 10, 412 | ), 413 | constraints:new BoxConstraints.loose(new Size(screenWidth, 170.0)) 414 | ), 415 | 416 | ``` 417 | 418 | 419 | 420 | 这里可以找到所有的定制选项 421 | 422 | >https://github.com/jzoom/flutter_swiper/blob/master/example/lib/src/ExampleCustom.dart -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Logo](banner.jpg) 2 | 3 |

4 | 5 | Build Status 6 | 7 | 8 | Coverage Status 9 | 10 | 11 | PRs Welcome 12 | 13 | 14 | pub package 15 | 16 | best-flutter 17 |

18 |

19 | 20 | 中文说明 21 | 22 |

23 | 24 | 25 | 26 | # flutter_swiper 27 | 28 | The best swiper for flutter , with multiple layouts, infinite loop. Compatible with Android & iOS. 29 | 30 | 31 | # :sparkles::sparkles: New Features:Layout for pagination. 32 | 33 | We are using this project [flutter_page_indicator](https://github.com/best-flutter/flutter_page_indicator) now . 34 | 35 | # :sparkles::sparkles: New Features:PageTransformer 36 | 37 | Finally, we have `PageTransformer` like android, just set a `transformer` to `Swiper`, 38 | it returns a widget that has been transformed. For now, only support for layout `DEFAULT`. 39 | Thanks to @FlutterRocks ,you've done great job 👏. 40 | 41 | We are using this project [transformer_page_view](https://github.com/best-flutter/transformer_page_view) now . 42 | 43 | 44 | # :sparkles::sparkles: New Features:Layout 45 | 46 | 47 | ![](https://github.com/jzoom/images/raw/master/layout1.gif) 48 | 49 | ![](https://github.com/jzoom/images/raw/master/layout2.gif) 50 | 51 | ![](https://github.com/jzoom/images/raw/master/layout3.gif) 52 | 53 | [See More](#build-in-layouts) 54 | 55 | 56 | # Showcases 57 | 58 | ![Horizontal](https://github.com/jzoom/flutter_swiper/raw/master/example/res/1.gif) 59 | 60 | ![Vertical](https://github.com/jzoom/flutter_swiper/raw/master/example/res/2.gif) 61 | 62 | ![Custom Pagination](https://github.com/jzoom/flutter_swiper/raw/master/example/res/3.gif) 63 | 64 | ![Custom Pagination](https://github.com/jzoom/flutter_swiper/raw/master/example/res/4.gif) 65 | 66 | ![Phone](https://github.com/jzoom/flutter_swiper/raw/master/example/res/5.gif) 67 | 68 | ![Example](https://github.com/jzoom/images/raw/master/swiper-example.gif) 69 | 70 | [See More](#codes) 71 | 72 | ## Roadmap 73 | 74 | >see:[ROADMAP.md](https://github.com/jzoom/flutter_swiper/blob/master/ROADMAP.md) 75 | 76 | ## Changelogs 77 | 78 | >see:[CHANGELOG.md](https://github.com/jzoom/flutter_swiper/blob/master/CHANGELOG.md) 79 | 80 | ## Getting Started 81 | 82 | - [Installation](#installation) 83 | - [Basic Usage](#basic-usage) 84 | - [Constructor](#constructor) 85 | + [Basic](#basic) 86 | + [Pagination](#pagination) 87 | + [Control buttons](#control-buttons) 88 | + [Controller](#controller) 89 | + [Autoplay](#autoplay) 90 | - [Build in layouts](#build-in-layouts) 91 | - [Codes](#codes) 92 | 93 | ### Installation 94 | 95 | Add 96 | 97 | ```bash 98 | 99 | flutter_swiper : ^lastest_version 100 | 101 | ``` 102 | to your pubspec.yaml ,and run 103 | 104 | ```bash 105 | flutter packages get 106 | ``` 107 | in your project's root directory. 108 | 109 | ### Basic Usage 110 | 111 | Create a new project with command 112 | 113 | ``` 114 | flutter create myapp 115 | ``` 116 | 117 | Edit lib/main.dart like this: 118 | 119 | ``` 120 | 121 | import 'package:flutter/material.dart'; 122 | 123 | import 'package:flutter_swiper/flutter_swiper.dart'; 124 | 125 | void main() => runApp(new MyApp()); 126 | 127 | class MyApp extends StatelessWidget { 128 | @override 129 | Widget build(BuildContext context) { 130 | return new MaterialApp( 131 | title: 'Flutter Demo', 132 | theme: new ThemeData( 133 | primarySwatch: Colors.blue, 134 | ), 135 | home: new MyHomePage(title: 'Flutter Demo Home Page'), 136 | ); 137 | } 138 | } 139 | 140 | class MyHomePage extends StatefulWidget { 141 | MyHomePage({Key key, this.title}) : super(key: key); 142 | 143 | final String title; 144 | 145 | @override 146 | _MyHomePageState createState() => new _MyHomePageState(); 147 | } 148 | 149 | class _MyHomePageState extends State { 150 | 151 | @override 152 | Widget build(BuildContext context) { 153 | return new Scaffold( 154 | appBar: new AppBar( 155 | title: new Text(widget.title), 156 | ), 157 | body: new Swiper( 158 | itemBuilder: (BuildContext context,int index){ 159 | return new Image.network("http://via.placeholder.com/350x150",fit: BoxFit.fill,); 160 | }, 161 | itemCount: 3, 162 | pagination: new SwiperPagination(), 163 | control: new SwiperControl(), 164 | ), 165 | ); 166 | } 167 | } 168 | 169 | ``` 170 | 171 | 172 | 173 | ### Constructor 174 | 175 | 176 | #### Basic 177 | 178 | | Parameter | Default | Description | 179 | | :------------ |:---------------:| :-----| 180 | | scrollDirection | Axis.horizontal | If `Axis.horizontal`, the scroll view's children are arranged horizontally in a row instead of vertically in a column. | 181 | | loop | true |Set to `false` to disable continuous loop mode. | 182 | | index | 0 | Index number of initial slide. | 183 | | autoplay | false |Set to `true` enable auto play mode. | 184 | | onIndexChanged | void onIndexChanged(int index) | Called with the new index when the user swiped or autoplay | 185 | | onTap | void onTap(int index) | Called when user tap ui. | 186 | | duration | 300.0 | The milliscends of every transaction animation costs | 187 | | pagination | null | set `new SwiperPagination()` to show default pagination 188 | | control | null | set `new SwiperControl()` to show default control buttons 189 | 190 | 191 | #### Pagination 192 | 193 | The pagination extends from `SwiperPlugin`,the `SwiperPlugin` provides extra ui for `Swiper`.Set `new SwiperPagination()` to show default pagination. 194 | 195 | 196 | | Parameter | Default | Description | 197 | | :------------ |:---------------:| :-----| 198 | | alignment | Alignment.bottomCenter | Change this value if you what to put pagination in other place | 199 | | margin | const EdgeInsets.all(10.0) | The distance between inner side of the parent container. | 200 | | builder | SwiperPagination.dots | There are two default styles `SwiperPagination.dots` and `SwiperPagination.fraction`,both can be customized. | 201 | 202 | If you'd like to customize your own pagination, you can do like this: 203 | 204 | ``` 205 | new Swiper( 206 | ..., 207 | pagination:new SwiperCustomPagination( 208 | builder:(BuildContext context, SwiperPluginConfig config){ 209 | return new YourOwnPaginatipon(); 210 | } 211 | ) 212 | ); 213 | 214 | ``` 215 | 216 | 217 | 218 | #### Control buttons 219 | 220 | The control also extends from `SwiperPlugin`,set `new SwiperControl()` to show default control buttons. 221 | 222 | 223 | | Parameter | Default | Description | 224 | | :------------ |:---------------:| :-----| 225 | | iconPrevious | Icons.arrow_back_ios | The icon data to display `previous` control button | 226 | | iconNext | Icons.arrow_forward_ios | The icon data to display `next`. | 227 | | color | Theme.of(context).primaryColor | Control button color | 228 | | size | 30.0 | Control button size | 229 | | padding | const EdgeInsets.all(5.0) | Control button padding | 230 | 231 | 232 | #### Controller 233 | 234 | The `Controller` is used to control the `index` of the Swiper, start or stop autoplay.You can create a controller by `new SwiperController()` and save the instance by futher usage. 235 | 236 | 237 | | Method | Description | 238 | | :------------ |:-----| 239 | | void move(int index, {bool animation: true}) | Move to the spicified `index`,with animation or not | 240 | | void next({bool animation: true}) | Move to next | 241 | | void previous({bool animation: true}) | Move to previous | 242 | | void startAutoplay() | Start autoplay | 243 | | void stopAutoplay() | Stop autoplay | 244 | 245 | 246 | 247 | #### Autoplay 248 | 249 | | Parameter | Default | Description | 250 | | :------------ |:---------------:| :-----| 251 | | autoplayDelay | 3000 | Autoplay delay milliseconds. | 252 | | autoplayDisableOnInteraction | true | If set true, `autoplay` is disabled when use swipes. | 253 | 254 | ## Build in layouts 255 | ![](https://github.com/jzoom/images/raw/master/layout1.gif) 256 | 257 | ``` 258 | new Swiper( 259 | itemBuilder: (BuildContext context, int index) { 260 | return new Image.network( 261 | "http://via.placeholder.com/288x188", 262 | fit: BoxFit.fill, 263 | ); 264 | }, 265 | itemCount: 10, 266 | viewportFraction: 0.8, 267 | scale: 0.9, 268 | ) 269 | 270 | ``` 271 | 272 | 273 | 274 | ![](https://github.com/jzoom/images/raw/master/layout2.gif) 275 | 276 | ``` 277 | new Swiper( 278 | itemBuilder: (BuildContext context, int index) { 279 | return new Image.network( 280 | "http://via.placeholder.com/288x188", 281 | fit: BoxFit.fill, 282 | ); 283 | }, 284 | itemCount: 10, 285 | itemWidth: 300.0, 286 | layout: SwiperLayout.STACK, 287 | ) 288 | ``` 289 | 290 | ![](https://github.com/jzoom/images/raw/master/layout3.gif) 291 | 292 | ``` 293 | new Swiper( 294 | itemBuilder: (BuildContext context, int index) { 295 | return new Image.network( 296 | "http://via.placeholder.com/288x188", 297 | fit: BoxFit.fill, 298 | ); 299 | }, 300 | itemCount: 10, 301 | itemWidth: 300.0, 302 | itemHeight: 400.0, 303 | layout: SwiperLayout.TINDER, 304 | ) 305 | ``` 306 | 307 | 308 | ![](https://github.com/jzoom/images/raw/master/layout4.gif) 309 | 310 | Very easy to create you own custom animation: 311 | ``` 312 | 313 | new Swiper( 314 | layout: SwiperLayout.CUSTOM, 315 | customLayoutOption: new CustomLayoutOption( 316 | startIndex: -1, 317 | stateCount: 3 318 | ).addRotate([ 319 | -45.0/180, 320 | 0.0, 321 | 45.0/180 322 | ]).addTranslate([ 323 | new Offset(-370.0, -40.0), 324 | new Offset(0.0, 0.0), 325 | new Offset(370.0, -40.0) 326 | ]), 327 | itemWidth: 300.0, 328 | itemHeight: 200.0, 329 | itemBuilder: (context, index) { 330 | return new Container( 331 | color: Colors.grey, 332 | child: new Center( 333 | child: new Text("$index"), 334 | ), 335 | ); 336 | }, 337 | itemCount: 10) 338 | 339 | ``` 340 | 341 | The `CustomLayoutOption` is designed to describe animations. 342 | It is very easy to specify every state of items in Swiper. 343 | 344 | ``` 345 | new CustomLayoutOption( 346 | startIndex: -1, /// Which index is the first item of array below 347 | stateCount: 3 /// array length 348 | ).addRotate([ // rotation of every item 349 | -45.0/180, 350 | 0.0, 351 | 45.0/180 352 | ]).addTranslate([ /// offset of every item 353 | new Offset(-370.0, -40.0), 354 | new Offset(0.0, 0.0), 355 | new Offset(370.0, -40.0) 356 | ]) 357 | 358 | ``` 359 | 360 | ## Codes 361 | 362 | ![Example](https://github.com/jzoom/images/raw/master/swiper-example.gif) 363 | 364 | ``` 365 | new ConstrainedBox( 366 | child: new Swiper( 367 | outer:false, 368 | itemBuilder: (c, i) { 369 | return new Wrap( 370 | runSpacing: 6.0, 371 | children: [0,1,2,3,4,5,6,7,8,9].map((i){ 372 | return new SizedBox( 373 | width: MediaQuery.of(context).size.width/5, 374 | child: new Column( 375 | mainAxisSize: MainAxisSize.min, 376 | children: [ 377 | new SizedBox( 378 | child: new Container( 379 | child: new Image.network("https://fuss10.elemecdn.com/c/db/d20d49e5029281b9b73db1c5ec6f9jpeg.jpeg%3FimageMogr/format/webp/thumbnail/!90x90r/gravity/Center/crop/90x90"), 380 | ), 381 | height: MediaQuery.of(context).size.width * 0.12, 382 | width: MediaQuery.of(context).size.width * 0.12, 383 | ), 384 | new Padding(padding: new EdgeInsets.only(top:6.0),child: new Text("$i"),) 385 | ], 386 | ), 387 | ); 388 | }).toList(), 389 | ); 390 | }, 391 | pagination: new SwiperPagination( 392 | margin: new EdgeInsets.all(5.0) 393 | ), 394 | itemCount: 10, 395 | ), 396 | constraints:new BoxConstraints.loose(new Size(screenWidth, 170.0)) 397 | ), 398 | 399 | ``` 400 | 401 | 402 | 403 | 404 | 405 | You can find all custom options here: 406 | 407 | >https://github.com/jzoom/flutter_swiper/blob/master/example/lib/src/ExampleCustom.dart 408 | 409 | 410 | 411 | 412 | 413 | -------------------------------------------------------------------------------- /ROADMAP.md: -------------------------------------------------------------------------------- 1 | V1 2 | - [x] Infinite loop 3 | - [x] Control buttons 4 | - [x] Pagination 5 | - [x] None loop 6 | - [x] Unit tests 7 | - [x] Examples 8 | - [x] Direction 9 | - [x] Custom control buttons 10 | - [x] Custom pagination 11 | - [x] Autoplay 12 | - [x] Controler 13 | - [x] Set indicator outside 14 | - [ ] More layouts 15 | -------------------------------------------------------------------------------- /banner.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/best-flutter/flutter_swiper/71eb23671d46f624790019963c7ce10456dec652/banner.jpg -------------------------------------------------------------------------------- /dev/bots/travis_install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "$PWD" 4 | export ROOT="$PWD" 5 | 6 | mkdir ~/development 7 | 8 | cd ~/development 9 | wget https://storage.googleapis.com/flutter_infra/releases/beta/linux/flutter_linux_v0.4.4-beta.tar.xz 10 | tar xf ~/development/flutter_linux_v0.4.4-beta.tar.xz 11 | 12 | export PATH=~/development/flutter/bin:$PATH 13 | 14 | 15 | cd $ROOT 16 | flutter packages get 17 | 18 | gem install coveralls-lcov 19 | -------------------------------------------------------------------------------- /dev/bots/travis_script.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -ex 3 | 4 | export PATH=~/development/flutter/bin:$PATH 5 | export ROOT="$PWD" 6 | 7 | if [[ "$SHARD" == "dartfmt" ]]; then 8 | echo 'Formating code' 9 | cd $ROOT 10 | flutter format . || exit $? 11 | else 12 | # tests shard 13 | cd $ROOT 14 | 15 | flutter test --coverage test/* || exit $? 16 | 17 | fi 18 | -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .dart_tool/ 3 | 4 | .packages 5 | .pub/ 6 | 7 | build/ 8 | 9 | .flutter-plugins 10 | -------------------------------------------------------------------------------- /example/.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 15 | 16 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /example/.idea/libraries/Dart_SDK.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /example/.idea/libraries/Flutter_Plugins.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /example/.idea/libraries/Flutter_for_Android.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /example/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /example/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /example/.idea/runConfigurations/main_dart.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /example/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 44b7e7d3f42f050a79712daab253af06e9daf530 8 | channel: beta 9 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # example 2 | 3 | A new Flutter project. 4 | 5 | ## Getting Started 6 | 7 | For help getting started with Flutter, view our online 8 | [documentation](https://flutter.io/). 9 | -------------------------------------------------------------------------------- /example/android/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | *.class 3 | .gradle 4 | /local.properties 5 | /.idea/workspace.xml 6 | /.idea/libraries 7 | .DS_Store 8 | /build 9 | /captures 10 | GeneratedPluginRegistrant.java 11 | -------------------------------------------------------------------------------- /example/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withReader('UTF-8') { reader -> 5 | localProperties.load(reader) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | apply plugin: 'com.android.application' 15 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 16 | 17 | android { 18 | compileSdkVersion 27 19 | 20 | lintOptions { 21 | disable 'InvalidPackage' 22 | } 23 | 24 | defaultConfig { 25 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 26 | applicationId "com.example.example" 27 | minSdkVersion 16 28 | targetSdkVersion 27 29 | versionCode 1 30 | versionName "1.0" 31 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 32 | } 33 | 34 | buildTypes { 35 | release { 36 | // TODO: Add your own signing config for the release build. 37 | // Signing with the debug keys for now, so `flutter run --release` works. 38 | signingConfig signingConfigs.debug 39 | } 40 | } 41 | } 42 | 43 | flutter { 44 | source '../..' 45 | } 46 | 47 | dependencies { 48 | testImplementation 'junit:junit:4.12' 49 | androidTestImplementation 'com.android.support.test:runner:1.0.1' 50 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1' 51 | } 52 | -------------------------------------------------------------------------------- /example/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 8 | 9 | 10 | 15 | 19 | 26 | 30 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /example/android/app/src/main/java/com/example/example/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.example; 2 | 3 | import android.os.Bundle; 4 | 5 | import io.flutter.app.FlutterActivity; 6 | import io.flutter.plugins.GeneratedPluginRegistrant; 7 | 8 | public class MainActivity extends FlutterActivity { 9 | @Override 10 | protected void onCreate(Bundle savedInstanceState) { 11 | super.onCreate(savedInstanceState); 12 | GeneratedPluginRegistrant.registerWith(this); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/best-flutter/flutter_swiper/71eb23671d46f624790019963c7ce10456dec652/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/best-flutter/flutter_swiper/71eb23671d46f624790019963c7ce10456dec652/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/best-flutter/flutter_swiper/71eb23671d46f624790019963c7ce10456dec652/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/best-flutter/flutter_swiper/71eb23671d46f624790019963c7ce10456dec652/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/best-flutter/flutter_swiper/71eb23671d46f624790019963c7ce10456dec652/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | -------------------------------------------------------------------------------- /example/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | google() 4 | jcenter() 5 | } 6 | 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:3.0.1' 9 | } 10 | } 11 | 12 | allprojects { 13 | repositories { 14 | google() 15 | jcenter() 16 | } 17 | } 18 | 19 | rootProject.buildDir = '../build' 20 | subprojects { 21 | project.buildDir = "${rootProject.buildDir}/${project.name}" 22 | } 23 | subprojects { 24 | project.evaluationDependsOn(':app') 25 | } 26 | 27 | task clean(type: Delete) { 28 | delete rootProject.buildDir 29 | } 30 | -------------------------------------------------------------------------------- /example/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/best-flutter/flutter_swiper/71eb23671d46f624790019963c7ce10456dec652/example/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 23 08:50:38 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip 7 | -------------------------------------------------------------------------------- /example/android/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /example/android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /example/android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() 4 | 5 | def plugins = new Properties() 6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') 7 | if (pluginsFile.exists()) { 8 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } 9 | } 10 | 11 | plugins.each { name, path -> 12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() 13 | include ":$name" 14 | project(":$name").projectDir = pluginDirectory 15 | } 16 | -------------------------------------------------------------------------------- /example/example.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /example/example_android.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /example/images/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/best-flutter/flutter_swiper/71eb23671d46f624790019963c7ce10456dec652/example/images/1.png -------------------------------------------------------------------------------- /example/images/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/best-flutter/flutter_swiper/71eb23671d46f624790019963c7ce10456dec652/example/images/2.png -------------------------------------------------------------------------------- /example/images/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/best-flutter/flutter_swiper/71eb23671d46f624790019963c7ce10456dec652/example/images/3.png -------------------------------------------------------------------------------- /example/images/bg.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/best-flutter/flutter_swiper/71eb23671d46f624790019963c7ce10456dec652/example/images/bg.jpeg -------------------------------------------------------------------------------- /example/images/bg0.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/best-flutter/flutter_swiper/71eb23671d46f624790019963c7ce10456dec652/example/images/bg0.jpeg -------------------------------------------------------------------------------- /example/images/bg1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/best-flutter/flutter_swiper/71eb23671d46f624790019963c7ce10456dec652/example/images/bg1.jpeg -------------------------------------------------------------------------------- /example/images/bg2.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/best-flutter/flutter_swiper/71eb23671d46f624790019963c7ce10456dec652/example/images/bg2.jpeg -------------------------------------------------------------------------------- /example/ios/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vagrant/ 3 | .sconsign.dblite 4 | .svn/ 5 | 6 | .DS_Store 7 | *.swp 8 | profile 9 | 10 | DerivedData/ 11 | build/ 12 | GeneratedPluginRegistrant.h 13 | GeneratedPluginRegistrant.m 14 | 15 | .generated/ 16 | 17 | *.pbxuser 18 | *.mode1v3 19 | *.mode2v3 20 | *.perspectivev3 21 | 22 | !default.pbxuser 23 | !default.mode1v3 24 | !default.mode2v3 25 | !default.perspectivev3 26 | 27 | xcuserdata 28 | 29 | *.moved-aside 30 | 31 | *.pyc 32 | *sync/ 33 | Icon? 34 | .tags* 35 | 36 | /Flutter/app.flx 37 | /Flutter/app.zip 38 | /Flutter/flutter_assets/ 39 | /Flutter/App.framework 40 | /Flutter/Flutter.framework 41 | /Flutter/Generated.xcconfig 42 | /ServiceDefinitions.json 43 | 44 | Pods/ 45 | -------------------------------------------------------------------------------- /example/ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | UIRequiredDeviceCapabilities 24 | 25 | arm64 26 | 27 | MinimumOSVersion 28 | 8.0 29 | 30 | 31 | -------------------------------------------------------------------------------- /example/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /example/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /example/ios/MyLaunch.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/best-flutter/flutter_swiper/71eb23671d46f624790019963c7ce10456dec652/example/ios/MyLaunch.jpg -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 40 | 41 | 42 | 43 | 44 | 45 | 56 | 58 | 64 | 65 | 66 | 67 | 68 | 69 | 75 | 77 | 83 | 84 | 85 | 86 | 88 | 89 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BuildSystemType 6 | Original 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner/AppDelegate.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface AppDelegate : FlutterAppDelegate 5 | 6 | @end 7 | -------------------------------------------------------------------------------- /example/ios/Runner/AppDelegate.m: -------------------------------------------------------------------------------- 1 | #include "AppDelegate.h" 2 | #include "GeneratedPluginRegistrant.h" 3 | 4 | @implementation AppDelegate 5 | 6 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 7 | [GeneratedPluginRegistrant registerWithRegistry:self]; 8 | // Override point for customization after application launch. 9 | return [super application:application didFinishLaunchingWithOptions:launchOptions]; 10 | } 11 | 12 | @end 13 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/best-flutter/flutter_swiper/71eb23671d46f624790019963c7ce10456dec652/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/best-flutter/flutter_swiper/71eb23671d46f624790019963c7ce10456dec652/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/best-flutter/flutter_swiper/71eb23671d46f624790019963c7ce10456dec652/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/best-flutter/flutter_swiper/71eb23671d46f624790019963c7ce10456dec652/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/best-flutter/flutter_swiper/71eb23671d46f624790019963c7ce10456dec652/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/best-flutter/flutter_swiper/71eb23671d46f624790019963c7ce10456dec652/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/best-flutter/flutter_swiper/71eb23671d46f624790019963c7ce10456dec652/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/best-flutter/flutter_swiper/71eb23671d46f624790019963c7ce10456dec652/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/best-flutter/flutter_swiper/71eb23671d46f624790019963c7ce10456dec652/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/best-flutter/flutter_swiper/71eb23671d46f624790019963c7ce10456dec652/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/best-flutter/flutter_swiper/71eb23671d46f624790019963c7ce10456dec652/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/best-flutter/flutter_swiper/71eb23671d46f624790019963c7ce10456dec652/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/best-flutter/flutter_swiper/71eb23671d46f624790019963c7ce10456dec652/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/best-flutter/flutter_swiper/71eb23671d46f624790019963c7ce10456dec652/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/best-flutter/flutter_swiper/71eb23671d46f624790019963c7ce10456dec652/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/best-flutter/flutter_swiper/71eb23671d46f624790019963c7ce10456dec652/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/best-flutter/flutter_swiper/71eb23671d46f624790019963c7ce10456dec652/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/best-flutter/flutter_swiper/71eb23671d46f624790019963c7ce10456dec652/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /example/ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /example/ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /example/ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | example 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | arm64 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | UIViewControllerBasedStatusBarAppearance 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /example/ios/Runner/main.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import "AppDelegate.h" 4 | 5 | int main(int argc, char * argv[]) { 6 | @autoreleasepool { 7 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /example/lib/InnerSwiper.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_swiper/flutter_swiper.dart'; 3 | 4 | void main() => runApp(new MyApp()); 5 | 6 | class MyApp extends StatelessWidget { 7 | @override 8 | Widget build(BuildContext context) { 9 | return new MaterialApp( 10 | home: new InnerSwiper(), 11 | ); 12 | } 13 | } 14 | 15 | class InnerSwiper extends StatefulWidget { 16 | @override 17 | State createState() { 18 | return new _InnerSwiperState(); 19 | } 20 | } 21 | 22 | class _InnerSwiperState extends State { 23 | SwiperController controller; 24 | 25 | List autoplayes; 26 | 27 | List controllers; 28 | 29 | @override 30 | void initState() { 31 | controller = new SwiperController(); 32 | autoplayes = new List() 33 | ..length = 10 34 | ..fillRange(0, 10, false); 35 | controllers = new List() 36 | ..length = 10 37 | ..fillRange(0, 10, new SwiperController()); 38 | super.initState(); 39 | } 40 | 41 | @override 42 | Widget build(BuildContext context) { 43 | return new Scaffold( 44 | body: new Swiper( 45 | loop: false, 46 | itemCount: 10, 47 | controller: controller, 48 | pagination: new SwiperPagination(), 49 | itemBuilder: (BuildContext context, int index) { 50 | return new Column( 51 | children: [ 52 | new SizedBox( 53 | child: new Swiper( 54 | controller: controllers[index], 55 | pagination: new SwiperPagination(), 56 | itemCount: 4, 57 | itemBuilder: (BuildContext context, int index) { 58 | return new Container( 59 | color: Colors.greenAccent, 60 | child: new Text("jkfjkldsfjd"), 61 | ); 62 | }, 63 | autoplay: autoplayes[index], 64 | ), 65 | height: 300.0, 66 | ), 67 | new RaisedButton( 68 | onPressed: () { 69 | setState(() { 70 | autoplayes[index] = true; 71 | }); 72 | }, 73 | child: new Text("Start autoplay"), 74 | ), 75 | new RaisedButton( 76 | onPressed: () { 77 | setState(() { 78 | autoplayes[index] = false; 79 | }); 80 | }, 81 | child: new Text("End autoplay"), 82 | ), 83 | new Text("is autoplay: ${autoplayes[index]}") 84 | ], 85 | ); 86 | }, 87 | ), 88 | ); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /example/lib/listener_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import 'package:flutter_swiper/flutter_swiper.dart'; 4 | import 'src/ExampleCustom.dart'; 5 | import 'src/config.dart'; 6 | import 'src/ExampleSwiperInScrollView.dart'; 7 | 8 | import 'package:flutter/cupertino.dart'; 9 | 10 | void main() => runApp(new MyApp()); 11 | 12 | class MyApp extends StatelessWidget { 13 | // This widget is the root of your application. 14 | @override 15 | Widget build(BuildContext context) { 16 | return new MaterialApp( 17 | title: 'Flutter Demo', 18 | theme: ThemeData( 19 | primarySwatch: Colors.blue, 20 | ), 21 | home: new MyHomePage(title: 'Flutter Swiper'), 22 | ); 23 | } 24 | } 25 | 26 | class MyHomePage extends StatefulWidget { 27 | MyHomePage({Key key, this.title}) : super(key: key); 28 | 29 | final String title; 30 | 31 | @override 32 | _MyHomePageState createState() => new _MyHomePageState(); 33 | } 34 | 35 | class _MyHomePageState extends State { 36 | @override 37 | Widget build(BuildContext context) { 38 | return new Scaffold( 39 | body: new Swiper( 40 | itemCount: 10, 41 | itemBuilder: (c, i) { 42 | return new Text("$i"); 43 | }, 44 | plugins: [], 45 | ), 46 | ); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /example/lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_page_indicator/flutter_page_indicator.dart'; 3 | 4 | import 'package:flutter_swiper/flutter_swiper.dart'; 5 | import 'src/ExampleCustom.dart'; 6 | import 'src/config.dart'; 7 | import 'src/ExampleSwiperInScrollView.dart'; 8 | 9 | import 'package:flutter/cupertino.dart'; 10 | 11 | void main() => runApp(new MyApp()); 12 | 13 | class MyApp extends StatelessWidget { 14 | // This widget is the root of your application. 15 | @override 16 | Widget build(BuildContext context) { 17 | return new MaterialApp( 18 | title: 'Flutter Demo', 19 | theme: ThemeData( 20 | primarySwatch: Colors.blue, 21 | ), 22 | home: new MyHomePage(title: 'Flutter Swiper'), 23 | //home: buildHome(), 24 | routes: { 25 | '/example01': (BuildContext context) => new ExampleHorizontal(), 26 | '/example02': (BuildContext context) => new ExampleVertical(), 27 | '/example03': (BuildContext context) => new ExampleFraction(), 28 | '/example04': (BuildContext context) => new ExampleCustomPagination(), 29 | '/example05': (BuildContext context) => new ExamplePhone(), 30 | '/example06': (BuildContext context) => new ScaffoldWidget( 31 | child: new ExampleSwiperInScrollView(), title: "ScrollView"), 32 | '/example07': (BuildContext context) => new ScaffoldWidget( 33 | child: new ExampleCustom(), 34 | title: "Custom All", 35 | ) 36 | }, 37 | ); 38 | } 39 | } 40 | 41 | class MyHomePage extends StatefulWidget { 42 | MyHomePage({Key key, this.title}) : super(key: key); 43 | 44 | final String title; 45 | 46 | @override 47 | _MyHomePageState createState() => new _MyHomePageState(); 48 | } 49 | 50 | class _MyHomePageState extends State { 51 | List render(BuildContext context, List children) { 52 | return ListTile.divideTiles( 53 | context: context, 54 | tiles: children.map((dynamic data) { 55 | return buildListTile(context, data[0], data[1], data[2]); 56 | })).toList(); 57 | } 58 | 59 | Widget buildListTile( 60 | BuildContext context, String title, String subtitle, String url) { 61 | return new ListTile( 62 | onTap: () { 63 | Navigator.of(context).pushNamed(url); 64 | }, 65 | isThreeLine: true, 66 | dense: false, 67 | leading: null, 68 | title: new Text(title), 69 | subtitle: new Text(subtitle), 70 | trailing: new Icon( 71 | Icons.arrow_right, 72 | color: Colors.blueAccent, 73 | ), 74 | ); 75 | } 76 | 77 | @override 78 | Widget build(BuildContext context) { 79 | // DateTime moonLanding = DateTime.parse("1969-07-20"); 80 | 81 | return new Scaffold( 82 | appBar: new AppBar( 83 | title: Text(widget.title), 84 | ), 85 | body: new ListView( 86 | children: render(context, [ 87 | ["Horizontal", "Scroll Horizontal", "/example01"], 88 | ["Vertical", "Scroll Vertical", "/example02"], 89 | ["Fraction", "Fraction style", "/example03"], 90 | ["Custom Pagination", "Custom Pagination", "/example04"], 91 | ["Phone", "Phone view", "/example05"], 92 | ["ScrollView ", "In a ScrollView", "/example06"], 93 | ["Custom", "Custom all properties", "/example07"] 94 | ]), 95 | ), 96 | ); 97 | } 98 | } 99 | 100 | const List titles = [ 101 | "Flutter Swiper is awosome", 102 | "Really nice", 103 | "Yeap" 104 | ]; 105 | 106 | class ExampleHorizontal extends StatelessWidget { 107 | @override 108 | Widget build(BuildContext context) { 109 | return new Scaffold( 110 | appBar: AppBar( 111 | title: Text("ExampleHorizontal"), 112 | ), 113 | body: new Swiper( 114 | itemBuilder: (BuildContext context, int index) { 115 | return new Image.asset( 116 | images[index], 117 | fit: BoxFit.fill, 118 | ); 119 | }, 120 | 121 | indicatorLayout: PageIndicatorLayout.COLOR, 122 | autoplay: true, 123 | itemCount: images.length, 124 | pagination: new SwiperPagination(), 125 | control: new SwiperControl(), 126 | )); 127 | } 128 | } 129 | 130 | class ExampleVertical extends StatelessWidget { 131 | @override 132 | Widget build(BuildContext context) { 133 | return new Scaffold( 134 | appBar: AppBar( 135 | title: Text("ExampleVertical"), 136 | ), 137 | body: new Swiper( 138 | itemBuilder: (BuildContext context, int index) { 139 | return new Image.asset( 140 | images[index], 141 | fit: BoxFit.fill, 142 | ); 143 | }, 144 | autoplay: true, 145 | itemCount: images.length, 146 | scrollDirection: Axis.vertical, 147 | pagination: new SwiperPagination(alignment: Alignment.centerRight), 148 | control: new SwiperControl(), 149 | )); 150 | } 151 | } 152 | 153 | class ExampleFraction extends StatelessWidget { 154 | @override 155 | Widget build(BuildContext context) { 156 | return new Scaffold( 157 | appBar: new AppBar( 158 | title: Text("ExampleFraction"), 159 | ), 160 | body: new Column( 161 | children: [ 162 | Expanded( 163 | child: new Swiper( 164 | itemBuilder: (BuildContext context, int index) { 165 | return new Image.asset( 166 | images[index], 167 | fit: BoxFit.fill, 168 | ); 169 | }, 170 | autoplay: true, 171 | itemCount: images.length, 172 | pagination: 173 | new SwiperPagination(builder: SwiperPagination.fraction), 174 | control: new SwiperControl(), 175 | )), 176 | Expanded( 177 | child: new Swiper( 178 | itemBuilder: (BuildContext context, int index) { 179 | return new Image.asset( 180 | images[index], 181 | fit: BoxFit.fill, 182 | ); 183 | }, 184 | autoplay: true, 185 | itemCount: images.length, 186 | scrollDirection: Axis.vertical, 187 | pagination: new SwiperPagination( 188 | alignment: Alignment.centerRight, 189 | builder: SwiperPagination.fraction), 190 | )) 191 | ], 192 | )); 193 | } 194 | } 195 | 196 | class ExampleCustomPagination extends StatelessWidget { 197 | @override 198 | Widget build(BuildContext context) { 199 | return new Scaffold( 200 | appBar: new AppBar( 201 | title: new Text("Custom Pagination"), 202 | ), 203 | body: new Column( 204 | children: [ 205 | new Expanded( 206 | child: new Swiper( 207 | itemBuilder: (BuildContext context, int index) { 208 | return new Image.asset( 209 | images[index], 210 | fit: BoxFit.fill, 211 | ); 212 | }, 213 | autoplay: true, 214 | itemCount: images.length, 215 | pagination: new SwiperPagination( 216 | margin: new EdgeInsets.all(0.0), 217 | builder: new SwiperCustomPagination(builder: 218 | (BuildContext context, SwiperPluginConfig config) { 219 | return new ConstrainedBox( 220 | child: new Container( 221 | color: Colors.white, 222 | child: new Text( 223 | "${titles[config.activeIndex]} ${config.activeIndex + 1}/${config.itemCount}", 224 | style: new TextStyle(fontSize: 20.0), 225 | )), 226 | constraints: new BoxConstraints.expand(height: 50.0), 227 | ); 228 | })), 229 | control: new SwiperControl(), 230 | ), 231 | ), 232 | new Expanded( 233 | child: new Swiper( 234 | itemBuilder: (BuildContext context, int index) { 235 | return new Image.asset( 236 | images[index], 237 | fit: BoxFit.fill, 238 | ); 239 | }, 240 | autoplay: true, 241 | itemCount: images.length, 242 | pagination: new SwiperPagination( 243 | margin: new EdgeInsets.all(0.0), 244 | builder: new SwiperCustomPagination(builder: 245 | (BuildContext context, SwiperPluginConfig config) { 246 | return new ConstrainedBox( 247 | child: new Row( 248 | children: [ 249 | new Text( 250 | "${titles[config.activeIndex]} ${config.activeIndex + 1}/${config.itemCount}", 251 | style: TextStyle(fontSize: 20.0), 252 | ), 253 | new Expanded( 254 | child: new Align( 255 | alignment: Alignment.centerRight, 256 | child: new DotSwiperPaginationBuilder( 257 | color: Colors.black12, 258 | activeColor: Colors.black, 259 | size: 10.0, 260 | activeSize: 20.0) 261 | .build(context, config), 262 | ), 263 | ) 264 | ], 265 | ), 266 | constraints: new BoxConstraints.expand(height: 50.0), 267 | ); 268 | })), 269 | control: new SwiperControl(color: Colors.redAccent), 270 | ), 271 | ) 272 | ], 273 | )); 274 | } 275 | } 276 | 277 | class ExamplePhone extends StatelessWidget { 278 | @override 279 | Widget build(BuildContext context) { 280 | return new Scaffold( 281 | appBar: new AppBar( 282 | title: new Text("Phone"), 283 | ), 284 | body: new Stack( 285 | children: [ 286 | ConstrainedBox( 287 | constraints: new BoxConstraints.expand(), 288 | child: new Image.asset( 289 | "images/bg.jpeg", 290 | fit: BoxFit.fill, 291 | ), 292 | ), 293 | new Swiper.children( 294 | autoplay: false, 295 | pagination: new SwiperPagination( 296 | margin: new EdgeInsets.fromLTRB(0.0, 0.0, 0.0, 30.0), 297 | builder: new DotSwiperPaginationBuilder( 298 | color: Colors.white30, 299 | activeColor: Colors.white, 300 | size: 20.0, 301 | activeSize: 20.0)), 302 | children: [ 303 | new Image.asset( 304 | "images/1.png", 305 | fit: BoxFit.contain, 306 | ), 307 | new Image.asset( 308 | "images/2.png", 309 | fit: BoxFit.contain, 310 | ), 311 | new Image.asset("images/3.png", fit: BoxFit.contain) 312 | ], 313 | ) 314 | ], 315 | ), 316 | ); 317 | } 318 | } 319 | 320 | class ScaffoldWidget extends StatelessWidget { 321 | final Widget child; 322 | final String title; 323 | final List actions; 324 | 325 | ScaffoldWidget({this.child, this.title, this.actions}); 326 | 327 | @override 328 | Widget build(BuildContext context) { 329 | return new Scaffold( 330 | appBar: new AppBar( 331 | title: new Text(title), 332 | actions: actions, 333 | ), 334 | body: child, 335 | ); 336 | } 337 | } 338 | -------------------------------------------------------------------------------- /example/lib/src/ExampleCustom.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_page_indicator/flutter_page_indicator.dart'; 3 | import 'package:flutter_swiper/flutter_swiper.dart'; 4 | import 'config.dart'; 5 | import 'forms/form_widget.dart'; 6 | 7 | class ExampleCustom extends StatefulWidget { 8 | @override 9 | State createState() { 10 | return new _ExampleCustomState(); 11 | } 12 | } 13 | 14 | class _ExampleCustomState extends State { 15 | //properties want to custom 16 | int _itemCount; 17 | 18 | bool _loop; 19 | 20 | bool _autoplay; 21 | 22 | int _autoplayDely; 23 | 24 | double _padding; 25 | 26 | bool _outer; 27 | 28 | double _radius; 29 | 30 | double _viewportFraction; 31 | 32 | SwiperLayout _layout; 33 | 34 | int _currentIndex; 35 | 36 | double _scale; 37 | 38 | Axis _scrollDirection; 39 | 40 | Curve _curve; 41 | 42 | double _fade; 43 | 44 | bool _autoplayDisableOnInteraction; 45 | 46 | CustomLayoutOption customLayoutOption; 47 | 48 | Widget _buildItem(BuildContext context, int index) { 49 | return ClipRRect( 50 | borderRadius: new BorderRadius.all(new Radius.circular(_radius)), 51 | child: new Image.asset( 52 | images[index % images.length], 53 | fit: BoxFit.fill, 54 | ), 55 | ); 56 | } 57 | 58 | @override 59 | void didUpdateWidget(ExampleCustom oldWidget) { 60 | customLayoutOption = new CustomLayoutOption(startIndex: -1, stateCount: 3) 61 | .addRotate([-45.0 / 180, 0.0, 45.0 / 180]).addTranslate([ 62 | new Offset(-370.0, -40.0), 63 | new Offset(0.0, 0.0), 64 | new Offset(370.0, -40.0) 65 | ]); 66 | super.didUpdateWidget(oldWidget); 67 | } 68 | 69 | @override 70 | void initState() { 71 | customLayoutOption = new CustomLayoutOption(startIndex: -1, stateCount: 3) 72 | .addRotate([-25.0 / 180, 0.0, 25.0 / 180]).addTranslate([ 73 | new Offset(-350.0, 0.0), 74 | new Offset(0.0, 0.0), 75 | new Offset(350.0, 0.0) 76 | ]); 77 | _fade = 1.0; 78 | _currentIndex = 0; 79 | _curve = Curves.ease; 80 | _scale = 0.8; 81 | _controller = new SwiperController(); 82 | _layout = SwiperLayout.TINDER; 83 | _radius = 10.0; 84 | _padding = 0.0; 85 | _loop = true; 86 | _itemCount = 3; 87 | _autoplay = false; 88 | _autoplayDely = 3000; 89 | _viewportFraction = 0.8; 90 | _outer = false; 91 | _scrollDirection = Axis.horizontal; 92 | _autoplayDisableOnInteraction = false; 93 | super.initState(); 94 | } 95 | 96 | // maintain the index 97 | 98 | Widget buildSwiper() { 99 | return new Swiper( 100 | onTap: (int index) { 101 | Navigator.of(context) 102 | .push(new MaterialPageRoute(builder: (BuildContext context) { 103 | return Scaffold( 104 | appBar: AppBar( 105 | title: Text("New page"), 106 | ), 107 | body: Container(), 108 | ); 109 | })); 110 | }, 111 | customLayoutOption: customLayoutOption, 112 | fade: _fade, 113 | index: _currentIndex, 114 | onIndexChanged: (int index) { 115 | setState(() { 116 | _currentIndex = index; 117 | }); 118 | }, 119 | curve: _curve, 120 | scale: _scale, 121 | itemWidth: 300.0, 122 | controller: _controller, 123 | layout: _layout, 124 | outer: _outer, 125 | itemHeight: 200.0, 126 | viewportFraction: _viewportFraction, 127 | autoplayDelay: _autoplayDely, 128 | loop: _loop, 129 | autoplay: _autoplay, 130 | itemBuilder: _buildItem, 131 | itemCount: _itemCount, 132 | scrollDirection: _scrollDirection, 133 | indicatorLayout: PageIndicatorLayout.COLOR, 134 | autoplayDisableOnInteraction: _autoplayDisableOnInteraction, 135 | pagination: new SwiperPagination( 136 | builder: const DotSwiperPaginationBuilder( 137 | size: 20.0, activeSize: 20.0, space: 10.0)), 138 | ); 139 | } 140 | 141 | SwiperController _controller; 142 | TextEditingController numberController = new TextEditingController(); 143 | @override 144 | Widget build(BuildContext context) { 145 | return new Column(children: [ 146 | new Container( 147 | color: Colors.black87, 148 | child: new SizedBox( 149 | height: 300.0, width: double.infinity, child: buildSwiper()), 150 | ), 151 | new Expanded( 152 | child: new ListView( 153 | children: [ 154 | new Text("Index:$_currentIndex"), 155 | new Row( 156 | children: [ 157 | new RaisedButton( 158 | onPressed: () { 159 | _controller.previous(animation: true); 160 | }, 161 | child: new Text("Prev"), 162 | ), 163 | new RaisedButton( 164 | onPressed: () { 165 | _controller.next(animation: true); 166 | }, 167 | child: new Text("Next"), 168 | ), 169 | new Expanded( 170 | child: new TextField( 171 | controller: numberController, 172 | )), 173 | new RaisedButton( 174 | onPressed: () { 175 | var text = numberController.text; 176 | setState(() { 177 | _currentIndex = int.parse(text); 178 | }); 179 | }, 180 | child: new Text("Update"), 181 | ), 182 | ], 183 | ), 184 | new FormWidget( 185 | label: "layout", 186 | child: new FormSelect( 187 | placeholder: "Select layout", 188 | value: _layout, 189 | values: [ 190 | SwiperLayout.DEFAULT, 191 | SwiperLayout.STACK, 192 | SwiperLayout.TINDER, 193 | SwiperLayout.CUSTOM 194 | ], 195 | valueChanged: (value) { 196 | _layout = value; 197 | setState(() {}); 198 | })), 199 | new FormWidget( 200 | label: "scrollDirection", 201 | child: new Switch( 202 | value: _scrollDirection == Axis.horizontal, 203 | onChanged: (bool value) => setState(() => _scrollDirection = 204 | value ? Axis.horizontal : Axis.vertical)), 205 | ), 206 | new FormWidget( 207 | label: "autoplayDisableOnInteractio", 208 | child: new Switch( 209 | value: _autoplayDisableOnInteraction, 210 | onChanged: (bool value) => 211 | setState(() => _autoplayDisableOnInteraction = value)), 212 | ), 213 | //Pannel Begin 214 | new FormWidget( 215 | label: "loop", 216 | child: new Switch( 217 | value: _loop, 218 | onChanged: (bool value) => setState(() => _loop = value)), 219 | ), 220 | new FormWidget( 221 | label: "outer", 222 | child: new Switch( 223 | value: _outer, 224 | onChanged: (bool value) => setState(() => _outer = value)), 225 | ), 226 | //Pannel Begin 227 | new FormWidget( 228 | label: "autoplay", 229 | child: new Switch( 230 | value: _autoplay, 231 | onChanged: (bool value) => setState(() => _autoplay = value)), 232 | ), 233 | 234 | new FormWidget( 235 | label: "padding", 236 | child: new NumberPad( 237 | number: _padding, 238 | step: 5.0, 239 | min: 0.0, 240 | max: 30.0, 241 | onChangeValue: (num value) { 242 | _padding = value.toDouble(); 243 | setState(() {}); 244 | }, 245 | ), 246 | ), 247 | new FormWidget( 248 | label: "scale", 249 | child: new NumberPad( 250 | number: _scale, 251 | step: 0.1, 252 | min: 0.0, 253 | max: 1.0, 254 | onChangeValue: (num value) { 255 | _scale = value.toDouble(); 256 | setState(() {}); 257 | }, 258 | ), 259 | ), 260 | new FormWidget( 261 | label: "fade", 262 | child: new NumberPad( 263 | number: _fade, 264 | step: 0.1, 265 | min: 0.0, 266 | max: 1.0, 267 | onChangeValue: (num value) { 268 | _fade = value.toDouble(); 269 | setState(() {}); 270 | }, 271 | ), 272 | ), 273 | new FormWidget( 274 | label: "itemCount", 275 | child: new NumberPad( 276 | number: _itemCount, 277 | step: 1, 278 | min: 0, 279 | max: 100, 280 | onChangeValue: (num value) { 281 | _itemCount = value.toInt(); 282 | setState(() {}); 283 | }, 284 | ), 285 | ), 286 | 287 | new FormWidget( 288 | label: "radius", 289 | child: new NumberPad( 290 | number: _radius, 291 | step: 1.0, 292 | min: 0.0, 293 | max: 30.0, 294 | onChangeValue: (num value) { 295 | this._radius = value.toDouble(); 296 | setState(() {}); 297 | }, 298 | ), 299 | ), 300 | 301 | new FormWidget( 302 | label: "viewportFraction", 303 | child: new NumberPad( 304 | number: _viewportFraction, 305 | step: 0.1, 306 | max: 1.0, 307 | min: 0.5, 308 | onChangeValue: (num value) { 309 | _viewportFraction = value.toDouble(); 310 | setState(() {}); 311 | }, 312 | ), 313 | ), 314 | 315 | new FormWidget( 316 | label: "curve", 317 | child: new FormSelect( 318 | placeholder: "Select curve", 319 | value: _layout, 320 | values: [ 321 | Curves.easeInOut, 322 | Curves.ease, 323 | Curves.bounceInOut, 324 | Curves.bounceOut, 325 | Curves.bounceIn, 326 | Curves.fastOutSlowIn 327 | ], 328 | valueChanged: (value) { 329 | _curve = value; 330 | setState(() {}); 331 | })), 332 | ], 333 | )) 334 | ]); 335 | } 336 | } 337 | -------------------------------------------------------------------------------- /example/lib/src/ExampleSwiperInScrollView.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_swiper/flutter_swiper.dart'; 3 | 4 | class ExampleSwiperInScrollView extends StatefulWidget { 5 | @override 6 | State createState() { 7 | return new _ExampleState(); 8 | } 9 | } 10 | 11 | class _ExampleState extends State 12 | with TickerProviderStateMixin { 13 | AnimationController controller; 14 | Animation _animation10; 15 | Animation _animation11; 16 | Animation _animation12; 17 | Animation _animation13; 18 | 19 | _ExampleState(); 20 | 21 | @override 22 | void dispose() { 23 | controller.dispose(); 24 | 25 | super.dispose(); 26 | } 27 | 28 | @override 29 | void initState() { 30 | controller = new AnimationController(vsync: this); 31 | _animation10 = new Tween(begin: 0.0, end: 1.0).animate(controller); 32 | _animation11 = new Tween(begin: 0.0, end: 1.0).animate(controller); 33 | _animation12 = new Tween(begin: 0.0, end: 1.0).animate(controller); 34 | _animation13 = new Tween(begin: 0.0, end: 1.0).animate(controller); 35 | controller.animateTo(1.0, duration: new Duration(seconds: 3)); 36 | super.initState(); 37 | } 38 | 39 | Widget _buildDynamicCard() { 40 | return new Card( 41 | elevation: 2.0, 42 | color: Colors.white, 43 | child: new Stack( 44 | children: [ 45 | Column( 46 | children: [ 47 | Container( 48 | padding: const EdgeInsets.all(10.0), 49 | ), 50 | ], 51 | ), 52 | new Column( 53 | children: [ 54 | new Row( 55 | mainAxisAlignment: MainAxisAlignment.spaceEvenly, 56 | children: [ 57 | Column( 58 | children: [ 59 | Container( 60 | padding: const EdgeInsets.only(top: 40.0), 61 | ), 62 | new ScaleTransition( 63 | scale: _animation10, 64 | alignment: FractionalOffset.center, 65 | ), 66 | ], 67 | ), 68 | new Column( 69 | children: [ 70 | Container( 71 | padding: const EdgeInsets.only(top: 160.0), 72 | ), 73 | new ScaleTransition( 74 | scale: _animation11, 75 | alignment: FractionalOffset.center, 76 | ), 77 | ], 78 | ), 79 | Container( 80 | padding: const EdgeInsets.all(1.0), 81 | ), 82 | Column( 83 | children: [ 84 | Container( 85 | padding: const EdgeInsets.only(top: 160.0), 86 | ), 87 | new ScaleTransition( 88 | scale: _animation12, 89 | alignment: FractionalOffset.center, 90 | ), 91 | ], 92 | ), 93 | Column( 94 | children: [ 95 | Container( 96 | padding: const EdgeInsets.only(top: 40.0), 97 | ), 98 | new ScaleTransition( 99 | scale: _animation13, 100 | alignment: FractionalOffset.center, 101 | ), 102 | ], 103 | ), 104 | ]), 105 | Container( 106 | padding: const EdgeInsets.all(10.0), 107 | ), 108 | ], 109 | ) 110 | ], 111 | ), 112 | ); 113 | } 114 | 115 | @override 116 | Widget build(BuildContext context) { 117 | double screenWidth = MediaQuery.of(context).size.width; 118 | return new Container( 119 | color: Theme.of(context).primaryColorLight, 120 | child: CustomScrollView( 121 | slivers: [ 122 | SliverList( 123 | delegate: new SliverChildBuilderDelegate((c, i) { 124 | return new Column( 125 | mainAxisSize: MainAxisSize.min, 126 | children: [ 127 | new SizedBox( 128 | height: 100.0, 129 | child: Swiper( 130 | scale:0.8, 131 | fade:0.8, 132 | itemBuilder: (c, i) { 133 | return Container( 134 | color: Colors.grey, 135 | child: Text("$i"), 136 | ); 137 | }, 138 | itemCount: 10, 139 | pagination: new SwiperPagination(), 140 | ), 141 | ), 142 | new SizedBox( 143 | height: 100.0, 144 | child: Swiper( 145 | scale:0.8, 146 | fade:0.8, 147 | itemBuilder: (c, i) { 148 | return Container( 149 | color: Colors.grey, 150 | child: Text("$i"), 151 | ); 152 | }, 153 | pagination: new SwiperPagination( 154 | builder: SwiperPagination.fraction), 155 | itemCount: 0), 156 | ), 157 | new SizedBox( 158 | height: 100.0, 159 | child: Swiper( 160 | scale:0.8, 161 | fade:0.8, 162 | itemBuilder: (c, i) { 163 | return Container( 164 | color: Colors.grey, 165 | child: Text("$i"), 166 | ); 167 | }, 168 | pagination: new SwiperPagination( 169 | builder: SwiperPagination.fraction), 170 | itemCount: 10000), 171 | ), 172 | new SizedBox( 173 | height: 100.0, 174 | child: Swiper( 175 | outer: true, 176 | scale:0.8, 177 | fade:0.8, 178 | itemBuilder: (c, i) { 179 | return new Container( 180 | color: Colors.grey, 181 | child: Text("$i"), 182 | ); 183 | }, 184 | pagination: SwiperPagination(), 185 | itemCount: 10), 186 | ), 187 | new Text("Image from network"), 188 | new SizedBox( 189 | height: 300.0, 190 | child: new Swiper( 191 | itemCount: 10, 192 | itemBuilder: (BuildContext context, int index) { 193 | return new Image.network( 194 | "https://ss3.baidu.com/9fo3dSag_xI4khGko9WTAnF6hhy/image/h%3D300/sign=87d6daed02f41bd5c553eef461d881a0/f9198618367adab4b025268587d4b31c8601e47b.jpg"); 195 | }, 196 | ), 197 | ), 198 | new SizedBox( 199 | height: 100.0, 200 | child: new Swiper( 201 | outer: true, 202 | scale:0.8, 203 | fade:0.8, 204 | itemBuilder: (c, i) { 205 | return new Card( 206 | elevation: 2.0, 207 | child: new Stack( 208 | alignment: AlignmentDirectional.center, 209 | children: [ 210 | new Container( 211 | child: new Image.network( 212 | "https://ss3.baidu.com/9fo3dSag_xI4khGko9WTAnF6hhy/image/h%3D300/sign=87d6daed02f41bd5c553eef461d881a0/f9198618367adab4b025268587d4b31c8601e47b.jpg"), 213 | ), 214 | FractionalTranslation( 215 | translation: Offset(0.0, 0.0), 216 | child: new Container( 217 | alignment: new FractionalOffset(0.0, 0.0), 218 | decoration: new BoxDecoration( 219 | border: new Border.all( 220 | color: Colors.lightBlue.withOpacity(0.5), 221 | width: 100.0, 222 | ), 223 | shape: BoxShape.circle, 224 | ), 225 | ), 226 | ), 227 | new Container( 228 | //padding: const EdgeInsets.only(bottom:10.0), 229 | margin: new EdgeInsets.all(140.0), 230 | 231 | child: Icon(Icons.location_on, 232 | color: Colors.white, size: 25.0), 233 | ), 234 | ], 235 | ), 236 | ); 237 | }, 238 | pagination: 239 | new SwiperPagination(alignment: Alignment.topCenter), 240 | itemCount: 10), 241 | ), 242 | new SizedBox( 243 | height: 400.0, 244 | child: new Swiper( 245 | outer: true, 246 | itemBuilder: (c, i) { 247 | return _buildDynamicCard(); 248 | }, 249 | pagination: 250 | new SwiperPagination(alignment: Alignment.topCenter), 251 | itemCount: 10), 252 | ), 253 | new SizedBox( 254 | height: 100.0, 255 | child: new Swiper( 256 | outer: true, 257 | fade:0.8, 258 | viewportFraction: 0.8, 259 | scale: 0.8, 260 | itemBuilder: (c, i) { 261 | return Container( 262 | color: Colors.grey, 263 | child: Text("$i"), 264 | ); 265 | }, 266 | pagination: 267 | new SwiperPagination(alignment: Alignment.topCenter), 268 | itemCount: 10), 269 | ), 270 | ], 271 | ); 272 | }, childCount: 1)) 273 | ], 274 | ), 275 | ); 276 | } 277 | } 278 | -------------------------------------------------------------------------------- /example/lib/src/config.dart: -------------------------------------------------------------------------------- 1 | const List images = [ 2 | "images/bg0.jpeg", 3 | "images/bg1.jpeg", 4 | "images/bg2.jpeg", 5 | ]; 6 | -------------------------------------------------------------------------------- /example/lib/src/forms/form_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter/cupertino.dart'; 3 | 4 | class FormWidget extends StatelessWidget { 5 | final String label; 6 | 7 | final Widget child; 8 | 9 | FormWidget({this.label, this.child}); 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | return new Padding( 14 | padding: new EdgeInsets.all(5.0), 15 | child: new Row( 16 | children: [ 17 | new Text(label, style: new TextStyle(fontSize: 14.0)), 18 | new Expanded( 19 | child: 20 | new Align(alignment: Alignment.centerRight, child: child)) 21 | ], 22 | )); 23 | } 24 | } 25 | 26 | class FormSelect extends StatefulWidget { 27 | final String placeholder; 28 | final ValueChanged valueChanged; 29 | final List values; 30 | final dynamic value; 31 | 32 | FormSelect({this.placeholder, this.valueChanged, this.value, this.values}); 33 | 34 | @override 35 | State createState() { 36 | return _FormSelectState(); 37 | } 38 | } 39 | 40 | class _FormSelectState extends State { 41 | int _selectedIndex = 0; 42 | 43 | @override 44 | void initState() { 45 | for (int i = 0, c = widget.values.length; i < c; ++i) { 46 | if (widget.values[i] == widget.value) { 47 | _selectedIndex = i; 48 | break; 49 | } 50 | } 51 | 52 | super.initState(); 53 | } 54 | 55 | @override 56 | Widget build(BuildContext context) { 57 | String placeholder = widget.placeholder; 58 | List values = widget.values; 59 | 60 | return new Container( 61 | child: new InkWell( 62 | child: new Text(_selectedIndex < 0 63 | ? placeholder 64 | : values[_selectedIndex].toString()), 65 | onTap: () { 66 | _selectedIndex = 0; 67 | showBottomSheet( 68 | context: context, 69 | builder: (BuildContext context) { 70 | return new SizedBox( 71 | height: values.length * 30.0 + 200.0, 72 | child: new Column( 73 | mainAxisSize: MainAxisSize.min, 74 | children: [ 75 | new SizedBox( 76 | height: values.length * 30.0 + 70.0, 77 | child: new CupertinoPicker( 78 | itemExtent: 30.0, 79 | children: values.map((dynamic value) { 80 | return new Text(value.toString()); 81 | }).toList(), 82 | onSelectedItemChanged: (int index) { 83 | _selectedIndex = index; 84 | }, 85 | ), 86 | ), 87 | new Center( 88 | child: new RaisedButton( 89 | onPressed: () { 90 | if (_selectedIndex >= 0) { 91 | widget 92 | .valueChanged(widget.values[_selectedIndex]); 93 | } 94 | 95 | setState(() {}); 96 | 97 | Navigator.of(context).pop(); 98 | }, 99 | child: new Text("ok"), 100 | ), 101 | ) 102 | ], 103 | ), 104 | ); 105 | }); 106 | }, 107 | ), 108 | ); 109 | } 110 | } 111 | 112 | class NumberPad extends StatelessWidget { 113 | final num number; 114 | final num step; 115 | final num max; 116 | final num min; 117 | final ValueChanged onChangeValue; 118 | 119 | NumberPad({this.number, this.step, this.onChangeValue, this.max, this.min}); 120 | 121 | void onAdd() { 122 | onChangeValue(number + step > max ? max : number + step); 123 | } 124 | 125 | void onSub() { 126 | onChangeValue(number - step < min ? min : number - step); 127 | } 128 | 129 | @override 130 | Widget build(BuildContext context) { 131 | return new Row( 132 | mainAxisSize: MainAxisSize.min, 133 | children: [ 134 | new IconButton(icon: new Icon(Icons.exposure_neg_1), onPressed: onSub), 135 | new Text( 136 | number is int ? number.toString() : number.toStringAsFixed(1), 137 | style: new TextStyle(fontSize: 14.0), 138 | ), 139 | new IconButton(icon: new Icon(Icons.exposure_plus_1), onPressed: onAdd) 140 | ], 141 | ); 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /example/pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://www.dartlang.org/tools/pub/glossary#lockfile 3 | packages: 4 | async: 5 | dependency: transitive 6 | description: 7 | name: async 8 | url: "https://pub.flutter-io.cn" 9 | source: hosted 10 | version: "2.0.8" 11 | boolean_selector: 12 | dependency: transitive 13 | description: 14 | name: boolean_selector 15 | url: "https://pub.flutter-io.cn" 16 | source: hosted 17 | version: "1.0.4" 18 | charcode: 19 | dependency: transitive 20 | description: 21 | name: charcode 22 | url: "https://pub.flutter-io.cn" 23 | source: hosted 24 | version: "1.1.2" 25 | collection: 26 | dependency: transitive 27 | description: 28 | name: collection 29 | url: "https://pub.flutter-io.cn" 30 | source: hosted 31 | version: "1.14.11" 32 | cupertino_icons: 33 | dependency: "direct main" 34 | description: 35 | name: cupertino_icons 36 | url: "https://pub.flutter-io.cn" 37 | source: hosted 38 | version: "0.1.2" 39 | flutter: 40 | dependency: "direct main" 41 | description: flutter 42 | source: sdk 43 | version: "0.0.0" 44 | flutter_page_indicator: 45 | dependency: transitive 46 | description: 47 | name: flutter_page_indicator 48 | url: "https://pub.flutter-io.cn" 49 | source: hosted 50 | version: "0.0.3" 51 | flutter_swiper: 52 | dependency: "direct main" 53 | description: 54 | path: ".." 55 | relative: true 56 | source: path 57 | version: "1.1.5" 58 | flutter_test: 59 | dependency: "direct dev" 60 | description: flutter 61 | source: sdk 62 | version: "0.0.0" 63 | matcher: 64 | dependency: transitive 65 | description: 66 | name: matcher 67 | url: "https://pub.flutter-io.cn" 68 | source: hosted 69 | version: "0.12.3+1" 70 | meta: 71 | dependency: transitive 72 | description: 73 | name: meta 74 | url: "https://pub.flutter-io.cn" 75 | source: hosted 76 | version: "1.1.6" 77 | path: 78 | dependency: transitive 79 | description: 80 | name: path 81 | url: "https://pub.flutter-io.cn" 82 | source: hosted 83 | version: "1.6.2" 84 | percent_indicator: 85 | dependency: "direct main" 86 | description: 87 | name: percent_indicator 88 | url: "https://pub.flutter-io.cn" 89 | source: hosted 90 | version: "1.0.9" 91 | quiver: 92 | dependency: transitive 93 | description: 94 | name: quiver 95 | url: "https://pub.flutter-io.cn" 96 | source: hosted 97 | version: "2.0.1" 98 | sky_engine: 99 | dependency: transitive 100 | description: flutter 101 | source: sdk 102 | version: "0.0.99" 103 | source_span: 104 | dependency: transitive 105 | description: 106 | name: source_span 107 | url: "https://pub.flutter-io.cn" 108 | source: hosted 109 | version: "1.4.1" 110 | stack_trace: 111 | dependency: transitive 112 | description: 113 | name: stack_trace 114 | url: "https://pub.flutter-io.cn" 115 | source: hosted 116 | version: "1.9.3" 117 | stream_channel: 118 | dependency: transitive 119 | description: 120 | name: stream_channel 121 | url: "https://pub.flutter-io.cn" 122 | source: hosted 123 | version: "1.6.8" 124 | string_scanner: 125 | dependency: transitive 126 | description: 127 | name: string_scanner 128 | url: "https://pub.flutter-io.cn" 129 | source: hosted 130 | version: "1.0.4" 131 | term_glyph: 132 | dependency: transitive 133 | description: 134 | name: term_glyph 135 | url: "https://pub.flutter-io.cn" 136 | source: hosted 137 | version: "1.0.1" 138 | test_api: 139 | dependency: transitive 140 | description: 141 | name: test_api 142 | url: "https://pub.flutter-io.cn" 143 | source: hosted 144 | version: "0.2.1" 145 | transformer_page_view: 146 | dependency: transitive 147 | description: 148 | name: transformer_page_view 149 | url: "https://pub.flutter-io.cn" 150 | source: hosted 151 | version: "0.1.5" 152 | typed_data: 153 | dependency: transitive 154 | description: 155 | name: typed_data 156 | url: "https://pub.flutter-io.cn" 157 | source: hosted 158 | version: "1.1.6" 159 | vector_math: 160 | dependency: transitive 161 | description: 162 | name: vector_math 163 | url: "https://pub.flutter-io.cn" 164 | source: hosted 165 | version: "2.0.8" 166 | sdks: 167 | dart: ">=2.0.0 <3.0.0" 168 | flutter: ">=0.1.4 <3.0.0" 169 | -------------------------------------------------------------------------------- /example/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: example 2 | description: A new Flutter project. 3 | 4 | dependencies: 5 | flutter: 6 | sdk: flutter 7 | 8 | # The following adds the Cupertino Icons font to your application. 9 | # Use with the CupertinoIcons class for iOS style icons. 10 | cupertino_icons: ^0.1.0 11 | 12 | flutter_swiper: 13 | path: ../ 14 | 15 | percent_indicator: 16 | 17 | dev_dependencies: 18 | flutter_test: 19 | sdk: flutter 20 | 21 | flutter: 22 | uses-material-design: true 23 | 24 | 25 | assets: 26 | - images/bg0.jpeg 27 | - images/bg1.jpeg 28 | - images/bg2.jpeg 29 | - images/bg.jpeg 30 | - images/1.png 31 | - images/2.png 32 | - images/3.png 33 | -------------------------------------------------------------------------------- /example/res/1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/best-flutter/flutter_swiper/71eb23671d46f624790019963c7ce10456dec652/example/res/1.gif -------------------------------------------------------------------------------- /example/res/2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/best-flutter/flutter_swiper/71eb23671d46f624790019963c7ce10456dec652/example/res/2.gif -------------------------------------------------------------------------------- /example/res/3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/best-flutter/flutter_swiper/71eb23671d46f624790019963c7ce10456dec652/example/res/3.gif -------------------------------------------------------------------------------- /example/res/4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/best-flutter/flutter_swiper/71eb23671d46f624790019963c7ce10456dec652/example/res/4.gif -------------------------------------------------------------------------------- /example/res/5.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/best-flutter/flutter_swiper/71eb23671d46f624790019963c7ce10456dec652/example/res/5.gif -------------------------------------------------------------------------------- /example/test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // To perform an interaction with a widget in your test, use the WidgetTester utility that Flutter 3 | // provides. For example, you can send tap and scroll gestures. You can also use WidgetTester to 4 | // find child widgets in the widget tree, read text, and verify that the values of widget properties 5 | // are correct. 6 | 7 | import 'package:flutter/material.dart'; 8 | import 'package:flutter_test/flutter_test.dart'; 9 | 10 | import 'package:example/main.dart'; 11 | 12 | void main() { 13 | testWidgets('Counter increments smoke test', (WidgetTester tester) async { 14 | // Build our app and trigger a frame. 15 | await tester.pumpWidget(new MyApp()); 16 | 17 | // Verify that our counter starts at 0. 18 | expect(find.text('0'), findsOneWidget); 19 | expect(find.text('1'), findsNothing); 20 | 21 | // Tap the '+' icon and trigger a frame. 22 | await tester.tap(find.byIcon(Icons.add)); 23 | await tester.pump(); 24 | 25 | // Verify that our counter has incremented. 26 | expect(find.text('0'), findsNothing); 27 | expect(find.text('1'), findsOneWidget); 28 | }); 29 | } 30 | -------------------------------------------------------------------------------- /flutter_swiper.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /lib/flutter_swiper.dart: -------------------------------------------------------------------------------- 1 | library flutter_swiper; 2 | 3 | export 'src/swiper.dart'; 4 | export 'src/swiper_pagination.dart'; 5 | export 'src/swiper_control.dart'; 6 | export 'src/swiper_controller.dart'; 7 | export 'src/swiper_plugin.dart'; 8 | -------------------------------------------------------------------------------- /lib/src/custom_layout.dart: -------------------------------------------------------------------------------- 1 | part of 'swiper.dart'; 2 | 3 | abstract class _CustomLayoutStateBase extends State 4 | with SingleTickerProviderStateMixin { 5 | double _swiperWidth; 6 | double _swiperHeight; 7 | Animation _animation; 8 | AnimationController _animationController; 9 | int _startIndex; 10 | int _animationCount; 11 | 12 | @override 13 | void initState() { 14 | if (widget.itemWidth == null) { 15 | throw new Exception( 16 | "==============\n\nwidget.itemWith must not be null when use stack layout.\n========\n"); 17 | } 18 | 19 | _createAnimationController(); 20 | widget.controller.addListener(_onController); 21 | super.initState(); 22 | } 23 | 24 | void _createAnimationController() { 25 | _animationController = new AnimationController(vsync: this, value: 0.5); 26 | Tween tween = new Tween(begin: 0.0, end: 1.0); 27 | _animation = tween.animate(_animationController); 28 | } 29 | 30 | @override 31 | void didChangeDependencies() { 32 | WidgetsBinding.instance.addPostFrameCallback(_getSize); 33 | super.didChangeDependencies(); 34 | } 35 | 36 | void _getSize(_) { 37 | afterRender(); 38 | } 39 | 40 | @mustCallSuper 41 | void afterRender() { 42 | RenderObject renderObject = context.findRenderObject(); 43 | Size size = renderObject.paintBounds.size; 44 | _swiperWidth = size.width; 45 | _swiperHeight = size.height; 46 | setState(() {}); 47 | } 48 | 49 | @override 50 | void didUpdateWidget(T oldWidget) { 51 | if (widget.controller != oldWidget.controller) { 52 | oldWidget.controller.removeListener(_onController); 53 | widget.controller.addListener(_onController); 54 | } 55 | 56 | if (widget.loop != oldWidget.loop) { 57 | if (!widget.loop) { 58 | _currentIndex = _ensureIndex(_currentIndex); 59 | } 60 | } 61 | 62 | super.didUpdateWidget(oldWidget); 63 | } 64 | 65 | int _ensureIndex(int index) { 66 | index = index % widget.itemCount; 67 | if (index < 0) { 68 | index += widget.itemCount; 69 | } 70 | return index; 71 | } 72 | 73 | @override 74 | void dispose() { 75 | widget.controller.removeListener(_onController); 76 | _animationController?.dispose(); 77 | super.dispose(); 78 | } 79 | 80 | Widget _buildItem(int i, int realIndex, double animationValue); 81 | 82 | Widget _buildContainer(List list) { 83 | return new Stack( 84 | children: list, 85 | ); 86 | } 87 | 88 | Widget _buildAnimation(BuildContext context, Widget w) { 89 | List list = []; 90 | 91 | double animationValue = _animation.value; 92 | 93 | for (int i = 0; i < _animationCount; ++i) { 94 | int realIndex = _currentIndex + i + _startIndex; 95 | realIndex = realIndex % widget.itemCount; 96 | if (realIndex < 0) { 97 | realIndex += widget.itemCount; 98 | } 99 | 100 | list.add(_buildItem(i, realIndex, animationValue)); 101 | } 102 | 103 | return new GestureDetector( 104 | behavior: HitTestBehavior.opaque, 105 | onPanStart: _onPanStart, 106 | onPanEnd: _onPanEnd, 107 | onPanUpdate: _onPanUpdate, 108 | child: new ClipRect( 109 | child: new Center( 110 | child: _buildContainer(list), 111 | ), 112 | ), 113 | ); 114 | } 115 | 116 | @override 117 | Widget build(BuildContext context) { 118 | if (_animationCount == null) { 119 | return new Container(); 120 | } 121 | return new AnimatedBuilder( 122 | animation: _animationController, builder: _buildAnimation); 123 | } 124 | 125 | double _currentValue; 126 | double _currentPos; 127 | 128 | bool _lockScroll = false; 129 | 130 | void _move(double position, {int nextIndex}) async { 131 | if (_lockScroll) return; 132 | try { 133 | _lockScroll = true; 134 | await _animationController.animateTo(position, 135 | duration: new Duration(milliseconds: widget.duration), 136 | curve: widget.curve); 137 | if (nextIndex != null) { 138 | widget.onIndexChanged(widget.getCorrectIndex(nextIndex)); 139 | } 140 | } catch (e) { 141 | print(e); 142 | } finally { 143 | if (nextIndex != null) { 144 | try { 145 | _animationController.value = 0.5; 146 | } catch (e) { 147 | print(e); 148 | } 149 | 150 | _currentIndex = nextIndex; 151 | } 152 | _lockScroll = false; 153 | } 154 | } 155 | 156 | int _nextIndex() { 157 | int index = _currentIndex + 1; 158 | if (!widget.loop && index >= widget.itemCount - 1) { 159 | return widget.itemCount - 1; 160 | } 161 | return index; 162 | } 163 | 164 | int _prevIndex() { 165 | int index = _currentIndex - 1; 166 | if (!widget.loop && index < 0) { 167 | return 0; 168 | } 169 | return index; 170 | } 171 | 172 | void _onController() { 173 | switch (widget.controller.event) { 174 | case IndexController.PREVIOUS: 175 | int prevIndex = _prevIndex(); 176 | if (prevIndex == _currentIndex) return; 177 | _move(1.0, nextIndex: prevIndex); 178 | break; 179 | case IndexController.NEXT: 180 | int nextIndex = _nextIndex(); 181 | if (nextIndex == _currentIndex) return; 182 | _move(0.0, nextIndex: nextIndex); 183 | break; 184 | case IndexController.MOVE: 185 | throw new Exception( 186 | "Custom layout does not support SwiperControllerEvent.MOVE_INDEX yet!"); 187 | case SwiperController.STOP_AUTOPLAY: 188 | case SwiperController.START_AUTOPLAY: 189 | break; 190 | } 191 | } 192 | 193 | void _onPanEnd(DragEndDetails details) { 194 | if (_lockScroll) return; 195 | 196 | double velocity = widget.scrollDirection == Axis.horizontal 197 | ? details.velocity.pixelsPerSecond.dx 198 | : details.velocity.pixelsPerSecond.dy; 199 | 200 | if (_animationController.value >= 0.75 || velocity > 500.0) { 201 | if (_currentIndex <= 0 && !widget.loop) { 202 | return; 203 | } 204 | _move(1.0, nextIndex: _currentIndex - 1); 205 | } else if (_animationController.value < 0.25 || velocity < -500.0) { 206 | if (_currentIndex >= widget.itemCount - 1 && !widget.loop) { 207 | return; 208 | } 209 | _move(0.0, nextIndex: _currentIndex + 1); 210 | } else { 211 | _move(0.5); 212 | } 213 | } 214 | 215 | void _onPanStart(DragStartDetails details) { 216 | if (_lockScroll) return; 217 | _currentValue = _animationController.value; 218 | _currentPos = widget.scrollDirection == Axis.horizontal 219 | ? details.globalPosition.dx 220 | : details.globalPosition.dy; 221 | } 222 | 223 | void _onPanUpdate(DragUpdateDetails details) { 224 | if (_lockScroll) return; 225 | double value = _currentValue + 226 | ((widget.scrollDirection == Axis.horizontal 227 | ? details.globalPosition.dx 228 | : details.globalPosition.dy) - 229 | _currentPos) / 230 | _swiperWidth / 231 | 2; 232 | // no loop ? 233 | if (!widget.loop) { 234 | if (_currentIndex >= widget.itemCount - 1) { 235 | if (value < 0.5) { 236 | value = 0.5; 237 | } 238 | } else if (_currentIndex <= 0) { 239 | if (value > 0.5) { 240 | value = 0.5; 241 | } 242 | } 243 | } 244 | 245 | _animationController.value = value; 246 | } 247 | 248 | int _currentIndex = 0; 249 | } 250 | 251 | double _getValue(List values, double animationValue, int index) { 252 | double s = values[index]; 253 | if (animationValue >= 0.5) { 254 | if (index < values.length - 1) { 255 | s = s + (values[index + 1] - s) * (animationValue - 0.5) * 2.0; 256 | } 257 | } else { 258 | if (index != 0) { 259 | s = s - (s - values[index - 1]) * (0.5 - animationValue) * 2.0; 260 | } 261 | } 262 | return s; 263 | } 264 | 265 | Offset _getOffsetValue(List values, double animationValue, int index) { 266 | Offset s = values[index]; 267 | double dx = s.dx; 268 | double dy = s.dy; 269 | if (animationValue >= 0.5) { 270 | if (index < values.length - 1) { 271 | dx = dx + (values[index + 1].dx - dx) * (animationValue - 0.5) * 2.0; 272 | dy = dy + (values[index + 1].dy - dy) * (animationValue - 0.5) * 2.0; 273 | } 274 | } else { 275 | if (index != 0) { 276 | dx = dx - (dx - values[index - 1].dx) * (0.5 - animationValue) * 2.0; 277 | dy = dy - (dy - values[index - 1].dy) * (0.5 - animationValue) * 2.0; 278 | } 279 | } 280 | return new Offset(dx, dy); 281 | } 282 | 283 | abstract class TransformBuilder { 284 | List values; 285 | TransformBuilder({this.values}); 286 | Widget build(int i, double animationValue, Widget widget); 287 | } 288 | 289 | class ScaleTransformBuilder extends TransformBuilder { 290 | final Alignment alignment; 291 | ScaleTransformBuilder({List values, this.alignment: Alignment.center}) 292 | : super(values: values); 293 | 294 | Widget build(int i, double animationValue, Widget widget) { 295 | double s = _getValue(values, animationValue, i); 296 | return new Transform.scale(scale: s, child: widget); 297 | } 298 | } 299 | 300 | class OpacityTransformBuilder extends TransformBuilder { 301 | OpacityTransformBuilder({List values}) : super(values: values); 302 | 303 | Widget build(int i, double animationValue, Widget widget) { 304 | double v = _getValue(values, animationValue, i); 305 | return new Opacity( 306 | opacity: v, 307 | child: widget, 308 | ); 309 | } 310 | } 311 | 312 | class RotateTransformBuilder extends TransformBuilder { 313 | RotateTransformBuilder({List values}) : super(values: values); 314 | 315 | Widget build(int i, double animationValue, Widget widget) { 316 | double v = _getValue(values, animationValue, i); 317 | return new Transform.rotate( 318 | angle: v, 319 | child: widget, 320 | ); 321 | } 322 | } 323 | 324 | class TranslateTransformBuilder extends TransformBuilder { 325 | TranslateTransformBuilder({List values}) : super(values: values); 326 | 327 | @override 328 | Widget build(int i, double animationValue, Widget widget) { 329 | Offset s = _getOffsetValue(values, animationValue, i); 330 | return new Transform.translate( 331 | offset: s, 332 | child: widget, 333 | ); 334 | } 335 | } 336 | 337 | class CustomLayoutOption { 338 | final List builders = []; 339 | final int startIndex; 340 | final int stateCount; 341 | 342 | CustomLayoutOption({this.stateCount, this.startIndex}) 343 | : assert(startIndex != null, stateCount != null); 344 | 345 | CustomLayoutOption addOpacity(List values) { 346 | builders.add(new OpacityTransformBuilder(values: values)); 347 | return this; 348 | } 349 | 350 | CustomLayoutOption addTranslate(List values) { 351 | builders.add(new TranslateTransformBuilder(values: values)); 352 | return this; 353 | } 354 | 355 | CustomLayoutOption addScale(List values, Alignment alignment) { 356 | builders 357 | .add(new ScaleTransformBuilder(values: values, alignment: alignment)); 358 | return this; 359 | } 360 | 361 | CustomLayoutOption addRotate(List values) { 362 | builders.add(new RotateTransformBuilder(values: values)); 363 | return this; 364 | } 365 | } 366 | 367 | class _CustomLayoutSwiper extends _SubSwiper { 368 | final CustomLayoutOption option; 369 | 370 | _CustomLayoutSwiper( 371 | {this.option, 372 | double itemWidth, 373 | bool loop, 374 | double itemHeight, 375 | ValueChanged onIndexChanged, 376 | Key key, 377 | IndexedWidgetBuilder itemBuilder, 378 | Curve curve, 379 | int duration, 380 | int index, 381 | int itemCount, 382 | Axis scrollDirection, 383 | SwiperController controller}) 384 | : assert(option != null), 385 | super( 386 | loop: loop, 387 | onIndexChanged: onIndexChanged, 388 | itemWidth: itemWidth, 389 | itemHeight: itemHeight, 390 | key: key, 391 | itemBuilder: itemBuilder, 392 | curve: curve, 393 | duration: duration, 394 | index: index, 395 | itemCount: itemCount, 396 | controller: controller, 397 | scrollDirection: scrollDirection); 398 | 399 | @override 400 | State createState() { 401 | return new _CustomLayoutState(); 402 | } 403 | } 404 | 405 | class _CustomLayoutState extends _CustomLayoutStateBase<_CustomLayoutSwiper> { 406 | @override 407 | void didChangeDependencies() { 408 | super.didChangeDependencies(); 409 | _startIndex = widget.option.startIndex; 410 | _animationCount = widget.option.stateCount; 411 | } 412 | 413 | @override 414 | void didUpdateWidget(_CustomLayoutSwiper oldWidget) { 415 | _startIndex = widget.option.startIndex; 416 | _animationCount = widget.option.stateCount; 417 | super.didUpdateWidget(oldWidget); 418 | } 419 | 420 | @override 421 | Widget _buildItem(int index, int realIndex, double animationValue) { 422 | List builders = widget.option.builders; 423 | 424 | Widget child = new SizedBox( 425 | width: widget.itemWidth ?? double.infinity, 426 | height: widget.itemHeight ?? double.infinity, 427 | child: widget.itemBuilder(context, realIndex)); 428 | 429 | for (int i = builders.length - 1; i >= 0; --i) { 430 | TransformBuilder builder = builders[i]; 431 | child = builder.build(index, animationValue, child); 432 | } 433 | 434 | return child; 435 | } 436 | } 437 | -------------------------------------------------------------------------------- /lib/src/swiper_control.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_swiper/flutter_swiper.dart'; 3 | 4 | class SwiperControl extends SwiperPlugin { 5 | ///IconData for previous 6 | final IconData iconPrevious; 7 | 8 | ///iconData fopr next 9 | final IconData iconNext; 10 | 11 | ///icon size 12 | final double size; 13 | 14 | ///Icon normal color, The theme's [ThemeData.primaryColor] by default. 15 | final Color color; 16 | 17 | ///if set loop=false on Swiper, this color will be used when swiper goto the last slide. 18 | ///The theme's [ThemeData.disabledColor] by default. 19 | final Color disableColor; 20 | 21 | final EdgeInsetsGeometry padding; 22 | 23 | final Key key; 24 | 25 | const SwiperControl( 26 | {this.iconPrevious: Icons.arrow_back_ios, 27 | this.iconNext: Icons.arrow_forward_ios, 28 | this.color, 29 | this.disableColor, 30 | this.key, 31 | this.size: 30.0, 32 | this.padding: const EdgeInsets.all(5.0)}); 33 | 34 | Widget buildButton(SwiperPluginConfig config, Color color, IconData iconDaga, 35 | int quarterTurns, bool previous) { 36 | return new GestureDetector( 37 | behavior: HitTestBehavior.opaque, 38 | onTap: () { 39 | if (previous) { 40 | config.controller.previous(animation: true); 41 | } else { 42 | config.controller.next(animation: true); 43 | } 44 | }, 45 | child: Padding( 46 | padding: padding, 47 | child: RotatedBox( 48 | quarterTurns: quarterTurns, 49 | child: Icon( 50 | iconDaga, 51 | semanticLabel: previous ? "Previous" : "Next", 52 | size: size, 53 | color: color, 54 | ))), 55 | ); 56 | } 57 | 58 | @override 59 | Widget build(BuildContext context, SwiperPluginConfig config) { 60 | ThemeData themeData = Theme.of(context); 61 | 62 | Color color = this.color ?? themeData.primaryColor; 63 | Color disableColor = this.disableColor ?? themeData.disabledColor; 64 | Color prevColor; 65 | Color nextColor; 66 | 67 | if (config.loop) { 68 | prevColor = nextColor = color; 69 | } else { 70 | bool next = config.activeIndex < config.itemCount - 1; 71 | bool prev = config.activeIndex > 0; 72 | prevColor = prev ? color : disableColor; 73 | nextColor = next ? color : disableColor; 74 | } 75 | 76 | Widget child; 77 | if (config.scrollDirection == Axis.horizontal) { 78 | child = Row( 79 | key: key, 80 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 81 | children: [ 82 | buildButton(config, prevColor, iconPrevious, 0, true), 83 | buildButton(config, nextColor, iconNext, 0, false) 84 | ], 85 | ); 86 | } else { 87 | child = Column( 88 | key: key, 89 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 90 | children: [ 91 | buildButton(config, prevColor, iconPrevious, -3, true), 92 | buildButton(config, nextColor, iconNext, -3, false) 93 | ], 94 | ); 95 | } 96 | 97 | return new Container( 98 | height: double.infinity, 99 | child: child, 100 | width: double.infinity, 101 | ); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /lib/src/swiper_controller.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_swiper/src/swiper_plugin.dart'; 2 | import 'package:transformer_page_view/transformer_page_view.dart'; 3 | 4 | class SwiperController extends IndexController { 5 | // Autoplay is started 6 | static const int START_AUTOPLAY = 2; 7 | 8 | // Autoplay is stopped. 9 | static const int STOP_AUTOPLAY = 3; 10 | 11 | // Indicate that the user is swiping 12 | static const int SWIPE = 4; 13 | 14 | // Indicate that the `Swiper` has changed it's index and is building it's ui ,so that the 15 | // `SwiperPluginConfig` is available. 16 | static const int BUILD = 5; 17 | 18 | // available when `event` == SwiperController.BUILD 19 | SwiperPluginConfig config; 20 | 21 | // available when `event` == SwiperController.SWIPE 22 | // this value is PageViewController.pos 23 | double pos; 24 | 25 | int index; 26 | bool animation; 27 | bool autoplay; 28 | 29 | SwiperController(); 30 | 31 | void startAutoplay() { 32 | event = SwiperController.START_AUTOPLAY; 33 | this.autoplay = true; 34 | notifyListeners(); 35 | } 36 | 37 | void stopAutoplay() { 38 | event = SwiperController.STOP_AUTOPLAY; 39 | this.autoplay = false; 40 | notifyListeners(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /lib/src/swiper_pagination.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter/foundation.dart'; 3 | import 'package:flutter_swiper/flutter_swiper.dart'; 4 | 5 | import 'package:flutter_page_indicator/flutter_page_indicator.dart'; 6 | 7 | class FractionPaginationBuilder extends SwiperPlugin { 8 | ///color ,if set null , will be Theme.of(context).scaffoldBackgroundColor 9 | final Color color; 10 | 11 | ///color when active,if set null , will be Theme.of(context).primaryColor 12 | final Color activeColor; 13 | 14 | ////font size 15 | final double fontSize; 16 | 17 | ///font size when active 18 | final double activeFontSize; 19 | 20 | final Key key; 21 | 22 | const FractionPaginationBuilder( 23 | {this.color, 24 | this.fontSize: 20.0, 25 | this.key, 26 | this.activeColor, 27 | this.activeFontSize: 35.0}); 28 | 29 | @override 30 | Widget build(BuildContext context, SwiperPluginConfig config) { 31 | ThemeData themeData = Theme.of(context); 32 | Color activeColor = this.activeColor ?? themeData.primaryColor; 33 | Color color = this.color ?? themeData.scaffoldBackgroundColor; 34 | 35 | if (Axis.vertical == config.scrollDirection) { 36 | return new Column( 37 | key: key, 38 | mainAxisSize: MainAxisSize.min, 39 | children: [ 40 | new Text( 41 | "${config.activeIndex + 1}", 42 | style: TextStyle(color: activeColor, fontSize: activeFontSize), 43 | ), 44 | new Text( 45 | "/", 46 | style: TextStyle(color: color, fontSize: fontSize), 47 | ), 48 | new Text( 49 | "${config.itemCount}", 50 | style: TextStyle(color: color, fontSize: fontSize), 51 | ) 52 | ], 53 | ); 54 | } else { 55 | return new Row( 56 | key: key, 57 | mainAxisSize: MainAxisSize.min, 58 | children: [ 59 | new Text( 60 | "${config.activeIndex + 1}", 61 | style: TextStyle(color: activeColor, fontSize: activeFontSize), 62 | ), 63 | new Text( 64 | " / ${config.itemCount}", 65 | style: TextStyle(color: color, fontSize: fontSize), 66 | ) 67 | ], 68 | ); 69 | } 70 | } 71 | } 72 | 73 | class RectSwiperPaginationBuilder extends SwiperPlugin { 74 | ///color when current index,if set null , will be Theme.of(context).primaryColor 75 | final Color activeColor; 76 | 77 | ///,if set null , will be Theme.of(context).scaffoldBackgroundColor 78 | final Color color; 79 | 80 | ///Size of the rect when activate 81 | final Size activeSize; 82 | 83 | ///Size of the rect 84 | final Size size; 85 | 86 | /// Space between rects 87 | final double space; 88 | 89 | final Key key; 90 | 91 | const RectSwiperPaginationBuilder( 92 | {this.activeColor, 93 | this.color, 94 | this.key, 95 | this.size: const Size(10.0, 2.0), 96 | this.activeSize: const Size(10.0, 2.0), 97 | this.space: 3.0}); 98 | 99 | @override 100 | Widget build(BuildContext context, SwiperPluginConfig config) { 101 | ThemeData themeData = Theme.of(context); 102 | Color activeColor = this.activeColor ?? themeData.primaryColor; 103 | Color color = this.color ?? themeData.scaffoldBackgroundColor; 104 | 105 | List list = []; 106 | 107 | if (config.itemCount > 20) { 108 | print( 109 | "The itemCount is too big, we suggest use FractionPaginationBuilder instead of DotSwiperPaginationBuilder in this sitituation"); 110 | } 111 | 112 | int itemCount = config.itemCount; 113 | int activeIndex = config.activeIndex; 114 | 115 | for (int i = 0; i < itemCount; ++i) { 116 | bool active = i == activeIndex; 117 | Size size = active ? this.activeSize : this.size; 118 | list.add(SizedBox( 119 | width: size.width, 120 | height: size.height, 121 | child: Container( 122 | color: active ? activeColor : color, 123 | key: Key("pagination_$i"), 124 | margin: EdgeInsets.all(space), 125 | ), 126 | )); 127 | } 128 | 129 | if (config.scrollDirection == Axis.vertical) { 130 | return new Column( 131 | key: key, 132 | mainAxisSize: MainAxisSize.min, 133 | children: list, 134 | ); 135 | } else { 136 | return new Row( 137 | key: key, 138 | mainAxisSize: MainAxisSize.min, 139 | children: list, 140 | ); 141 | } 142 | } 143 | } 144 | 145 | class DotSwiperPaginationBuilder extends SwiperPlugin { 146 | ///color when current index,if set null , will be Theme.of(context).primaryColor 147 | final Color activeColor; 148 | 149 | ///,if set null , will be Theme.of(context).scaffoldBackgroundColor 150 | final Color color; 151 | 152 | ///Size of the dot when activate 153 | final double activeSize; 154 | 155 | ///Size of the dot 156 | final double size; 157 | 158 | /// Space between dots 159 | final double space; 160 | 161 | final Key key; 162 | 163 | const DotSwiperPaginationBuilder( 164 | {this.activeColor, 165 | this.color, 166 | this.key, 167 | this.size: 10.0, 168 | this.activeSize: 10.0, 169 | this.space: 3.0}); 170 | 171 | @override 172 | Widget build(BuildContext context, SwiperPluginConfig config) { 173 | if (config.itemCount > 20) { 174 | print( 175 | "The itemCount is too big, we suggest use FractionPaginationBuilder instead of DotSwiperPaginationBuilder in this sitituation"); 176 | } 177 | Color activeColor = this.activeColor; 178 | Color color = this.color; 179 | 180 | if (activeColor == null || color == null) { 181 | ThemeData themeData = Theme.of(context); 182 | activeColor = this.activeColor ?? themeData.primaryColor; 183 | color = this.color ?? themeData.scaffoldBackgroundColor; 184 | } 185 | 186 | if (config.indicatorLayout != PageIndicatorLayout.NONE && 187 | config.layout == SwiperLayout.DEFAULT) { 188 | return new PageIndicator( 189 | count: config.itemCount, 190 | controller: config.pageController, 191 | layout: config.indicatorLayout, 192 | size: size, 193 | activeColor: activeColor, 194 | color: color, 195 | space: space, 196 | ); 197 | } 198 | 199 | List list = []; 200 | 201 | int itemCount = config.itemCount; 202 | int activeIndex = config.activeIndex; 203 | 204 | for (int i = 0; i < itemCount; ++i) { 205 | bool active = i == activeIndex; 206 | list.add(Container( 207 | key: Key("pagination_$i"), 208 | margin: EdgeInsets.all(space), 209 | child: ClipOval( 210 | child: Container( 211 | color: active ? activeColor : color, 212 | width: active ? activeSize : size, 213 | height: active ? activeSize : size, 214 | ), 215 | ), 216 | )); 217 | } 218 | 219 | if (config.scrollDirection == Axis.vertical) { 220 | return new Column( 221 | key: key, 222 | mainAxisSize: MainAxisSize.min, 223 | children: list, 224 | ); 225 | } else { 226 | return new Row( 227 | key: key, 228 | mainAxisSize: MainAxisSize.min, 229 | children: list, 230 | ); 231 | } 232 | } 233 | } 234 | 235 | typedef Widget SwiperPaginationBuilder( 236 | BuildContext context, SwiperPluginConfig config); 237 | 238 | class SwiperCustomPagination extends SwiperPlugin { 239 | final SwiperPaginationBuilder builder; 240 | 241 | SwiperCustomPagination({@required this.builder}) : assert(builder != null); 242 | 243 | @override 244 | Widget build(BuildContext context, SwiperPluginConfig config) { 245 | return builder(context, config); 246 | } 247 | } 248 | 249 | class SwiperPagination extends SwiperPlugin { 250 | /// dot style pagination 251 | static const SwiperPlugin dots = const DotSwiperPaginationBuilder(); 252 | 253 | /// fraction style pagination 254 | static const SwiperPlugin fraction = const FractionPaginationBuilder(); 255 | 256 | static const SwiperPlugin rect = const RectSwiperPaginationBuilder(); 257 | 258 | /// Alignment.bottomCenter by default when scrollDirection== Axis.horizontal 259 | /// Alignment.centerRight by default when scrollDirection== Axis.vertical 260 | final Alignment alignment; 261 | 262 | /// Distance between pagination and the container 263 | final EdgeInsetsGeometry margin; 264 | 265 | /// Build the widet 266 | final SwiperPlugin builder; 267 | 268 | final Key key; 269 | 270 | const SwiperPagination( 271 | {this.alignment, 272 | this.key, 273 | this.margin: const EdgeInsets.all(10.0), 274 | this.builder: SwiperPagination.dots}); 275 | 276 | Widget build(BuildContext context, SwiperPluginConfig config) { 277 | Alignment alignment = this.alignment ?? 278 | (config.scrollDirection == Axis.horizontal 279 | ? Alignment.bottomCenter 280 | : Alignment.centerRight); 281 | Widget child = Container( 282 | margin: margin, 283 | child: this.builder.build(context, config), 284 | ); 285 | if (!config.outer) { 286 | child = new Align( 287 | key: key, 288 | alignment: alignment, 289 | child: child, 290 | ); 291 | } 292 | return child; 293 | } 294 | } 295 | -------------------------------------------------------------------------------- /lib/src/swiper_plugin.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/widgets.dart'; 2 | import 'package:flutter_page_indicator/flutter_page_indicator.dart'; 3 | import 'package:flutter_swiper/flutter_swiper.dart'; 4 | 5 | /// plugin to display swiper components 6 | /// 7 | abstract class SwiperPlugin { 8 | const SwiperPlugin(); 9 | 10 | Widget build(BuildContext context, SwiperPluginConfig config); 11 | } 12 | 13 | class SwiperPluginConfig { 14 | final int activeIndex; 15 | final int itemCount; 16 | final PageIndicatorLayout indicatorLayout; 17 | final Axis scrollDirection; 18 | final bool loop; 19 | final bool outer; 20 | final PageController pageController; 21 | final SwiperController controller; 22 | final SwiperLayout layout; 23 | 24 | const SwiperPluginConfig( 25 | {this.activeIndex, 26 | this.itemCount, 27 | this.indicatorLayout, 28 | this.outer, 29 | this.scrollDirection, 30 | this.controller, 31 | this.pageController, 32 | this.layout, 33 | this.loop}) 34 | : assert(scrollDirection != null), 35 | assert(controller != null); 36 | } 37 | 38 | class SwiperPluginView extends StatelessWidget { 39 | final SwiperPlugin plugin; 40 | final SwiperPluginConfig config; 41 | 42 | const SwiperPluginView(this.plugin, this.config); 43 | 44 | @override 45 | Widget build(BuildContext context) { 46 | return plugin.build(context, config); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://www.dartlang.org/tools/pub/glossary#lockfile 3 | packages: 4 | async: 5 | dependency: transitive 6 | description: 7 | name: async 8 | url: "https://pub.flutter-io.cn" 9 | source: hosted 10 | version: "2.0.8" 11 | boolean_selector: 12 | dependency: transitive 13 | description: 14 | name: boolean_selector 15 | url: "https://pub.flutter-io.cn" 16 | source: hosted 17 | version: "1.0.4" 18 | charcode: 19 | dependency: transitive 20 | description: 21 | name: charcode 22 | url: "https://pub.flutter-io.cn" 23 | source: hosted 24 | version: "1.1.2" 25 | collection: 26 | dependency: transitive 27 | description: 28 | name: collection 29 | url: "https://pub.flutter-io.cn" 30 | source: hosted 31 | version: "1.14.11" 32 | flutter: 33 | dependency: "direct main" 34 | description: flutter 35 | source: sdk 36 | version: "0.0.0" 37 | flutter_page_indicator: 38 | dependency: "direct main" 39 | description: 40 | name: flutter_page_indicator 41 | url: "https://pub.flutter-io.cn" 42 | source: hosted 43 | version: "0.0.3" 44 | flutter_test: 45 | dependency: "direct dev" 46 | description: flutter 47 | source: sdk 48 | version: "0.0.0" 49 | matcher: 50 | dependency: transitive 51 | description: 52 | name: matcher 53 | url: "https://pub.flutter-io.cn" 54 | source: hosted 55 | version: "0.12.3+1" 56 | meta: 57 | dependency: transitive 58 | description: 59 | name: meta 60 | url: "https://pub.flutter-io.cn" 61 | source: hosted 62 | version: "1.1.6" 63 | path: 64 | dependency: transitive 65 | description: 66 | name: path 67 | url: "https://pub.flutter-io.cn" 68 | source: hosted 69 | version: "1.6.2" 70 | quiver: 71 | dependency: transitive 72 | description: 73 | name: quiver 74 | url: "https://pub.flutter-io.cn" 75 | source: hosted 76 | version: "2.0.1" 77 | sky_engine: 78 | dependency: transitive 79 | description: flutter 80 | source: sdk 81 | version: "0.0.99" 82 | source_span: 83 | dependency: transitive 84 | description: 85 | name: source_span 86 | url: "https://pub.flutter-io.cn" 87 | source: hosted 88 | version: "1.4.1" 89 | stack_trace: 90 | dependency: transitive 91 | description: 92 | name: stack_trace 93 | url: "https://pub.flutter-io.cn" 94 | source: hosted 95 | version: "1.9.3" 96 | stream_channel: 97 | dependency: transitive 98 | description: 99 | name: stream_channel 100 | url: "https://pub.flutter-io.cn" 101 | source: hosted 102 | version: "1.6.8" 103 | string_scanner: 104 | dependency: transitive 105 | description: 106 | name: string_scanner 107 | url: "https://pub.flutter-io.cn" 108 | source: hosted 109 | version: "1.0.4" 110 | term_glyph: 111 | dependency: transitive 112 | description: 113 | name: term_glyph 114 | url: "https://pub.flutter-io.cn" 115 | source: hosted 116 | version: "1.0.1" 117 | test_api: 118 | dependency: transitive 119 | description: 120 | name: test_api 121 | url: "https://pub.flutter-io.cn" 122 | source: hosted 123 | version: "0.2.1" 124 | transformer_page_view: 125 | dependency: "direct main" 126 | description: 127 | name: transformer_page_view 128 | url: "https://pub.flutter-io.cn" 129 | source: hosted 130 | version: "0.1.5" 131 | typed_data: 132 | dependency: transitive 133 | description: 134 | name: typed_data 135 | url: "https://pub.flutter-io.cn" 136 | source: hosted 137 | version: "1.1.6" 138 | vector_math: 139 | dependency: transitive 140 | description: 141 | name: vector_math 142 | url: "https://pub.flutter-io.cn" 143 | source: hosted 144 | version: "2.0.8" 145 | sdks: 146 | dart: ">=2.0.0 <3.0.0" 147 | flutter: ">=0.1.4 <3.0.0" 148 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: flutter_swiper 2 | description: The best swiper(carousel) for flutter, with multiple layouts, infinite loop. Compatible with Android & iOS. 3 | version: 1.1.6 4 | author: JZoom 5 | homepage: https://github.com/jzoom/flutter_swiper 6 | 7 | dependencies: 8 | flutter: 9 | sdk: flutter 10 | 11 | transformer_page_view: ^0.1.6 12 | flutter_page_indicator: ^0.0.3 13 | 14 | environment: 15 | sdk: ">=2.0.0-dev.48.0 <3.0.0" 16 | flutter: ">=0.1.4 <3.0.0" 17 | 18 | dev_dependencies: 19 | flutter_test: 20 | sdk: flutter 21 | 22 | flutter: 23 | -------------------------------------------------------------------------------- /test/control_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_test/flutter_test.dart'; 3 | import 'package:flutter_swiper/flutter_swiper.dart'; 4 | 5 | void main() { 6 | testWidgets('Control horizontal', (WidgetTester tester) async { 7 | SwiperController controller = new SwiperController(); 8 | 9 | SwiperPluginConfig config = new SwiperPluginConfig( 10 | activeIndex: 0, 11 | controller: controller, 12 | itemCount: 10, 13 | loop: true, 14 | scrollDirection: Axis.horizontal); 15 | 16 | Key key = new UniqueKey(); 17 | await tester.pumpWidget(new MaterialApp( 18 | home: new Scaffold(body: new Builder(builder: (BuildContext context) { 19 | return new SwiperControl(key: key).build(context, config); 20 | })), 21 | )); 22 | 23 | expect(find.byKey(key), findsOneWidget); 24 | 25 | bool first = true; 26 | 27 | await tester.tap(find.byWidgetPredicate((Widget widget) { 28 | if (widget is GestureDetector && first) { 29 | first = false; 30 | return true; 31 | } 32 | 33 | return false; 34 | })); 35 | }); 36 | 37 | testWidgets('Control vertical', (WidgetTester tester) async { 38 | SwiperController controller = new SwiperController(); 39 | 40 | SwiperPluginConfig config = new SwiperPluginConfig( 41 | activeIndex: 0, 42 | controller: controller, 43 | itemCount: 10, 44 | loop: true, 45 | scrollDirection: Axis.vertical); 46 | 47 | Key key = new UniqueKey(); 48 | await tester.pumpWidget(new MaterialApp( 49 | home: new Scaffold(body: new Builder(builder: (BuildContext context) { 50 | return new SwiperControl( 51 | key: key, color: Colors.white, disableColor: Colors.black87) 52 | .build(context, config); 53 | })), 54 | )); 55 | 56 | expect(find.byKey(key), findsOneWidget); 57 | 58 | bool first = true; 59 | 60 | await tester.tap(find.byWidgetPredicate((Widget widget) { 61 | if (widget is GestureDetector && first) { 62 | first = false; 63 | return true; 64 | } 65 | 66 | return false; 67 | })); 68 | }); 69 | } 70 | -------------------------------------------------------------------------------- /test/flutter_swiper_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_test/flutter_test.dart'; 3 | import 'package:flutter_swiper/flutter_swiper.dart'; 4 | 5 | void main() { 6 | testWidgets('Default Swiper', (WidgetTester tester) async { 7 | // Build our app and trigger a frame. 8 | await tester.pumpWidget(MaterialApp( 9 | home: Swiper( 10 | itemBuilder: (context, index) { 11 | return Text("0"); 12 | }, 13 | itemCount: 10))); 14 | 15 | expect(find.text("0", skipOffstage: false), findsOneWidget); 16 | }); 17 | 18 | testWidgets('Default Swiper loop:false', (WidgetTester tester) async { 19 | // Build our app and trigger a frame. 20 | await tester.pumpWidget(MaterialApp( 21 | home: Swiper( 22 | onTap: (int inde) {}, 23 | itemBuilder: (context, index) { 24 | return Text("0"); 25 | }, 26 | itemCount: 10, 27 | loop: false, 28 | ))); 29 | 30 | expect(find.text("0", skipOffstage: true), findsOneWidget); 31 | }); 32 | 33 | testWidgets('Create Swiper with children', (WidgetTester tester) async { 34 | // Build our app and trigger a frame. 35 | await tester.pumpWidget(MaterialApp( 36 | home: Swiper.children( 37 | children: [Text("0"), Text("1")], 38 | ))); 39 | 40 | expect(find.text("0", skipOffstage: false), findsOneWidget); 41 | }); 42 | 43 | testWidgets('Create Swiper with list', (WidgetTester tester) async { 44 | // Build our app and trigger a frame. 45 | await tester.pumpWidget(MaterialApp( 46 | home: Swiper.list( 47 | list: ["0", "1"], 48 | builder: (BuildContext context, dynamic data, int index) { 49 | return Text(data); 50 | }, 51 | ))); 52 | 53 | expect(find.text("0", skipOffstage: false), findsOneWidget); 54 | }); 55 | 56 | testWidgets('Swiper with default plugins', (WidgetTester tester) async { 57 | // Build our app and trigger a frame. 58 | SwiperController controller = SwiperController(); 59 | await tester.pumpWidget(MaterialApp( 60 | home: Swiper( 61 | controller: controller, 62 | itemBuilder: (context, index) { 63 | return Text("0"); 64 | }, 65 | itemCount: 10, 66 | pagination: SwiperPagination(), 67 | control: SwiperControl(), 68 | ))); 69 | 70 | expect(find.text("0", skipOffstage: false), findsOneWidget); 71 | }); 72 | 73 | const List titles = [ 74 | "Flutter Swiper is awosome", 75 | "Really nice", 76 | "Yeap" 77 | ]; 78 | 79 | testWidgets('Customize pagination', (WidgetTester tester) async { 80 | // Build our app and trigger a frame. 81 | SwiperController controller = SwiperController(); 82 | await tester.pumpWidget(MaterialApp( 83 | home: Swiper( 84 | controller: controller, 85 | itemBuilder: (context, index) { 86 | return Text("0"); 87 | }, 88 | itemCount: 10, 89 | pagination: SwiperCustomPagination( 90 | builder: (BuildContext context, SwiperPluginConfig config) { 91 | return ConstrainedBox( 92 | child: Row( 93 | children: [ 94 | Text( 95 | "${titles[config.activeIndex]} ${config.activeIndex + 1}/${config.itemCount}", 96 | style: TextStyle(fontSize: 20.0), 97 | ), 98 | Expanded( 99 | child: Align( 100 | alignment: Alignment.centerRight, 101 | child: DotSwiperPaginationBuilder( 102 | color: Colors.black12, 103 | activeColor: Colors.black, 104 | size: 10.0, 105 | activeSize: 20.0) 106 | .build(context, config), 107 | ), 108 | ) 109 | ], 110 | ), 111 | constraints: BoxConstraints.expand(height: 50.0), 112 | ); 113 | }), 114 | control: SwiperControl(), 115 | ))); 116 | 117 | controller.startAutoplay(); 118 | 119 | controller.stopAutoplay(); 120 | 121 | await controller.move(0, animation: false); 122 | await controller.move(0, animation: false); 123 | 124 | await controller.next(animation: false); 125 | await controller.previous(animation: false); 126 | 127 | expect(find.text("0", skipOffstage: false), findsOneWidget); 128 | }); 129 | 130 | testWidgets('Swiper fraction', (WidgetTester tester) async { 131 | // Build our app and trigger a frame. 132 | SwiperController controller = SwiperController(); 133 | await tester.pumpWidget(MaterialApp( 134 | home: Swiper( 135 | controller: controller, 136 | itemBuilder: (context, index) { 137 | return Text("0"); 138 | }, 139 | itemCount: 10, 140 | pagination: SwiperPagination(builder: SwiperPagination.fraction), 141 | control: SwiperControl(), 142 | ))); 143 | 144 | expect(find.text("0", skipOffstage: false), findsOneWidget); 145 | }); 146 | 147 | testWidgets('Zero itemCount', (WidgetTester tester) async { 148 | // Build our app and trigger a frame. 149 | SwiperController controller = SwiperController(); 150 | await tester.pumpWidget(MaterialApp( 151 | home: Swiper( 152 | controller: controller, 153 | itemBuilder: (context, index) { 154 | return Text("0"); 155 | }, 156 | itemCount: 0, 157 | pagination: SwiperPagination(builder: SwiperPagination.fraction), 158 | control: SwiperControl(), 159 | ))); 160 | 161 | expect(find.text("0", skipOffstage: false), findsNothing); 162 | }); 163 | } 164 | -------------------------------------------------------------------------------- /test/layout_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_test/flutter_test.dart'; 3 | import 'package:flutter_swiper/flutter_swiper.dart'; 4 | 5 | void main() { 6 | testWidgets('STACK', (WidgetTester tester) async { 7 | await tester.pumpWidget(MaterialApp( 8 | home: Swiper( 9 | layout: SwiperLayout.STACK, 10 | itemWidth: 300.0, 11 | itemHeight: 200.0, 12 | itemBuilder: (context, index) { 13 | return new Container( 14 | color: Colors.grey, 15 | child: new Center( 16 | child: new Text("$index"), 17 | ), 18 | ); 19 | }, 20 | itemCount: 10))); 21 | }); 22 | 23 | testWidgets('TINDER', (WidgetTester tester) async { 24 | await tester.pumpWidget(MaterialApp( 25 | home: Swiper( 26 | layout: SwiperLayout.TINDER, 27 | itemWidth: 300.0, 28 | itemHeight: 200.0, 29 | itemBuilder: (context, index) { 30 | return new Container( 31 | color: Colors.grey, 32 | child: new Center( 33 | child: new Text("$index"), 34 | ), 35 | ); 36 | }, 37 | itemCount: 10))); 38 | }); 39 | 40 | testWidgets('DEFAULT', (WidgetTester tester) async { 41 | await tester.pumpWidget(MaterialApp( 42 | home: Swiper( 43 | layout: SwiperLayout.DEFAULT, 44 | viewportFraction: 0.8, 45 | scale: 0.9, 46 | itemBuilder: (context, index) { 47 | return new Container( 48 | color: Colors.grey, 49 | child: new Center( 50 | child: new Text("$index"), 51 | ), 52 | ); 53 | }, 54 | itemCount: 10))); 55 | }); 56 | 57 | testWidgets('CUSTOM', (WidgetTester tester) async { 58 | CustomLayoutOption customLayoutOption; 59 | customLayoutOption = new CustomLayoutOption(startIndex: -1, stateCount: 3) 60 | .addRotate([-45.0 / 180, 0.0, 45.0 / 180]).addTranslate([ 61 | new Offset(-370.0, -40.0), 62 | new Offset(0.0, 0.0), 63 | new Offset(370.0, -40.0) 64 | ]); 65 | await tester.pumpWidget(MaterialApp( 66 | home: Swiper( 67 | layout: SwiperLayout.CUSTOM, 68 | itemWidth: 300.0, 69 | itemHeight: 200.0, 70 | customLayoutOption: customLayoutOption, 71 | itemBuilder: (context, index) { 72 | return new Container( 73 | color: Colors.grey, 74 | child: new Center( 75 | child: new Text("$index"), 76 | ), 77 | ); 78 | }, 79 | itemCount: 10))); 80 | }); 81 | } 82 | -------------------------------------------------------------------------------- /test/pagination_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_test/flutter_test.dart'; 3 | import 'package:flutter_swiper/flutter_swiper.dart'; 4 | 5 | void main() { 6 | testWidgets('Pagination', (WidgetTester tester) async { 7 | SwiperController controller = new SwiperController(); 8 | 9 | SwiperPluginConfig config = new SwiperPluginConfig( 10 | activeIndex: 0, 11 | controller: controller, 12 | itemCount: 10, 13 | scrollDirection: Axis.horizontal); 14 | 15 | Key key = new UniqueKey(); 16 | await tester.pumpWidget(new MaterialApp( 17 | home: new Scaffold(body: new Builder(builder: (BuildContext context) { 18 | return new DotSwiperPaginationBuilder( 19 | key: key, 20 | activeColor: new Color(0xff000000), 21 | color: new Color(0xffffffff), 22 | space: 10.0, 23 | size: 10.0, 24 | activeSize: 20.0) 25 | .build(context, config); 26 | })), 27 | )); 28 | 29 | for (int i = 0; i < 10; ++i) { 30 | expect(find.byWidgetPredicate((Widget widget) { 31 | if (widget.key != null && 32 | widget.key is ValueKey && 33 | (widget.key as ValueKey).value == 'pagination_$i') return true; 34 | 35 | return false; 36 | }), findsOneWidget); 37 | } 38 | 39 | expect(find.byKey(key), findsOneWidget); 40 | }); 41 | 42 | testWidgets('Pagination vertical', (WidgetTester tester) async { 43 | SwiperController controller = new SwiperController(); 44 | 45 | SwiperPluginConfig config = new SwiperPluginConfig( 46 | activeIndex: 0, 47 | controller: controller, 48 | itemCount: 10, 49 | scrollDirection: Axis.vertical); 50 | 51 | Key key = new UniqueKey(); 52 | await tester.pumpWidget(new MaterialApp( 53 | home: new Scaffold(body: new Builder(builder: (BuildContext context) { 54 | return new DotSwiperPaginationBuilder( 55 | key: key, 56 | activeColor: new Color(0xff000000), 57 | color: new Color(0xffffffff), 58 | space: 10.0, 59 | size: 10.0, 60 | activeSize: 20.0) 61 | .build(context, config); 62 | })), 63 | )); 64 | 65 | for (int i = 0; i < 10; ++i) { 66 | expect(find.byWidgetPredicate((Widget widget) { 67 | if (widget.key != null && 68 | widget.key is ValueKey && 69 | (widget.key as ValueKey).value == 'pagination_$i') return true; 70 | 71 | return false; 72 | }), findsOneWidget); 73 | } 74 | 75 | expect(find.byKey(key), findsOneWidget); 76 | }); 77 | 78 | testWidgets('Pagination fraction', (WidgetTester tester) async { 79 | SwiperController controller = new SwiperController(); 80 | 81 | SwiperPluginConfig config = new SwiperPluginConfig( 82 | activeIndex: 0, 83 | controller: controller, 84 | itemCount: 10, 85 | scrollDirection: Axis.horizontal); 86 | 87 | Key key = new UniqueKey(); 88 | await tester.pumpWidget(new MaterialApp( 89 | home: new Scaffold(body: new Builder(builder: (BuildContext context) { 90 | return new FractionPaginationBuilder( 91 | key: key, 92 | activeColor: new Color(0xff000000), 93 | color: new Color(0xffffffff), 94 | ).build(context, config); 95 | })), 96 | )); 97 | 98 | expect(find.text("1"), findsOneWidget); 99 | expect(find.text(" / 10"), findsOneWidget); 100 | 101 | expect(find.byKey(key), findsOneWidget); 102 | }); 103 | 104 | testWidgets('Pagination fraction vertical', (WidgetTester tester) async { 105 | SwiperController controller = new SwiperController(); 106 | 107 | SwiperPluginConfig config = new SwiperPluginConfig( 108 | activeIndex: 0, 109 | controller: controller, 110 | itemCount: 10, 111 | scrollDirection: Axis.vertical); 112 | 113 | Key key = new UniqueKey(); 114 | await tester.pumpWidget(new MaterialApp( 115 | home: new Scaffold(body: new Builder(builder: (BuildContext context) { 116 | return new FractionPaginationBuilder( 117 | key: key, 118 | activeColor: new Color(0xff000000), 119 | color: new Color(0xffffffff), 120 | ).build(context, config); 121 | })), 122 | )); 123 | 124 | expect(find.text("1"), findsOneWidget); 125 | expect(find.text("10"), findsOneWidget); 126 | 127 | expect(find.byKey(key), findsOneWidget); 128 | }); 129 | } 130 | --------------------------------------------------------------------------------