Rodinei Fagundes

Merge branch 'master' of github.com:jamesblasco/modal_bottom_sheet

Showing 52 changed files with 809 additions and 164 deletions
name: Flutter Web
on:
push:
branches:
- master
jobs:
build:
name: Build Web
env:
my_secret: ${{secrets.commit_secret}}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: subosito/flutter-action@v1
with:
channel: 'dev'
- run: |
cd example
flutter config --enable-web
flutter pub get
- run: |
cd example
flutter build web --release --dart-define=FLUTTER_WEB_USE_SKIA=true
- run: |
cd example/build/web
git init
git config --global user.email git@jaimeblasco.com
git config --global user.name jamesblasco
git status
git remote add origin https://${{secrets.commit_secret}}@github.com/jamesblasco/modal_bottom_sheet.git
git checkout -b gh-pages
git add --all
git commit -m "Update web"
git push origin gh-pages -f
... ...
... ... @@ -2,4 +2,9 @@
## [0.1.0] - Package Release.
## [0.1.4] - Clean code and fix small bugs
## [0.1.5] - Scroll improvements and bug fixes
- Support for closing a modal with a scroll view by dragging down fast.
- Fix assertion in CupertinoBottomSheet and BottomSheetRoute when using the CupetinoApp or WidgetsApp as root
- Fix assertion when scrollController isn't used by the builder
\ No newline at end of file
... ...
TODO: Add your license here.
MIT License
Copyright (c) 2020 Jaime Blasco
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
... ...
<img src="https://github.com/jamesblasco/modal_bottom_sheet/blob/master/screenshots/preview.png?raw=true">
<a href="https://jamesblasco.github.io/modal_bottom_sheet/#/"><img src="https://github.com/jamesblasco/modal_bottom_sheet/blob/master/screenshots/preview.png?raw=true"></a>
# Flutter Modal Bottom Sheet
Create awesome and powerful modal bottom sheets
Create awesome and powerful modal bottom sheets.
| Cupertino Modal | Multiple Modals | Material Modal | Bar Modal | Create your own |
|---|---|---|---|---|
|<img height="300" src="https://github.com/jamesblasco/modal_bottom_sheet/blob/master/screenshots/cupertino_shared_view.gif?raw=true">| <img height="300" src="https://github.com/jamesblasco/modal_bottom_sheet/blob/master/screenshots/modal_inside_modal.gif?raw=true">| <img height="300" src="https://github.com/jamesblasco/modal_bottom_sheet/blob/master/screenshots/material_fit.png?raw=true">|<img height="300" src="https://github.com/jamesblasco/modal_bottom_sheet/blob/master/screenshots/bar_modal.png?raw=true">| <img height="300" src="https://github.com/jamesblasco/modal_bottom_sheet/blob/master/screenshots/avatar_modal.png?raw=true">|
## Try it
Explore the [Web Demo](https://jamesblasco.github.io/modal_bottom_sheet/#/) or clone the repository.
Known problems on web demo:
- Web demo can run very slow on mobile devides.
- Fake status bar doesn't change color as the iOS, Android app
## First Steps
How to install it? [Follow Instructions](
... ... @@ -19,11 +30,13 @@ https://pub.dev/packages/modal_bottom_sheet#-installing-tab-)
showMaterialModalBottomSheet(
context: context,
builder: (context, scrollController) => Container(),
})
)
```
What to use this over flutter `showModalBottomSheet`?
`showMaterialModalBottomSheet` supports closing bottoms sheets by dragging down even if there is a scrollview inside.
`showModalBottomSheet` won't work correctly with scrollviews
`showModalBottomSheet` won't work correctly with scrollviews.
Also it supports `WillPopScope` to prevent closing the dialog
#### Generic params for all modal bottom sheets
... ... @@ -35,7 +48,7 @@ What to use this over flutter `showModalBottomSheet`?
|Color barrierColor | The `barrierColor` parameter controls the color of the scrim for this route |
|bool enableDrag = true| The `enableDrag` parameter specifies whether the bottom sheet can be dragged up and down and dismissed by swiping downwards. |
|AnimationController secondAnimation| The `secondAnimation` parameter allows you to provide an animation controller that will be used to animate push/pop of the modal route. Using this param is advised against and will be probably removed in future versions |
|bool bounce = false| The `enableDrag` parameter specifies if the bottom sheet can go beyond the top boundary while dragging |
|bool bounce = false| The `bounce` parameter specifies if the bottom sheet can go beyond the top boundary while dragging |
#### Material params
... ... @@ -51,7 +64,7 @@ iOS 13 came with an amazing new modal navigation and now it is available to use
showCupertinoModalBottomSheet(
context: context,
builder: (context, scrollController) => Container(),
})
)
```
See generic paramameter in the Material section above
... ... @@ -73,7 +86,10 @@ Notice this route type behaves the same as `MaterialPageRoute` and supports cust
How can I change my route class? See cases:
<details><summary> 1. Using Navigator.of(context).push </summary>
<details><summary> 1.
Using `Navigator.of(context).push`
</summary>
```dart
Navigator.of(context).push(MaterialPageRoute(builder: (context) => Container()));`
... ... @@ -85,8 +101,8 @@ Navigator.of(context).push(MaterialPageRoute(builder: (context) => Container()))
</details>
<details><summary>
2.
<details><summary>2.
Using `onGenerateRoute` parameter of `MaterialApp`, `CupertinoApp` or `Navigator`
</summary>
... ... @@ -106,8 +122,8 @@ Navigator.of(context).push(MaterialPageRoute(builder: (context) => Container()))
</details>
<details><summary>
3.
<details><summary> 3.
Using `pageRouteBuilder` parameter of `WidgetApp`
</summary>
... ... @@ -118,13 +134,13 @@ pageRouteBuilder: <T>(RouteSettings settings, WidgetBuilder builder) => Material
</details>
<details>
<summary>
4.
<summary>4.
Using `routes` parameter from `MaterialApp` or `CupertinoApp`
</summary>
Unfortunately this routes are `MaterialPageRoute` and `CupertinoPageRoute` respectively and cannot be changes.
You can change the way you call the previous route with one of the previous methods or try option 2
Unfortunately this parameter uses `MaterialPageRoute` and `CupertinoPageRoute` respectively and cannot be changed.
You can modify the way you call the previous route with one of the previous methods or try option 2
</details>
... ... @@ -173,7 +189,7 @@ Check in the example project `showAvatarModalBottomSheet` for how to create your
## Roadmap
- [ ] Support closing by dragging fast on a modal with a scroll view.
- [X] Support closing by dragging fast on a modal with a scroll view.
- [ ] Improve animation curves when user is not dragging.
... ...
include: package:pedantic/analysis_options.yaml
enable-experiment:
- extension-methods
\ No newline at end of file
... ...
enable-experiment:
- extension-methods
\ No newline at end of file
... ...
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig"
... ...
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.xcconfig"
... ...
# Uncomment this line to define a global platform for your project
# platform :ios, '9.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
project 'Runner', {
'Debug' => :debug,
'Profile' => :release,
'Release' => :release,
}
def parse_KV_file(file, separator='=')
file_abs_path = File.expand_path(file)
if !File.exists? file_abs_path
return [];
end
generated_key_values = {}
skip_line_start_symbols = ["#", "/"]
File.foreach(file_abs_path) do |line|
next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ }
plugin = line.split(pattern=separator)
if plugin.length == 2
podname = plugin[0].strip()
path = plugin[1].strip()
podpath = File.expand_path("#{path}", file_abs_path)
generated_key_values[podname] = podpath
else
puts "Invalid plugin specification: #{line}"
end
end
generated_key_values
end
target 'Runner' do
use_frameworks!
use_modular_headers!
# Flutter Pod
copied_flutter_dir = File.join(__dir__, 'Flutter')
copied_framework_path = File.join(copied_flutter_dir, 'Flutter.framework')
copied_podspec_path = File.join(copied_flutter_dir, 'Flutter.podspec')
unless File.exist?(copied_framework_path) && File.exist?(copied_podspec_path)
# Copy Flutter.framework and Flutter.podspec to Flutter/ to have something to link against if the xcode backend script has not run yet.
# That script will copy the correct debug/profile/release version of the framework based on the currently selected Xcode configuration.
# CocoaPods will not embed the framework on pod install (before any build phases can generate) if the dylib does not exist.
generated_xcode_build_settings_path = File.join(copied_flutter_dir, 'Generated.xcconfig')
unless File.exist?(generated_xcode_build_settings_path)
raise "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first"
end
generated_xcode_build_settings = parse_KV_file(generated_xcode_build_settings_path)
cached_framework_dir = generated_xcode_build_settings['FLUTTER_FRAMEWORK_DIR'];
unless File.exist?(copied_framework_path)
FileUtils.cp_r(File.join(cached_framework_dir, 'Flutter.framework'), copied_flutter_dir)
end
unless File.exist?(copied_podspec_path)
FileUtils.cp(File.join(cached_framework_dir, 'Flutter.podspec'), copied_flutter_dir)
end
end
# Keep pod path relative so it can be checked into Podfile.lock.
pod 'Flutter', :path => 'Flutter'
# Plugin Pods
# Prepare symlinks folder. We use symlinks to avoid having Podfile.lock
# referring to absolute paths on developers' machines.
system('rm -rf .symlinks')
system('mkdir -p .symlinks/plugins')
plugin_pods = parse_KV_file('../.flutter-plugins')
plugin_pods.each do |name, path|
symlink = File.join('.symlinks', 'plugins', name)
File.symlink(path, symlink)
pod name, :path => File.join(symlink, 'ios')
end
end
# Prevent Cocoapods from embedding a second Flutter framework and causing an error with the new Xcode build system.
install! 'cocoapods', :disable_input_output_paths => true
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['ENABLE_BITCODE'] = 'NO'
end
end
end
... ...
PODS:
- Flutter (1.0.0)
- url_launcher (0.0.1):
- Flutter
- url_launcher_macos (0.0.1):
- Flutter
- url_launcher_web (0.0.1):
- Flutter
DEPENDENCIES:
- Flutter (from `Flutter`)
- url_launcher (from `.symlinks/plugins/url_launcher/ios`)
- url_launcher_macos (from `.symlinks/plugins/url_launcher_macos/ios`)
- url_launcher_web (from `.symlinks/plugins/url_launcher_web/ios`)
EXTERNAL SOURCES:
Flutter:
:path: Flutter
url_launcher:
:path: ".symlinks/plugins/url_launcher/ios"
url_launcher_macos:
:path: ".symlinks/plugins/url_launcher_macos/ios"
url_launcher_web:
:path: ".symlinks/plugins/url_launcher_web/ios"
SPEC CHECKSUMS:
Flutter: 0e3d915762c693b495b44d77113d4970485de6ec
url_launcher: a1c0cc845906122c4784c542523d8cacbded5626
url_launcher_macos: fd7894421cd39320dce5f292fc99ea9270b2a313
url_launcher_web: e5527357f037c87560776e36436bf2b0288b965c
PODFILE CHECKSUM: 1b66dae606f75376c5f2135a8290850eeb09ae83
COCOAPODS: 1.8.4
... ...
... ... @@ -8,8 +8,13 @@
/* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
212D1E304840672EFB9BFFA7 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8D52A2E75CF34C7E6DC549F4 /* Pods_Runner.framework */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; };
3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; };
9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
... ... @@ -22,6 +27,8 @@
dstPath = "";
dstSubfolderSpec = 10;
files = (
3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */,
9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
... ... @@ -31,17 +38,23 @@
/* Begin PBXFileReference section */
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
248080BB287D735D5E630360 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = "<group>"; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
8D52A2E75CF34C7E6DC549F4 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = "<group>"; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
B3E04C271E591BD1327CA5FF /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
BAB1D322E537D55B4325D2C3 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
... ... @@ -49,16 +62,32 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */,
3B80C3941E831B6300D905FE /* App.framework in Frameworks */,
212D1E304840672EFB9BFFA7 /* Pods_Runner.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
7FA2A098790C5377E18FABC1 /* Pods */ = {
isa = PBXGroup;
children = (
BAB1D322E537D55B4325D2C3 /* Pods-Runner.debug.xcconfig */,
B3E04C271E591BD1327CA5FF /* Pods-Runner.release.xcconfig */,
248080BB287D735D5E630360 /* Pods-Runner.profile.xcconfig */,
);
name = Pods;
path = Pods;
sourceTree = "<group>";
};
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
3B80C3931E831B6300D905FE /* App.framework */,
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
9740EEBA1CF902C7004384FC /* Flutter.framework */,
9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
9740EEB31CF90195004384FC /* Generated.xcconfig */,
... ... @@ -72,6 +101,8 @@
9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */,
7FA2A098790C5377E18FABC1 /* Pods */,
9D90B19A7E12B9186516773E /* Frameworks */,
);
sourceTree = "<group>";
};
... ... @@ -106,6 +137,14 @@
name = "Supporting Files";
sourceTree = "<group>";
};
9D90B19A7E12B9186516773E /* Frameworks */ = {
isa = PBXGroup;
children = (
8D52A2E75CF34C7E6DC549F4 /* Pods_Runner.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
... ... @@ -113,12 +152,14 @@
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
00BBBB875F21B7EBEF944E13 /* [CP] Check Pods Manifest.lock */,
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
87338F8232AE1406F5B9308C /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
... ... @@ -136,7 +177,7 @@
isa = PBXProject;
attributes = {
LastUpgradeCheck = 1020;
ORGANIZATIONNAME = "";
ORGANIZATIONNAME = "The Chromium Authors";
TargetAttributes = {
97C146ED1CF9000F007C117D = {
CreatedOnToolsVersion = 7.3.1;
... ... @@ -145,7 +186,7 @@
};
};
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
compatibilityVersion = "Xcode 9.3";
compatibilityVersion = "Xcode 3.2";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
... ... @@ -177,6 +218,28 @@
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
00BBBB875F21B7EBEF944E13 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
... ... @@ -189,7 +252,22 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin";
};
87338F8232AE1406F5B9308C /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
... ...
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreviewsEnabled</key>
<false/>
</dict>
</plist>
... ... @@ -4,4 +4,7 @@
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace>
... ...
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreviewsEnabled</key>
<false/>
</dict>
</plist>
#import "GeneratedPluginRegistrant.h"
#import "GeneratedPluginRegistrant.h"
\ No newline at end of file
... ...
import 'dart:ui';
import 'package:example/examples/sliver_container.dart';
import 'package:example/modals/modal_fit.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:modal_bottom_sheet/modal_bottom_sheet.dart';
... ... @@ -14,11 +12,10 @@ class CupertinoSharePage extends StatelessWidget {
appBar: appBar(context),
body: CupertinoPageScaffold(
child: Center(
child: Hero(
tag: 'image',
child: Image.network(
'https://images.unsplash.com/photo-1586042062881-03688ce69774')),
),
child: Hero(
tag: 'image',
child: Image.asset('assets/demo_image.jpeg'),
)),
),
bottomNavigationBar: bottomAppBar(context));
}
... ... @@ -116,22 +113,20 @@ class PhotoShareBottomSheet extends StatelessWidget {
borderRadius: BorderRadius.circular(12),
child: Hero(
tag: 'image',
child: Image.network(
'https://images.unsplash.com/photo-1586042062881-03688ce69774'),
child:
Image.asset('assets/demo_image.jpeg'),
))),
Padding(
padding: EdgeInsets.symmetric(horizontal: 6),
child: ClipRRect(
borderRadius: BorderRadius.circular(12),
child: Image.network(
'https://images.unsplash.com/photo-1586042062881-03688ce69774'),
child: Image.asset('assets/demo_image.jpeg'),
)),
Padding(
padding: EdgeInsets.symmetric(horizontal: 6),
child: ClipRRect(
borderRadius: BorderRadius.circular(12),
child: Image.network(
'https://images.unsplash.com/photo-1586042062881-03688ce69774'),
child: Image.asset('assets/demo_image.jpeg'),
)),
],
),
... ... @@ -166,8 +161,7 @@ class PhotoShareBottomSheet extends StatelessWidget {
width: 60,
decoration: BoxDecoration(
image: DecorationImage(
image:
NetworkImage(app.imageUrl),
image: AssetImage(app.imageUrl),
fit: BoxFit.cover),
color: Colors.white,
borderRadius:
... ... @@ -292,7 +286,7 @@ class PhotoShareBottomSheet extends StatelessWidget {
children: <Widget>[
Material(
child: CircleAvatar(
backgroundImage: NetworkImage(
backgroundImage: AssetImage(
person.imageUrl,
),
radius: 30,
... ... @@ -338,8 +332,8 @@ class PhotoShareBottomSheet extends StatelessWidget {
SizedBox(width: 18),
ClipRRect(
borderRadius: BorderRadius.circular(4),
child: Image.network(
'https://images.unsplash.com/photo-1586042062881-03688ce69774',
child: Image.asset(
'assets/demo_image.jpeg',
fit: BoxFit.cover,
height: 40,
width: 40,
... ... @@ -422,31 +416,24 @@ class Item {
}
final people = [
Item('MacBook Pro',
'https://www.uoduckstore.com/TDS%20Product%20Images/Apple%20MacBook%20Pro%2016%20w%20T%20Bar%20Late%202019_1.jpg'),
Item('Jaime Blasco',
'https://media-exp1.licdn.com/dms/image/C5603AQGfIMBxWBRMSg/profile-displayphoto-shrink_200_200/0?e=1591833600&v=beta&t=r6xnd4oBDfb3A3IcsgliyrT_avYaeBEwRr9XtlizWq8'),
Item('Mya Johnston',
'https://images.unsplash.com/photo-1520813792240-56fc4a3765a7'),
Item('MacBook Pro', 'assets/MacBook.jpg'),
Item('Jaime Blasco', 'assets/jaimeblasco.jpeg'),
Item('Mya Johnston', 'assets/person1.jpeg'),
// https://images.unsplash.com/photo-1520813792240-56fc4a3765a7'
Item('Maxime Nicholls',
'https://images.unsplash.com/photo-1520719627573-5e2c1a6610f0'),
'assets/person4.jpeg'), //https://images.unsplash.com/photo-1568707043650-eb03f2536825'
Item('Susanna Thorne',
'https://images.unsplash.com/photo-1568707043650-eb03f2536825'),
Item('Jarod Aguilar',
'https://images.unsplash.com/photo-1547106634-56dcd53ae883')
'assets/person2.jpeg'), //https://images.unsplash.com/photo-1520719627573-5e2c1a6610f0
Item('Jarod Aguilar', 'assets/person3.jpeg')
//https://images.unsplash.com/photo-1547106634-56dcd53ae883
];
final apps = [
Item('Messages',
'https://upload.wikimedia.org/wikipedia/commons/thumb/5/51/IMessage_logo.svg/1200px-IMessage_logo.svg.png'),
Item('Github',
'https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png'),
Item('Slack',
'https://is3-ssl.mzstatic.com/image/thumb/Purple113/v4/6e/80/06/6e80063f-e5c8-3f20-d8d5-22dd0740f5ba/AppIcon-0-0-1x_U007emarketing-0-0-0-7-0-0-sRGB-0-0-0-GLES2_U002c0-512MB-85-220-0-0.png/246x0w.png'),
Item('Twitter',
'https://cfcdnpull-creativefreedoml.netdna-ssl.com/wp-content/uploads/2015/06/Twitter-bird-white-blue2.png'),
Item('Mail',
'https://upload.wikimedia.org/wikipedia/commons/thumb/4/4e/Mail_%28iOS%29.svg/1200px-Mail_%28iOS%29.svg.png'),
Item('Messages', 'assets/message.png'),
Item('Github', 'assets/github_app.png'),
Item('Slack', 'assets/slack.png'),
Item('Twitter', 'assets/twitter.png'),
Item('Mail', 'assets/mail.png'),
];
final actions = [
... ...
... ... @@ -69,6 +69,7 @@ class _SliverGroupElement extends RenderObjectElement {
if (child == _backgroundDecoration) _backgroundDecoration = null;
if (child == _foregroundDecoration) _foregroundDecoration = null;
if (child == _sliver) _sliver = null;
super.forgetChild(child);
}
@override
... ...
import 'package:example/modals/circular_modal.dart';
import 'package:example/web_frame.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:modal_bottom_sheet/modal_bottom_sheet.dart';
import 'modals/floating_modal.dart';
import 'modals/modal_complex_all.dart';
import 'modals/modal_fit.dart';
import 'modals/modal_inside_modal.dart';
import 'modals/modal_inside_modal.dart';
import 'modals/modal_simple.dart';
import 'modals/modal_will_scope.dart';
import 'modals/modal_with_navigator.dart';
import 'modals/modal_with_scroll.dart';
... ... @@ -21,6 +21,11 @@ class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
title: 'BottomSheet Modals',
builder: (context, child) => WebFrame(
child: child,
),
onGenerateRoute: (RouteSettings settings) {
switch (settings.name) {
case '/':
... ... @@ -35,6 +40,7 @@ class MyApp extends StatelessWidget {
builder: (context) => CupertinoPageScaffold(
backgroundColor: Colors.white,
navigationBar: CupertinoNavigationBar(
transitionBetweenRoutes: false,
middle: Text('Normal Navigation Presentation'),
trailing: GestureDetector(
child: Icon(Icons.arrow_upward),
... ... @@ -94,6 +100,7 @@ class _MyHomePageState extends State<MyHomePage> {
child: CupertinoPageScaffold(
backgroundColor: Colors.white,
navigationBar: CupertinoNavigationBar(
transitionBetweenRoutes: false,
middle: Text('iOS13 Modal Presentation'),
trailing: GestureDetector(
child: Icon(Icons.arrow_forward),
... ... @@ -142,6 +149,13 @@ class _MyHomePageState extends State<MyHomePage> {
scrollController: scrollController),
)),
ListTile(
title: Text('Float Modal'),
onTap: () => showFloatingModalBottomSheet(
context: context,
builder: (context, scrollController) =>
ModalFit(scrollController: scrollController),
)),
ListTile(
title: Text('Cupertino Modal fit'),
onTap: () => showCupertinoModalBottomSheet(
expand: false,
... ... @@ -151,7 +165,7 @@ class _MyHomePageState extends State<MyHomePage> {
ModalFit(scrollController: scrollController),
)),
ListTile(
title: Text('Cupertino Small Modal forzed to expand'),
title: Text('Cupertino Small Modal forced to expand'),
onTap: () => showCupertinoModalBottomSheet(
expand: true,
context: context,
... ... @@ -170,7 +184,18 @@ class _MyHomePageState extends State<MyHomePage> {
scrollController: scrollController),
)),
ListTile(
title: Text('Cupertino Navigator + Scroll + WillScope'),
title: Text('Cupertino Modal with inside navigation'),
onTap: () => showCupertinoModalBottomSheet(
expand: true,
context: context,
backgroundColor: Colors.transparent,
builder: (context, scrollController) =>
ModalWithNavigator(
scrollController: scrollController),
)),
ListTile(
title:
Text('Cupertino Navigator + Scroll + WillPopScope'),
onTap: () => showCupertinoModalBottomSheet(
expand: true,
context: context,
... ... @@ -180,7 +205,7 @@ class _MyHomePageState extends State<MyHomePage> {
scrollController: scrollController),
)),
ListTile(
title: Text('Cupertino Modal with WillScope'),
title: Text('Cupertino Modal with WillPopScope'),
onTap: () => showCupertinoModalBottomSheet(
expand: true,
context: context,
... ...
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:modal_bottom_sheet/modal_bottom_sheet.dart';
class FloatingModal extends StatelessWidget {
final Widget child;
final Color backgroundColor;
const FloatingModal({Key key, this.child, this.backgroundColor})
: super(key: key);
@override
Widget build(BuildContext context) {
return SafeArea(
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 20),
child: Material(
color: backgroundColor,
clipBehavior: Clip.antiAlias,
borderRadius: BorderRadius.circular(12),
child: child,
),
),
);
}
}
Future<T> showFloatingModalBottomSheet<T>({
@required BuildContext context,
@required ScrollWidgetBuilder builder,
Color backgroundColor,
}) async {
final result = await showCustomModalBottomSheet(
context: context,
builder: builder,
containerWidget: (_, animation, child) => FloatingModal(
child: child,
),
expand: false);
return result;
}
... ...
... ... @@ -2,8 +2,6 @@ import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:modal_bottom_sheet/modal_bottom_sheet.dart';
import 'modal_with_scroll.dart';
class ModalInsideModal extends StatelessWidget {
final ScrollController scrollController;
... ...
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:url_launcher/url_launcher.dart';
class WebFrame extends StatelessWidget {
final Widget child;
const WebFrame({Key key, this.child}) : super(key: key);
@override
Widget build(BuildContext context) {
if (kIsWeb && MediaQuery.of(context).size.width > 600) {
final date = DateTime.now();
final MediaQueryData mediaQuery = MediaQueryData(
size: Size(414, 896),
padding: EdgeInsets.only(
top: 44,
bottom: 34,
),
devicePixelRatio: 2,
);
return Material(
child: Padding(
padding: EdgeInsets.all(60),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Flexible(
flex: 2,
key: Key('Preview'),
child: FittedBox(
fit: BoxFit.contain,
child: Builder(builder: (context) {
final device = MediaQuery(
data: mediaQuery,
child: Container(
width: mediaQuery.size.width,
height: mediaQuery.size.height,
alignment: Alignment.center,
child: Stack(
fit: StackFit.expand,
children: <Widget>[
child,
Positioned(
top: 0,
left: 0,
right: 0,
height: 44,
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: <Widget>[
Padding(
padding:
EdgeInsets.only(left: 30, top: 4),
child: Text(
'${date.hour}:${date.minute}',
style: TextStyle(
fontWeight: FontWeight.bold),
)),
Padding(
padding: EdgeInsets.only(right: 18),
child: Row(
children: <Widget>[
Icon(
Icons.signal_cellular_4_bar,
size: 14,
),
SizedBox(width: 4),
Icon(Icons.wifi, size: 16),
SizedBox(width: 4),
Icon(
CupertinoIcons.battery_charging,
size: 20)
],
))
],
),
),
Align(
alignment: Alignment.bottomCenter,
child: Container(
margin: EdgeInsets.only(bottom: 8),
height: 4,
width: 140,
decoration: BoxDecoration(
color: Colors.black,
borderRadius: BorderRadius.circular(4)),
),
)
],
)),
);
return Container(
child: ClipRRect(
clipBehavior: Clip.antiAlias,
borderRadius: BorderRadius.circular(38.5),
child: device),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(50),
border: Border.all(color: Colors.black, width: 12)),
);
}),
),
),
SizedBox(width: 80),
Flexible(
flex: 1,
child: FittedBox(
fit: BoxFit.scaleDown,
child: Container(
padding: EdgeInsets.only(bottom: 40),
width: mediaQuery.size.width,
height: mediaQuery.size.height,
alignment: Alignment.center,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Expanded(
child: Text(
'Modal\nBottom\nSheet',
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 80,
),
maxLines: 3,
overflow: TextOverflow.clip,
)),
Spacer(),
Row(
children: <Widget>[
InkWell(
onTap: () => launch(
'https://pub.dev/packages/modal_bottom_sheet'),
child: Image.asset('assets/flutter.png',
height: 60),
),
Spacer(),
InkWell(
onTap: () => launch(
'https://github.com/jamesblasco/modal_bottom_sheet'),
child: Image.asset('assets/github.png',
height: 60),
),
],
)
],
))))
],
),
),
);
} else {
return child;
}
}
}
... ...
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "ephemeral/Flutter-Generated.xcconfig"
... ...
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "ephemeral/Flutter-Generated.xcconfig"
... ...
... ... @@ -5,6 +5,8 @@
import FlutterMacOS
import Foundation
import url_launcher_macos
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
}
... ...
platform :osx, '10.11'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
project 'Runner', {
'Debug' => :debug,
'Profile' => :release,
'Release' => :release,
}
def parse_KV_file(file, separator='=')
file_abs_path = File.expand_path(file)
if !File.exists? file_abs_path
return [];
end
pods_ary = []
skip_line_start_symbols = ["#", "/"]
File.foreach(file_abs_path) { |line|
next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ }
plugin = line.split(pattern=separator)
if plugin.length == 2
podname = plugin[0].strip()
path = plugin[1].strip()
podpath = File.expand_path("#{path}", file_abs_path)
pods_ary.push({:name => podname, :path => podpath});
else
puts "Invalid plugin specification: #{line}"
end
}
return pods_ary
end
def pubspec_supports_macos(file)
file_abs_path = File.expand_path(file)
if !File.exists? file_abs_path
return false;
end
File.foreach(file_abs_path) { |line|
return true if line =~ /^\s*macos:/
}
return false
end
target 'Runner' do
use_frameworks!
use_modular_headers!
# Prepare symlinks folder. We use symlinks to avoid having Podfile.lock
# referring to absolute paths on developers' machines.
ephemeral_dir = File.join('Flutter', 'ephemeral')
symlink_dir = File.join(ephemeral_dir, '.symlinks')
symlink_plugins_dir = File.join(symlink_dir, 'plugins')
system("rm -rf #{symlink_dir}")
system("mkdir -p #{symlink_plugins_dir}")
# Flutter Pods
generated_xcconfig = parse_KV_file(File.join(ephemeral_dir, 'Flutter-Generated.xcconfig'))
if generated_xcconfig.empty?
puts "Flutter-Generated.xcconfig must exist. If you're running pod install manually, make sure flutter packages get is executed first."
end
generated_xcconfig.map { |p|
if p[:name] == 'FLUTTER_FRAMEWORK_DIR'
symlink = File.join(symlink_dir, 'flutter')
File.symlink(File.dirname(p[:path]), symlink)
pod 'FlutterMacOS', :path => File.join(symlink, File.basename(p[:path]))
end
}
# Plugin Pods
plugin_pods = parse_KV_file('../.flutter-plugins')
plugin_pods.map { |p|
symlink = File.join(symlink_plugins_dir, p[:name])
File.symlink(p[:path], symlink)
if pubspec_supports_macos(File.join(symlink, 'pubspec.yaml'))
pod p[:name], :path => File.join(symlink, 'macos')
end
}
end
# Prevent Cocoapods from embedding a second Flutter framework and causing an error with the new Xcode build system.
install! 'cocoapods', :disable_input_output_paths => true
... ...
... ... @@ -74,6 +74,11 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
flutter_web_plugins:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
image:
dependency: transitive
description:
... ... @@ -96,12 +101,12 @@ packages:
source: hosted
version: "1.1.8"
modal_bottom_sheet:
dependency: "direct dev"
dependency: "direct main"
description:
path: ".."
relative: true
source: path
version: "0.1.0"
version: "0.1.4"
path:
dependency: transitive
description:
... ... @@ -123,6 +128,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.4.0"
plugin_platform_interface:
dependency: transitive
description:
name: plugin_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.2"
quiver:
dependency: transitive
description:
... ... @@ -184,6 +196,34 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.6"
url_launcher:
dependency: "direct main"
description:
name: url_launcher
url: "https://pub.dartlang.org"
source: hosted
version: "5.4.2"
url_launcher_macos:
dependency: transitive
description:
name: url_launcher_macos
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.1+4"
url_launcher_platform_interface:
dependency: transitive
description:
name: url_launcher_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.6"
url_launcher_web:
dependency: transitive
description:
name: url_launcher_web
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.1+1"
vector_math:
dependency: transitive
description:
... ... @@ -199,4 +239,5 @@ packages:
source: hosted
version: "3.5.0"
sdks:
dart: ">=2.4.0 <3.0.0"
dart: ">=2.7.0 <3.0.0"
flutter: ">=1.12.8 <2.0.0"
... ...
... ... @@ -14,11 +14,14 @@ description: A new Flutter project.
version: 1.0.0+1
environment:
sdk: ">=2.1.0 <3.0.0"
sdk: ">=2.7.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
url_launcher: ^5.4.2
modal_bottom_sheet:
path: '../'
# The following adds the Cupertino Icons font to your application.
... ... @@ -28,8 +31,6 @@ dependencies:
dev_dependencies:
flutter_test:
sdk: flutter
modal_bottom_sheet:
path: '../'
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec
... ... @@ -42,6 +43,8 @@ flutter:
# the material Icons class.
uses-material-design: true
assets:
- assets/
# To add assets to your application, add an assets section, like this:
# assets:
# - images/a_dot_burr.jpeg
... ...
... ... @@ -3,7 +3,24 @@
<head>
<meta charset="UTF-8">
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
<meta name="description" content="A new Flutter project.">
<!-- Primary Meta Tags -->
<title>Flutter Modal Bottom Sheets</title>
<meta name="title" content="Flutter Modal Bottom Sheets">
<meta name="description" content="Build advanced modals. Cupertino, material or create your own">
<!-- Open Graph / Facebook -->
<meta property="og:type" content="website">
<meta property="og:url" content="https://jamesblasco.github.io/modal_bottom_sheet/">
<meta property="og:title" content="Flutter Modal Bottom Sheets">
<meta property="og:description" content="Build advanced modals. Cupertino, material or create your own">
<meta property="og:image" content="https://jamesblasco.github.io/modal_bottom_sheet/icons/image.png">
<!-- Twitter -->
<meta property="twitter:card" content="summary_large_image">
<meta property="twitter:url" content="https://jamesblasco.github.io/modal_bottom_sheet/">
<meta property="twitter:title" content="Flutter Modal Bottom Sheets">
<meta property="twitter:description" content="Build advanced modals. Cupertino, material or create your own">
<meta property="og:image" content="https://jamesblasco.github.io/modal_bottom_sheet/icons/image.png">
<!-- iOS meta tags & icons -->
<meta name="apple-mobile-web-app-capable" content="yes">
... ... @@ -14,7 +31,6 @@
<!-- Favicon -->
<link rel="shortcut icon" type="image/png" href="/favicon.png"/>
<title>example</title>
<link rel="manifest" href="/manifest.json">
</head>
<body>
... ... @@ -24,7 +40,9 @@
<script>
if ('serviceWorker' in navigator) {
window.addEventListener('load', function () {
navigator.serviceWorker.register('/flutter_service_worker.js');
navigator.serviceWorker.register('flutter_service_worker.js', {
scope: './'
});
});
}
</script>
... ...
... ... @@ -30,13 +30,11 @@ typedef WidgetWithChildBuilder = Widget Function(
/// See also:
///
/// * [showMaterialModalBottomSheet] which can be used to display a modal bottom
/// sheet with Material appareance.
/// * [showCupertinoModalBottomSheet] which can be used to display a modal bottom
/// sheet with Cupertino appareance.
class ModalBottomSheet extends StatefulWidget {
/// Creates a bottom sheet.
///
/// Typically, bottom sheets are created implicitly by
/// [ScaffoldState.showBottomSheet], for persistent bottom sheets, or by
/// [showModalBottomSheet], for modal bottom sheets.
const ModalBottomSheet({
Key key,
this.animationController,
... ... @@ -85,8 +83,6 @@ class ModalBottomSheet extends StatefulWidget {
/// A builder for the contents of the sheet.
///
/// The bottom sheet will wrap the widget produced by this builder in a
/// [Material] widget.
final ScrollWidgetBuilder builder;
/// If true, the bottom sheet can be dragged up and down and dismissed by
... ... @@ -124,8 +120,7 @@ class _ModalBottomSheetState extends State<ModalBottomSheet>
AnimationController _bounceDragController;
double get _childHeight {
final RenderBox renderBox =
_childKey.currentContext.findRenderObject() as RenderBox;
final renderBox = _childKey.currentContext.findRenderObject() as RenderBox;
return renderBox.size.height;
}
... ... @@ -152,8 +147,9 @@ class _ModalBottomSheetState extends State<ModalBottomSheet>
widget.animationController.forward().then((value) {
// When using WillPop, animation doesn't end at 1.
// Check more in detail the problem
if (!widget.animationController.isCompleted)
if (!widget.animationController.isCompleted) {
widget.animationController.value = 1;
}
});
_bounceDragController.reverse();
}
... ... @@ -182,7 +178,6 @@ class _ModalBottomSheetState extends State<ModalBottomSheet>
final canClose = await shouldClose();
if (canClose) {
_close();
print('close');
return;
} else {
_cancelClose();
... ... @@ -208,7 +203,7 @@ class _ModalBottomSheetState extends State<ModalBottomSheet>
isDragging = false;
_bounceDragController.reverse();
bool canClose = true;
var canClose = true;
if (widget.shouldClose != null && hasReachedWillPopThreshold) {
_cancelClose();
canClose = await shouldClose();
... ... @@ -217,12 +212,11 @@ class _ModalBottomSheetState extends State<ModalBottomSheet>
// If speed is bigger than _minFlingVelocity try to close it
if (velocity > _minFlingVelocity) {
_close();
print('close2');
} else if (hasReachedCloseThreshold) {
if (widget.animationController.value > 0.0)
if (widget.animationController.value > 0.0) {
widget.animationController.fling(velocity: -1.0);
}
_close();
print('close3');
} else {
_cancelClose();
}
... ... @@ -231,13 +225,26 @@ class _ModalBottomSheetState extends State<ModalBottomSheet>
}
}
_handleScrollUpdate(ScrollNotification notification) {
// As we cannot access the dragGesture detector of the scroll view
// we can not know the DragDownDetails and therefore the end velocity.
// VelocityTracker it is used to calculate the end velocity of the scroll
// when user is trying to close the modal by dragging
VelocityTracker _velocityTracker;
DateTime _startTime;
void _handleScrollUpdate(ScrollNotification notification) {
if (notification.metrics.pixels <= notification.metrics.minScrollExtent) {
//Check if listener is same from scrollController
if (!_scrollController.hasClients) return;
if (_scrollController.position.pixels != notification.metrics.pixels) {
return false;
return;
}
DragUpdateDetails dragDetails;
if (notification is ScrollStartNotification) {
_velocityTracker = VelocityTracker();
_startTime = DateTime.now();
}
if (notification is ScrollUpdateNotification) {
dragDetails = notification.dragDetails;
}
... ... @@ -245,12 +252,14 @@ class _ModalBottomSheetState extends State<ModalBottomSheet>
dragDetails = notification.dragDetails;
}
if (dragDetails != null) {
print('scroll');
final duration = _startTime.difference(DateTime.now());
final offset = Offset(0, _scrollController.offset);
_velocityTracker.addPosition(duration, offset);
_handleDragUpdate(dragDetails.primaryDelta);
} else if (isDragging) {
final velocity = _velocityTracker.getVelocity().pixelsPerSecond.dy;
_handleDragEnd(velocity);
}
// Todo: detect dragEnd during scroll so it can bottom sheet can close
// if velocity > _minFlingVelocity
else if (isDragging) _handleDragEnd(0);
}
}
... ... @@ -270,14 +279,15 @@ class _ModalBottomSheetState extends State<ModalBottomSheet>
curve: Curves.easeOutSine,
);
Widget child = widget.builder(context, _scrollController);
var child = widget.builder(context, _scrollController);
if (widget.containerBuilder != null)
if (widget.containerBuilder != null) {
child = widget.containerBuilder(
context,
widget.animationController,
child,
);
}
// Todo: Add curved Animation when push and pop without gesture
/* final Animation<double> containerAnimation = CurvedAnimation(
... ... @@ -366,15 +376,14 @@ class _CustomBottomSheetLayout extends SingleChildLayoutDelegate {
@override
Offset getPositionForChild(Size size, Size childSize) {
if (this.childHeight == null) this.childHeight = childSize.height;
childHeight ??= childSize.height;
return Offset(0.0, size.height - childSize.height);
}
@override
bool shouldRelayout(_CustomBottomSheetLayout oldDelegate) {
if (progress != oldDelegate.progress) {
this.childHeight = oldDelegate.childHeight;
childHeight = oldDelegate.childHeight;
return true;
}
return false;
... ...
import 'dart:async';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import '../modal_bottom_sheet.dart';
... ... @@ -32,15 +33,18 @@ class _ModalBottomSheet<T> extends StatefulWidget {
}
class _ModalBottomSheetState<T> extends State<_ModalBottomSheet<T>> {
String _getRouteLabel(MaterialLocalizations localizations) {
final platform = Theme.of(context).platform;
String _getRouteLabel() {
final platform = Theme.of(context)?.platform ?? defaultTargetPlatform;
switch (platform) {
case TargetPlatform.iOS:
return '';
case TargetPlatform.android:
case TargetPlatform.fuchsia:
return localizations.dialogLabel;
break;
if (Localizations.of(context, MaterialLocalizations) != null) {
return MaterialLocalizations.of(context).dialogLabel;
} else {
return DefaultMaterialLocalizations().dialogLabel;
}
}
return null;
}
... ... @@ -57,17 +61,13 @@ class _ModalBottomSheetState<T> extends State<_ModalBottomSheet<T>> {
super.dispose();
}
updateController() {
void updateController() {
widget.secondAnimationController?.value = widget.route.animation.value;
}
@override
Widget build(BuildContext context) {
assert(debugCheckHasMediaQuery(context));
assert(debugCheckHasMaterialLocalizations(context));
final MaterialLocalizations localizations =
MaterialLocalizations.of(context);
final String routeLabel = _getRouteLabel(localizations);
return AnimatedBuilder(
animation: widget.route._animationController,
... ... @@ -77,7 +77,7 @@ class _ModalBottomSheetState<T> extends State<_ModalBottomSheet<T>> {
return Semantics(
scopesRoute: true,
namesRoute: true,
label: routeLabel,
label: _getRouteLabel(),
explicitChildNodes: true,
child: ModalBottomSheet(
expanded: widget.route.expanded,
... ...
... ... @@ -4,10 +4,15 @@
import 'dart:async';
import 'package:flutter/cupertino.dart';
import 'package:flutter/cupertino.dart' show CupertinoTheme;
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/material.dart'
show
Colors,
Theme,
MaterialLocalizations,
debugCheckHasMaterialLocalizations;
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
... ... @@ -85,7 +90,13 @@ Future<T> showCupertinoModalBottomSheet<T>({
assert(useRootNavigator != null);
assert(enableDrag != null);
assert(debugCheckHasMediaQuery(context));
assert(debugCheckHasMaterialLocalizations(context));
final hasMaterialLocalizations =
Localizations.of<MaterialLocalizations>(context, MaterialLocalizations) !=
null;
final barrierLabel = hasMaterialLocalizations
? MaterialLocalizations.of(context).modalBarrierDismissLabel
: '';
final result = await Navigator.of(context, rootNavigator: useRootNavigator)
.push(CupertinoModalBottomSheetRoute<T>(
builder: builder,
... ... @@ -96,7 +107,7 @@ Future<T> showCupertinoModalBottomSheet<T>({
),
secondAnimationController: secondAnimation,
expanded: expand,
barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel,
barrierLabel: barrierLabel,
elevation: elevation,
bounce: bounce,
shape: shape,
... ... @@ -184,9 +195,9 @@ class _CupertinoModalTransition extends StatelessWidget {
@override
Widget build(BuildContext context) {
double startRoundCorner = 0;
var startRoundCorner = 0.0;
final paddingTop = MediaQuery.of(context).padding.top;
if (defaultTargetPlatform == TargetPlatform.iOS && paddingTop > 20) {
if (Theme.of(context).platform == TargetPlatform.iOS && paddingTop > 20) {
startRoundCorner = 38.5;
//https://kylebashour.com/posts/finding-the-real-iphone-x-corner-radius
}
... ... @@ -202,8 +213,6 @@ class _CupertinoModalTransition extends StatelessWidget {
animation: curvedAnimation,
child: body,
builder: (context, child) {
Widget result = child;
final progress = curvedAnimation.value;
final yOffset = progress * paddingTop;
final scale = 1 - progress / 10;
... ... @@ -220,7 +229,7 @@ class _CupertinoModalTransition extends StatelessWidget {
alignment: Alignment.topCenter,
child: ClipRRect(
borderRadius: BorderRadius.circular(radius),
child: result),
child: child),
),
)
],
... ... @@ -233,6 +242,7 @@ class _CupertinoModalTransition extends StatelessWidget {
class _CupertinoScaffold extends InheritedWidget {
final AnimationController animation;
@override
final Widget child;
const _CupertinoScaffold({Key key, this.animation, this.child})
... ... @@ -273,7 +283,12 @@ class CupertinoScaffold extends StatefulWidget {
assert(useRootNavigator != null);
assert(enableDrag != null);
assert(debugCheckHasMediaQuery(context));
assert(debugCheckHasMaterialLocalizations(context));
final isCupertinoApp = Theme.of(context, shadowThemeOnly: true) == null;
String barrierLabel = '';
if (!isCupertinoApp) {
assert(debugCheckHasMaterialLocalizations(context));
barrierLabel = MaterialLocalizations.of(context).modalBarrierDismissLabel;
}
final result = await Navigator.of(context, rootNavigator: useRootNavigator)
.push(CupertinoModalBottomSheetRoute<T>(
builder: builder,
... ... @@ -283,7 +298,7 @@ class CupertinoScaffold extends StatefulWidget {
backgroundColor: backgroundColor,
),
expanded: expand,
barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel,
barrierLabel: barrierLabel,
bounce: bounce,
isDismissible: isDismissible ?? expand == false ? true : false,
modalBarrierColor: barrierColor ?? Colors.black12,
... ...
... ... @@ -55,14 +55,13 @@ WidgetWithChildBuilder _materialContainerBuilder(BuildContext context,
ThemeData theme,
Clip clipBehavior,
ShapeBorder shape}) {
final BottomSheetThemeData bottomSheetTheme =
Theme.of(context).bottomSheetTheme;
final Color color = backgroundColor ??
final bottomSheetTheme = Theme.of(context).bottomSheetTheme;
final color = backgroundColor ??
bottomSheetTheme?.modalBackgroundColor ??
bottomSheetTheme?.backgroundColor;
final double _elevation = elevation ?? bottomSheetTheme.elevation ?? 0;
final ShapeBorder _shape = shape ?? bottomSheetTheme.shape;
final Clip _clipBehavior =
final _elevation = elevation ?? bottomSheetTheme.elevation ?? 0.0;
final _shape = shape ?? bottomSheetTheme.shape;
final _clipBehavior =
clipBehavior ?? bottomSheetTheme.clipBehavior ?? Clip.none;
final result = (context, animation, child) => Material(
... ...
... ... @@ -40,7 +40,7 @@ class MaterialWithModalsPageRoute<T> extends MaterialPageRoute<T> {
@override
void didChangeNext(Route nextRoute) {
if (nextRoute is ModalBottomSheetRoute) {
this._nextModalRoute = nextRoute;
_nextModalRoute = nextRoute;
}
super.didChangeNext(nextRoute);
... ... @@ -60,7 +60,7 @@ class MaterialWithModalsPageRoute<T> extends MaterialPageRoute<T> {
@override
Widget buildTransitions(BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation, Widget child) {
final PageTransitionsTheme theme = Theme.of(context).pageTransitionsTheme;
final theme = Theme.of(context).pageTransitionsTheme;
if (_nextModalRoute != null) {
if (!secondaryAnimation.isDismissed) {
// Avoid default transition theme to animate when a new modal view is pushed
... ...
... ... @@ -96,7 +96,7 @@ packages:
source: hosted
version: "1.6.4"
pedantic:
dependency: transitive
dependency: "direct dev"
description:
name: pedantic
url: "https://pub.dartlang.org"
... ... @@ -186,3 +186,4 @@ packages:
version: "3.5.0"
sdks:
dart: ">=2.4.0 <3.0.0"
flutter: ">=1.12.0 <2.0.0"
... ...
name: modal_bottom_sheet
description: 'Create flutter advanced modal bottom sheets. Material, Cupertino or your own style'
version: 0.1.3
description: 'Create awesome and powerful modal bottom sheets. Material, Cupertino iOS 13 or create your own style'
version: 0.1.5
homepage: 'https://github.com/jamesblasco/modal_bottom_sheet'
environment:
... ... @@ -14,6 +14,7 @@ dependencies:
dev_dependencies:
flutter_test:
sdk: flutter
pedantic: ^1.8.0+1
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec
... ...