├── lib ├── chapter13 │ ├── index.dart │ └── webview.dart ├── chapter12 │ └── index.dart ├── chapter11 │ ├── index.dart │ ├── socket.dart │ ├── file.dart │ └── http.dart ├── chapter2 │ ├── index.dart │ ├── cupertino_route.dart │ ├── 2.2 │ │ └── router.dart │ ├── counter.dart │ ├── state.dart │ └── getstate.dart ├── chapter8 │ ├── index.dart │ ├── pointer.dart │ ├── pointer_down_listener.dart │ └── notification.dart ├── chapter3 │ ├── index.dart │ ├── button.dart │ └── switch_checkbox.dart ├── chapter5 │ ├── index.dart │ ├── padding.dart │ ├── container.dart │ └── decoratedbox.dart ├── chapter4 │ ├── index.dart │ ├── row_column.dart │ ├── stack.dart │ └── layoutbuilder.dart ├── chapter10 │ ├── index.dart │ ├── donewidget_test.dart │ ├── custom_paint.dart │ ├── gradient_button.dart │ ├── turn_box.dart │ └── custom_checkbox_test.dart ├── chapter7 │ ├── index.dart │ ├── willpopscope.dart │ └── value_listenable_builder.dart ├── chapter14 │ ├── index.dart │ ├── constraints.dart │ ├── draw_main.dart │ ├── repaintboundary.dart │ └── state_change_update_flow.dart ├── chapter9 │ ├── index.dart │ ├── scale_animation_animatedbuilder.dart │ ├── animated_switcher_counter.dart │ ├── scale_animation_animatedwidget.dart │ ├── scale_animation.dart │ └── grow_transition.dart ├── routes.dart ├── chapter6 │ ├── fixedextentlist.dart │ ├── index.dart │ ├── single_child_scrollview.dart │ ├── sliver_persistent_header_tobox.dart │ ├── custom_pull_refresh.dart │ ├── infinite_gridview.dart │ ├── keepalive.dart │ ├── scrollnotification.dart │ ├── sliver_flexible_header.dart │ ├── configuration.dart │ └── pull_refresh.dart ├── widgets │ ├── index.dart │ ├── layoutlog.dart │ ├── keepalive.dart │ ├── extra_info_constraints.dart │ ├── event_bus.dart │ ├── translate_with_expanded_painting_area.dart │ ├── after_layout.dart │ ├── hit_test_blocker.dart │ ├── turn_box.dart │ ├── gradient_button.dart │ └── sliver_header_delegate.dart └── common.dart ├── gitme ├── lib │ ├── widgets │ │ └── index.dart │ ├── states │ │ ├── index.dart │ │ └── profile_change_notifier.dart │ ├── routes │ │ ├── index.dart │ │ ├── theme_change.dart │ │ └── language.dart │ ├── common │ │ ├── index.dart │ │ ├── icons.dart │ │ └── global.dart │ ├── models │ │ ├── index.dart │ │ ├── cacheConfig.dart │ │ ├── profile.dart │ │ ├── cacheConfig.g.dart │ │ ├── user.dart │ │ ├── commonUser.dart │ │ ├── profile.g.dart │ │ └── repo.dart │ └── index.dart ├── jsons │ ├── cacheConfig.json │ ├── profile.json │ ├── user.json │ ├── commonUser.json │ └── repo.json ├── fonts │ └── iconfont.ttf ├── imgs │ ├── logo_dark.png │ ├── logo_light.png │ └── avatar-default.png ├── android │ ├── gradle.properties │ ├── app │ │ ├── src │ │ │ ├── main │ │ │ │ ├── res │ │ │ │ │ ├── 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 │ │ │ │ │ ├── drawable │ │ │ │ │ │ └── launch_background.xml │ │ │ │ │ ├── drawable-v21 │ │ │ │ │ │ └── launch_background.xml │ │ │ │ │ ├── values │ │ │ │ │ │ └── styles.xml │ │ │ │ │ └── values-night │ │ │ │ │ │ └── styles.xml │ │ │ │ └── java │ │ │ │ │ └── club │ │ │ │ │ └── flutterchina │ │ │ │ │ └── gitme │ │ │ │ │ └── MainActivity.java │ │ │ ├── debug │ │ │ │ └── AndroidManifest.xml │ │ │ └── profile │ │ │ │ └── AndroidManifest.xml │ │ └── build.gradle │ ├── gradle │ │ └── wrapper │ │ │ └── gradle-wrapper.properties │ ├── .gitignore │ ├── settings.gradle │ └── build.gradle ├── macos │ ├── .gitignore │ ├── Runner │ │ ├── Configs │ │ │ ├── Debug.xcconfig │ │ │ ├── Release.xcconfig │ │ │ ├── Warnings.xcconfig │ │ │ └── AppInfo.xcconfig │ │ ├── Assets.xcassets │ │ │ └── AppIcon.appiconset │ │ │ │ ├── app_icon_128.png │ │ │ │ ├── app_icon_16.png │ │ │ │ ├── app_icon_256.png │ │ │ │ ├── app_icon_32.png │ │ │ │ ├── app_icon_512.png │ │ │ │ ├── app_icon_64.png │ │ │ │ ├── app_icon_1024.png │ │ │ │ └── Contents.json │ │ ├── AppDelegate.swift │ │ ├── Release.entitlements │ │ ├── DebugProfile.entitlements │ │ ├── MainFlutterWindow.swift │ │ └── Info.plist │ ├── Flutter │ │ ├── Flutter-Debug.xcconfig │ │ ├── Flutter-Release.xcconfig │ │ └── GeneratedPluginRegistrant.swift │ ├── Runner.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ ├── Runner.xcodeproj │ │ └── project.xcworkspace │ │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ ├── Podfile │ └── Podfile.lock ├── ios │ ├── Flutter │ │ ├── Debug.xcconfig │ │ ├── Release.xcconfig │ │ └── AppFrameworkInfo.plist │ ├── Runner │ │ ├── AppDelegate.h │ │ ├── Assets.xcassets │ │ │ ├── LaunchImage.imageset │ │ │ │ ├── LaunchImage.png │ │ │ │ ├── LaunchImage@2x.png │ │ │ │ ├── LaunchImage@3x.png │ │ │ │ ├── README.md │ │ │ │ └── Contents.json │ │ │ └── AppIcon.appiconset │ │ │ │ ├── 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-1024x1024@1x.png │ │ │ │ └── Icon-App-83.5x83.5@2x.png │ │ ├── main.m │ │ ├── AppDelegate.m │ │ ├── Info.plist │ │ └── Base.lproj │ │ │ └── Main.storyboard │ ├── Runner.xcodeproj │ │ └── project.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ ├── WorkspaceSettings.xcsettings │ │ │ └── IDEWorkspaceChecks.plist │ ├── Runner.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── WorkspaceSettings.xcsettings │ │ │ └── IDEWorkspaceChecks.plist │ ├── .gitignore │ ├── Podfile │ └── Podfile.lock ├── .metadata ├── README.md ├── .gitignore ├── test │ └── widget_test.dart ├── analysis_options.yaml └── l10n-arb │ └── intl_zh_CN.arb ├── imgs ├── sea.png └── avatar.png ├── web ├── favicon.png ├── icons │ ├── Icon-192.png │ └── Icon-512.png └── manifest.json ├── android ├── gradle.properties ├── app │ └── src │ │ ├── main │ │ ├── res │ │ │ ├── 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 │ │ │ ├── drawable │ │ │ │ └── launch_background.xml │ │ │ ├── drawable-v21 │ │ │ │ └── launch_background.xml │ │ │ ├── values │ │ │ │ └── styles.xml │ │ │ └── values-night │ │ │ │ └── styles.xml │ │ └── kotlin │ │ │ └── club │ │ │ └── flutterchina │ │ │ └── flutter_demo │ │ │ └── MainActivity.kt │ │ ├── debug │ │ └── AndroidManifest.xml │ │ └── profile │ │ └── AndroidManifest.xml ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties ├── .gitignore ├── settings.gradle └── build.gradle ├── macos ├── .gitignore ├── Runner │ ├── Configs │ │ ├── Debug.xcconfig │ │ ├── Release.xcconfig │ │ ├── Warnings.xcconfig │ │ └── AppInfo.xcconfig │ ├── Assets.xcassets │ │ └── AppIcon.appiconset │ │ │ ├── app_icon_16.png │ │ │ ├── app_icon_32.png │ │ │ ├── app_icon_64.png │ │ │ ├── app_icon_1024.png │ │ │ ├── app_icon_128.png │ │ │ ├── app_icon_256.png │ │ │ ├── app_icon_512.png │ │ │ └── Contents.json │ ├── AppDelegate.swift │ ├── Release.entitlements │ ├── MainFlutterWindow.swift │ ├── DebugProfile.entitlements │ └── Info.plist ├── Flutter │ ├── Flutter-Debug.xcconfig │ ├── Flutter-Release.xcconfig │ └── GeneratedPluginRegistrant.swift ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── Runner.xcodeproj │ └── project.xcworkspace │ │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── Podfile.lock └── Podfile ├── ios ├── Flutter │ ├── Debug.xcconfig │ ├── Release.xcconfig │ └── AppFrameworkInfo.plist ├── Runner │ ├── AppDelegate.h │ ├── Assets.xcassets │ │ ├── LaunchImage.imageset │ │ │ ├── LaunchImage.png │ │ │ ├── LaunchImage@2x.png │ │ │ ├── LaunchImage@3x.png │ │ │ ├── README.md │ │ │ └── Contents.json │ │ └── AppIcon.appiconset │ │ │ ├── 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-1024x1024@1x.png │ │ │ └── Icon-App-83.5x83.5@2x.png │ ├── main.m │ ├── AppDelegate.m │ ├── Base.lproj │ │ └── Main.storyboard │ └── Info.plist ├── build │ └── Pods.build │ │ └── Release-iphonesimulator │ │ ├── Flutter.build │ │ └── dgph │ │ ├── camera.build │ │ └── dgph │ │ ├── Pods-Runner.build │ │ └── dgph │ │ ├── image_picker.build │ │ └── dgph │ │ ├── path_provider.build │ │ └── dgph │ │ ├── video_player.build │ │ └── dgph │ │ └── webview_flutter.build │ │ └── dgph ├── Runner.xcodeproj │ └── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ ├── WorkspaceSettings.xcsettings │ │ └── IDEWorkspaceChecks.plist ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── WorkspaceSettings.xcsettings │ │ └── IDEWorkspaceChecks.plist ├── .gitignore ├── Podfile └── Podfile.lock ├── hjs.html ├── .metadata ├── README.md ├── assets ├── stackoverflow_dark.css └── stackoverflow_light.css ├── .gitignore ├── test └── widget_test.dart ├── analysis_options.yaml └── code.html /lib/chapter13/index.dart: -------------------------------------------------------------------------------- 1 | export 'webview.dart'; -------------------------------------------------------------------------------- /gitme/lib/widgets/index.dart: -------------------------------------------------------------------------------- 1 | export 'repo_item.dart'; -------------------------------------------------------------------------------- /gitme/lib/states/index.dart: -------------------------------------------------------------------------------- 1 | export 'profile_change_notifier.dart'; 2 | -------------------------------------------------------------------------------- /imgs/sea.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/imgs/sea.png -------------------------------------------------------------------------------- /lib/chapter12/index.dart: -------------------------------------------------------------------------------- 1 | export 'code_highlight.dart'; 2 | export 'markdown.dart'; 3 | -------------------------------------------------------------------------------- /imgs/avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/imgs/avatar.png -------------------------------------------------------------------------------- /web/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/web/favicon.png -------------------------------------------------------------------------------- /gitme/jsons/cacheConfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "enable":true, 3 | "maxAge":1000, 4 | "maxCount":100 5 | } -------------------------------------------------------------------------------- /web/icons/Icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/web/icons/Icon-192.png -------------------------------------------------------------------------------- /web/icons/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/web/icons/Icon-512.png -------------------------------------------------------------------------------- /gitme/fonts/iconfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/gitme/fonts/iconfont.ttf -------------------------------------------------------------------------------- /gitme/imgs/logo_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/gitme/imgs/logo_dark.png -------------------------------------------------------------------------------- /gitme/imgs/logo_light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/gitme/imgs/logo_light.png -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /gitme/imgs/avatar-default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/gitme/imgs/avatar-default.png -------------------------------------------------------------------------------- /lib/chapter11/index.dart: -------------------------------------------------------------------------------- 1 | export 'file.dart'; 2 | export 'http.dart'; 3 | export 'websocket.dart'; 4 | export 'socket.dart'; -------------------------------------------------------------------------------- /macos/.gitignore: -------------------------------------------------------------------------------- 1 | # Flutter-related 2 | **/Flutter/ephemeral/ 3 | **/Pods/ 4 | 5 | # Xcode-related 6 | **/xcuserdata/ 7 | -------------------------------------------------------------------------------- /macos/Runner/Configs/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Debug.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /gitme/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /gitme/macos/.gitignore: -------------------------------------------------------------------------------- 1 | # Flutter-related 2 | **/Flutter/ephemeral/ 3 | **/Pods/ 4 | 5 | # Xcode-related 6 | **/xcuserdata/ 7 | -------------------------------------------------------------------------------- /gitme/macos/Runner/Configs/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Debug.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /macos/Runner/Configs/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Release.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /gitme/macos/Runner/Configs/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Release.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /gitme/lib/routes/index.dart: -------------------------------------------------------------------------------- 1 | export 'home_page.dart'; 2 | export 'login.dart'; 3 | export 'theme_change.dart'; 4 | export 'language.dart'; -------------------------------------------------------------------------------- /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /gitme/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /gitme/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /gitme/lib/common/index.dart: -------------------------------------------------------------------------------- 1 | export 'git_api.dart'; 2 | export 'global.dart'; 3 | export 'net_cache.dart'; 4 | export 'icons.dart'; 5 | export 'funs.dart'; -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface AppDelegate : FlutterAppDelegate 5 | 6 | @end 7 | -------------------------------------------------------------------------------- /gitme/ios/Runner/AppDelegate.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface AppDelegate : FlutterAppDelegate 5 | 6 | @end 7 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /gitme/jsons/profile.json: -------------------------------------------------------------------------------- 1 | { 2 | "user?":"$user", 3 | "token?":"", 4 | "theme":0, 5 | "cache?":"$cacheConfig", 6 | "lastLogin?":"", 7 | "locale?":"en" 8 | } -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /gitme/lib/models/index.dart: -------------------------------------------------------------------------------- 1 | export 'repo.dart' ; 2 | export 'cacheConfig.dart' ; 3 | export 'user.dart' ; 4 | export 'commonUser.dart' ; 5 | export 'profile.dart' ; 6 | -------------------------------------------------------------------------------- /ios/build/Pods.build/Release-iphonesimulator/Flutter.build/dgph: -------------------------------------------------------------------------------- 1 | DGPH1.04 Aug 25 202119:34:47/Usersduwen Documentscodeflutter_in_action_2iosPods -------------------------------------------------------------------------------- /ios/build/Pods.build/Release-iphonesimulator/camera.build/dgph: -------------------------------------------------------------------------------- 1 | DGPH1.04 Aug 25 202119:34:47/Usersduwen Documentscodeflutter_in_action_2iosPods -------------------------------------------------------------------------------- /macos/Flutter/Flutter-Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "ephemeral/Flutter-Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /macos/Flutter/Flutter-Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "ephemeral/Flutter-Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /gitme/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/gitme/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /gitme/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/gitme/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /gitme/macos/Flutter/Flutter-Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "ephemeral/Flutter-Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/build/Pods.build/Release-iphonesimulator/Pods-Runner.build/dgph: -------------------------------------------------------------------------------- 1 | DGPH1.04 Aug 25 202119:34:47/Usersduwen Documentscodeflutter_in_action_2iosPods -------------------------------------------------------------------------------- /ios/build/Pods.build/Release-iphonesimulator/image_picker.build/dgph: -------------------------------------------------------------------------------- 1 | DGPH1.04 Aug 25 202119:34:47/Usersduwen Documentscodeflutter_in_action_2iosPods -------------------------------------------------------------------------------- /ios/build/Pods.build/Release-iphonesimulator/path_provider.build/dgph: -------------------------------------------------------------------------------- 1 | DGPH1.04 Aug 25 202119:34:47/Usersduwen Documentscodeflutter_in_action_2iosPods -------------------------------------------------------------------------------- /ios/build/Pods.build/Release-iphonesimulator/video_player.build/dgph: -------------------------------------------------------------------------------- 1 | DGPH1.04 Aug 25 202119:34:47/Usersduwen Documentscodeflutter_in_action_2iosPods -------------------------------------------------------------------------------- /gitme/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/gitme/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /gitme/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/gitme/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /gitme/macos/Flutter/Flutter-Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "ephemeral/Flutter-Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/build/Pods.build/Release-iphonesimulator/webview_flutter.build/dgph: -------------------------------------------------------------------------------- 1 | DGPH1.04 Aug 25 202119:34:47/Usersduwen Documentscodeflutter_in_action_2iosPods -------------------------------------------------------------------------------- /gitme/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/gitme/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png -------------------------------------------------------------------------------- /lib/chapter2/index.dart: -------------------------------------------------------------------------------- 1 | export './2.2/router.dart'; 2 | export 'counter.dart' show CounterRoute ; 3 | export 'state.dart'; 4 | export 'getstate.dart'; 5 | export 'cupertino_route.dart'; 6 | -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /gitme/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/gitme/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /gitme/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/gitme/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png -------------------------------------------------------------------------------- /gitme/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/gitme/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png -------------------------------------------------------------------------------- /gitme/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/gitme/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png -------------------------------------------------------------------------------- /gitme/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/gitme/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png -------------------------------------------------------------------------------- /gitme/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/gitme/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png -------------------------------------------------------------------------------- /gitme/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/gitme/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png -------------------------------------------------------------------------------- /gitme/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/gitme/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /gitme/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/gitme/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /gitme/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/gitme/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /gitme/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/gitme/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /gitme/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/gitme/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /gitme/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/gitme/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /gitme/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/gitme/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /gitme/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/gitme/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /gitme/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/gitme/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /gitme/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/gitme/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /gitme/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/gitme/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /gitme/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/gitme/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /gitme/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/gitme/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /gitme/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/gitme/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /gitme/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/gitme/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /gitme/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/gitme/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /lib/chapter8/index.dart: -------------------------------------------------------------------------------- 1 | export 'notification.dart'; 2 | export 'pointer.dart'; 3 | export 'event_conflict.dart'; 4 | export 'gesture.dart'; 5 | export 'pointer_down_listener.dart'; 6 | export 'stack_event.dart'; -------------------------------------------------------------------------------- /gitme/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/gitme/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /gitme/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wendux/flutter_in_action_2/HEAD/gitme/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /lib/chapter3/index.dart: -------------------------------------------------------------------------------- 1 | export 'text.dart'; 2 | export 'button.dart'; 3 | export 'image_icon.dart'; 4 | export 'switch_checkbox.dart'; 5 | export 'textfield.dart'; 6 | export 'progress.dart'; 7 | export 'form.dart'; -------------------------------------------------------------------------------- /lib/chapter5/index.dart: -------------------------------------------------------------------------------- 1 | export 'decoratedbox.dart'; 2 | export 'padding.dart'; 3 | export 'scaffold.dart'; 4 | export 'transform.dart'; 5 | export 'container.dart'; 6 | export 'clip.dart'; 7 | export 'fittedbox.dart'; -------------------------------------------------------------------------------- /android/app/src/main/kotlin/club/flutterchina/flutter_demo/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package club.flutterchina.book 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /gitme/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /gitme/android/app/src/main/java/club/flutterchina/gitme/MainActivity.java: -------------------------------------------------------------------------------- 1 | package club.flutterchina.gitme; 2 | 3 | import io.flutter.embedding.android.FlutterActivity; 4 | 5 | public class MainActivity extends FlutterActivity { 6 | } 7 | -------------------------------------------------------------------------------- /hjs.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /lib/chapter4/index.dart: -------------------------------------------------------------------------------- 1 | export 'align.dart'; 2 | export 'row_column.dart'; 3 | export 'table.dart'; 4 | export 'wrap_and_flow.dart'; 5 | export 'stack.dart'; 6 | export 'constraints.dart'; 7 | export 'layoutbuilder.dart'; 8 | export 'afterlayout.dart'; -------------------------------------------------------------------------------- /lib/chapter10/index.dart: -------------------------------------------------------------------------------- 1 | export 'custom_paint.dart'; 2 | export 'gradient_button.dart'; 3 | export 'gradient_circular_progress.dart'; 4 | export 'turn_box.dart'; 5 | export 'custom_checkbox_test.dart'; 6 | export 'donewidget_test.dart'; 7 | export 'watermark.dart'; 8 | 9 | -------------------------------------------------------------------------------- /lib/chapter7/index.dart: -------------------------------------------------------------------------------- 1 | export 'inheritedwidget.dart'; 2 | export 'provider_route.dart'; 3 | export 'color.dart'; 4 | export 'theme.dart'; 5 | export 'future_and_stream_builder.dart'; 6 | export 'dialog.dart'; 7 | export 'willpopscope.dart'; 8 | export 'value_listenable_builder.dart'; -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /macos/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | @NSApplicationMain 5 | class AppDelegate: FlutterAppDelegate { 6 | override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { 7 | return true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /gitme/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 | -------------------------------------------------------------------------------- /gitme/macos/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | @NSApplicationMain 5 | class AppDelegate: FlutterAppDelegate { 6 | override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { 7 | return true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /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-6.7-all.zip 7 | -------------------------------------------------------------------------------- /macos/Runner/Release.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /gitme/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-6.7-all.zip 7 | -------------------------------------------------------------------------------- /gitme/macos/Runner/Release.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /gitme/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /gitme/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /macos/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /gitme/lib/index.dart: -------------------------------------------------------------------------------- 1 | export 'models/index.dart'; 2 | export 'states/index.dart'; 3 | export 'routes/index.dart'; 4 | export 'widgets/index.dart'; 5 | export 'l10n/localization_intl.dart'; 6 | export 'package:provider/provider.dart'; 7 | export 'common/index.dart'; 8 | export 'package:flutter/material.dart'; 9 | 10 | 11 | -------------------------------------------------------------------------------- /gitme/macos/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /gitme/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /gitme/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /gitme/android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /gitme/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /lib/chapter14/index.dart: -------------------------------------------------------------------------------- 1 | export 'image_internal.dart'; 2 | export 'my_center.dart'; 3 | export 'left_right_box.dart'; 4 | export 'accurate_sized_box.dart'; 5 | export 'state_change_update_flow.dart'; 6 | export 'paint_test.dart'; 7 | export 'repaintboundary.dart'; 8 | export 'compositing_bits.dart'; 9 | export 'constraints.dart'; 10 | -------------------------------------------------------------------------------- /macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /gitme/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /gitme/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.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: d79295af24c3ed621c33713ecda14ad196fd9c31 8 | channel: beta 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | **/*.keystore 13 | **/*.jks 14 | -------------------------------------------------------------------------------- /gitme/.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: d79295af24c3ed621c33713ecda14ad196fd9c31 8 | channel: beta 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /macos/Flutter/GeneratedPluginRegistrant.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | import FlutterMacOS 6 | import Foundation 7 | 8 | import path_provider_macos 9 | 10 | func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { 11 | PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) 12 | } 13 | -------------------------------------------------------------------------------- /lib/chapter9/index.dart: -------------------------------------------------------------------------------- 1 | export 'animated_switcher_counter.dart'; 2 | export 'animated_widgets.dart'; 3 | export 'animation_switcher.dart'; 4 | export 'grow_transition.dart'; 5 | export 'hero_animation.dart'; 6 | export 'scale_animation.dart'; 7 | export 'scale_animation_animatedbuilder.dart'; 8 | export 'scale_animation_animatedwidget.dart'; 9 | export 'stagger_animation.dart'; -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /gitme/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /gitme/android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /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. -------------------------------------------------------------------------------- /gitme/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. -------------------------------------------------------------------------------- /gitme/macos/Runner/DebugProfile.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.cs.allow-jit 8 | 9 | com.apple.security.network.server 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /gitme/lib/models/cacheConfig.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'cacheConfig.g.dart'; 4 | 5 | @JsonSerializable() 6 | class CacheConfig { 7 | CacheConfig(); 8 | 9 | late bool enable; 10 | late num maxAge; 11 | late num maxCount; 12 | 13 | factory CacheConfig.fromJson(Map json) => _$CacheConfigFromJson(json); 14 | Map toJson() => _$CacheConfigToJson(this); 15 | } 16 | -------------------------------------------------------------------------------- /gitme/lib/common/icons.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class MyIcons { 4 | static const IconData github_outline = IconData(0xe799, fontFamily: 'myIcon'); 5 | static const IconData github = IconData(0xe7ab, fontFamily: 'myIcon'); 6 | static const IconData fork = IconData(0xe65b, fontFamily: 'myIcon'); 7 | static const IconData pr = IconData(0xe8b8, fontFamily: 'myIcon'); 8 | static const IconData code = IconData(0xe646, fontFamily: 'myIcon'); 9 | } -------------------------------------------------------------------------------- /macos/Runner/MainFlutterWindow.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | class MainFlutterWindow: NSWindow { 5 | override func awakeFromNib() { 6 | let flutterViewController = FlutterViewController.init() 7 | let windowFrame = self.frame 8 | self.contentViewController = flutterViewController 9 | self.setFrame(windowFrame, display: true) 10 | 11 | RegisterGeneratedPlugins(registry: flutterViewController) 12 | 13 | super.awakeFromNib() 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /gitme/macos/Runner/MainFlutterWindow.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | class MainFlutterWindow: NSWindow { 5 | override func awakeFromNib() { 6 | let flutterViewController = FlutterViewController.init() 7 | let windowFrame = self.frame 8 | self.contentViewController = flutterViewController 9 | self.setFrame(windowFrame, display: true) 10 | 11 | RegisterGeneratedPlugins(registry: flutterViewController) 12 | 13 | super.awakeFromNib() 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.m: -------------------------------------------------------------------------------- 1 | #import "AppDelegate.h" 2 | #import "GeneratedPluginRegistrant.h" 3 | 4 | @implementation AppDelegate 5 | 6 | - (BOOL)application:(UIApplication *)application 7 | didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 8 | [GeneratedPluginRegistrant registerWithRegistry:self]; 9 | // Override point for customization after application launch. 10 | return [super application:application didFinishLaunchingWithOptions:launchOptions]; 11 | } 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /lib/routes.dart: -------------------------------------------------------------------------------- 1 | export './widgets/index.dart'; 2 | export 'chapter2/index.dart'; 3 | export 'chapter3/index.dart'; 4 | export 'chapter4/index.dart'; 5 | export 'chapter5/index.dart'; 6 | export 'chapter6/index.dart'; 7 | export 'chapter7/index.dart'; 8 | export 'chapter8/index.dart'; 9 | export 'chapter9/index.dart'; 10 | export 'chapter10/index.dart'; 11 | export 'chapter11/index.dart'; 12 | export 'chapter12/index.dart'; 13 | export 'chapter13/index.dart'; 14 | export 'chapter14/index.dart'; 15 | -------------------------------------------------------------------------------- /gitme/ios/Runner/AppDelegate.m: -------------------------------------------------------------------------------- 1 | #import "AppDelegate.h" 2 | #import "GeneratedPluginRegistrant.h" 3 | 4 | @implementation AppDelegate 5 | 6 | - (BOOL)application:(UIApplication *)application 7 | didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 8 | [GeneratedPluginRegistrant registerWithRegistry:self]; 9 | // Override point for customization after application launch. 10 | return [super application:application didFinishLaunchingWithOptions:launchOptions]; 11 | } 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /macos/Runner/DebugProfile.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.cs.allow-jit 8 | 9 | com.apple.security.network.server 10 | 11 | 12 | com.apple.security.network.client 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties") 4 | def properties = new Properties() 5 | 6 | assert localPropertiesFile.exists() 7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } 8 | 9 | def flutterSdkPath = properties.getProperty("flutter.sdk") 10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" 12 | -------------------------------------------------------------------------------- /gitme/android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties") 4 | def properties = new Properties() 5 | 6 | assert localPropertiesFile.exists() 7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } 8 | 9 | def flutterSdkPath = properties.getProperty("flutter.sdk") 10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" 12 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /gitme/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /gitme/lib/models/profile.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | import "user.dart"; 3 | import "cacheConfig.dart"; 4 | part 'profile.g.dart'; 5 | 6 | @JsonSerializable() 7 | class Profile { 8 | Profile(); 9 | 10 | User? user; 11 | String? token; 12 | late num theme; 13 | CacheConfig? cache; 14 | String? lastLogin; 15 | String? locale; 16 | 17 | factory Profile.fromJson(Map json) => _$ProfileFromJson(json); 18 | Map toJson() => _$ProfileToJson(this); 19 | } 20 | -------------------------------------------------------------------------------- /gitme/android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /gitme/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 | -------------------------------------------------------------------------------- /gitme/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | google() 4 | jcenter() 5 | } 6 | 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:4.1.0' 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 | project.evaluationDependsOn(':app') 23 | } 24 | 25 | task clean(type: Delete) { 26 | delete rootProject.buildDir 27 | } 28 | -------------------------------------------------------------------------------- /gitme/macos/Flutter/GeneratedPluginRegistrant.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | import FlutterMacOS 6 | import Foundation 7 | 8 | import path_provider_macos 9 | import shared_preferences_macos 10 | import sqflite 11 | 12 | func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { 13 | PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) 14 | SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) 15 | SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) 16 | } 17 | -------------------------------------------------------------------------------- /gitme/README.md: -------------------------------------------------------------------------------- 1 | # gitme 2 | 3 | A new Flutter project. 4 | 5 | ## Getting Started 6 | 7 | This project is a starting point for a Flutter application. 8 | 9 | A few resources to get you started if this is your first Flutter project: 10 | 11 | - [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) 12 | - [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) 13 | 14 | For help getting started with Flutter, view our 15 | [online documentation](https://flutter.dev/docs), which offers tutorials, 16 | samples, guidance on mobile development, and a full API reference. 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # flutter_in_action_2 2 | 3 | A new Flutter project. 4 | 5 | ## Getting Started 6 | 7 | This project is a starting point for a Flutter application. 8 | 9 | A few resources to get you started if this is your first Flutter project: 10 | 11 | - [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) 12 | - [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) 13 | 14 | For help getting started with Flutter, view our 15 | [online documentation](https://flutter.dev/docs), which offers tutorials, 16 | samples, guidance on mobile development, and a full API reference. 17 | -------------------------------------------------------------------------------- /lib/chapter4/row_column.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class CenterColumnRoute extends StatelessWidget { 4 | const CenterColumnRoute({Key? key}) : super(key: key); 5 | 6 | @override 7 | Widget build(BuildContext context) { 8 | return ConstrainedBox( 9 | constraints: const BoxConstraints(minWidth: double.infinity), 10 | child: Column( 11 | crossAxisAlignment: CrossAxisAlignment.center, 12 | mainAxisSize: MainAxisSize.min, 13 | children: const [ 14 | Text("hi"), 15 | Text("world"), 16 | ], 17 | ), 18 | ); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lib/chapter6/fixedextentlist.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_in_action_2/routes.dart'; 3 | 4 | class FixedExtentList extends StatelessWidget { 5 | const FixedExtentList({Key? key}) : super(key: key); 6 | 7 | @override 8 | Widget build(BuildContext context) { 9 | return ListView.builder( 10 | // itemExtent: 56, 11 | //prototypeItem: ListTile(title: Text("1")), 12 | itemBuilder: (context, index) { 13 | return LayoutLogPrint( 14 | tag: index, 15 | child: ListTile(title: Text("$index")), 16 | ); 17 | }, 18 | ); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lib/chapter6/index.dart: -------------------------------------------------------------------------------- 1 | export 'single_child_scrollview.dart'; 2 | export 'custom_pull_refresh.dart'; 3 | export 'pull_refresh.dart'; 4 | export 'infinite_listview.dart'; 5 | export 'infinite_gridview.dart'; 6 | export 'custom_scrollview.dart'; 7 | export 'pageview.dart' hide Page; 8 | export 'fixedextentlist.dart'; 9 | export 'tabview.dart'; 10 | export 'scrollnotification.dart'; 11 | export 'animatedlist.dart'; 12 | export 'persistentheader.dart'; 13 | export 'sliver_persistent_header_tobox.dart'; 14 | export 'nestedscrollview.dart'; 15 | export 'keepalive.dart'; 16 | export 'sliver_flexible_header.dart'; 17 | export 'configuration.dart'; 18 | -------------------------------------------------------------------------------- /lib/widgets/index.dart: -------------------------------------------------------------------------------- 1 | export 'page_scaffold.dart'; 2 | export 'gradient_button.dart'; 3 | export 'gradient_circular_progress_indicator.dart'; 4 | export 'turn_box.dart'; 5 | export 'keepalive.dart'; 6 | export 'layoutlog.dart'; 7 | export 'sliver_header_delegate.dart'; 8 | export 'extra_info_constraints.dart'; 9 | export 'sliver_flexible_header.dart'; 10 | export 'pull_refresh_box.dart'; 11 | export 'sliver_persistent_header_tobox.dart'; 12 | export 'watermark.dart'; 13 | export 'translate_with_expanded_painting_area.dart'; 14 | export 'after_layout.dart'; 15 | export 'event_bus.dart'; 16 | export 'hit_test_blocker.dart'; 17 | export 'code_highlight.dart'; -------------------------------------------------------------------------------- /macos/Runner/Configs/Warnings.xcconfig: -------------------------------------------------------------------------------- 1 | WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings 2 | GCC_WARN_UNDECLARED_SELECTOR = YES 3 | CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES 4 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE 5 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES 6 | CLANG_WARN_PRAGMA_PACK = YES 7 | CLANG_WARN_STRICT_PROTOTYPES = YES 8 | CLANG_WARN_COMMA = YES 9 | GCC_WARN_STRICT_SELECTOR_MATCH = YES 10 | CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES 11 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES 12 | GCC_WARN_SHADOW = YES 13 | CLANG_WARN_UNREACHABLE_CODE = YES 14 | -------------------------------------------------------------------------------- /gitme/macos/Runner/Configs/Warnings.xcconfig: -------------------------------------------------------------------------------- 1 | WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings 2 | GCC_WARN_UNDECLARED_SELECTOR = YES 3 | CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES 4 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE 5 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES 6 | CLANG_WARN_PRAGMA_PACK = YES 7 | CLANG_WARN_STRICT_PROTOTYPES = YES 8 | CLANG_WARN_COMMA = YES 9 | GCC_WARN_STRICT_SELECTOR_MATCH = YES 10 | CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES 11 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES 12 | GCC_WARN_SHADOW = YES 13 | CLANG_WARN_UNREACHABLE_CODE = YES 14 | -------------------------------------------------------------------------------- /lib/chapter2/cupertino_route.dart: -------------------------------------------------------------------------------- 1 | //导入cupertino widget 库 2 | import 'package:flutter/cupertino.dart'; 3 | 4 | class CupertinoTestRoute extends StatelessWidget { 5 | const CupertinoTestRoute({Key? key}) : super(key: key); 6 | 7 | @override 8 | Widget build(BuildContext context) { 9 | return CupertinoPageScaffold( 10 | navigationBar: const CupertinoNavigationBar( 11 | middle: Text("Cupertino Demo"), 12 | ), 13 | child: Center( 14 | child: CupertinoButton( 15 | color: CupertinoColors.activeBlue, 16 | child: const Text("Press"), 17 | onPressed: () {} 18 | ), 19 | ), 20 | ); 21 | } 22 | } -------------------------------------------------------------------------------- /gitme/macos/Runner/Configs/AppInfo.xcconfig: -------------------------------------------------------------------------------- 1 | // Application-level settings for the Runner target. 2 | // 3 | // This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the 4 | // future. If not, the values below would default to using the project name when this becomes a 5 | // 'flutter create' template. 6 | 7 | // The application's name. By default this is also the title of the Flutter window. 8 | PRODUCT_NAME = gitme 9 | 10 | // The application's bundle identifier 11 | PRODUCT_BUNDLE_IDENTIFIER = club.flutterchina.gitme 12 | 13 | // The copyright displayed in application information 14 | PRODUCT_COPYRIGHT = Copyright © 2021 club.flutterchina. All rights reserved. 15 | -------------------------------------------------------------------------------- /web/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "flutter_in_action_2", 3 | "short_name": "flutter_in_action_2", 4 | "start_url": ".", 5 | "display": "standalone", 6 | "background_color": "#0175C2", 7 | "theme_color": "#0175C2", 8 | "description": "A new Flutter project.", 9 | "orientation": "portrait-primary", 10 | "prefer_related_applications": false, 11 | "icons": [ 12 | { 13 | "src": "icons/Icon-192.png", 14 | "sizes": "192x192", 15 | "type": "image/png" 16 | }, 17 | { 18 | "src": "icons/Icon-512.png", 19 | "sizes": "512x512", 20 | "type": "image/png" 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /lib/widgets/layoutlog.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/widgets.dart'; 2 | 3 | class LayoutLogPrint extends StatelessWidget { 4 | const LayoutLogPrint({ 5 | Key? key, 6 | this.tag, 7 | this.debugPrint = print, 8 | required this.child, 9 | }) : super(key: key); 10 | 11 | final Widget child; 12 | final Function(Object? object) debugPrint; 13 | final T? tag; 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | return LayoutBuilder(builder: (_, constraints) { 18 | assert(() { 19 | debugPrint('${tag ?? key ?? child.runtimeType}: $constraints'); 20 | return true; 21 | }()); 22 | return child; 23 | }); 24 | } 25 | } 26 | 27 | 28 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.3.50' 3 | repositories { 4 | google() 5 | mavenCentral() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:4.1.0' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | } 12 | } 13 | 14 | allprojects { 15 | repositories { 16 | google() 17 | mavenCentral() 18 | } 19 | } 20 | 21 | rootProject.buildDir = '../build' 22 | subprojects { 23 | project.buildDir = "${rootProject.buildDir}/${project.name}" 24 | project.evaluationDependsOn(':app') 25 | } 26 | 27 | task clean(type: Delete) { 28 | delete rootProject.buildDir 29 | } 30 | -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | *.mode1v3 2 | *.mode2v3 3 | *.moved-aside 4 | *.pbxuser 5 | *.perspectivev3 6 | **/*sync/ 7 | .sconsign.dblite 8 | .tags* 9 | **/.vagrant/ 10 | **/DerivedData/ 11 | Icon? 12 | **/Pods/ 13 | **/.symlinks/ 14 | profile 15 | xcuserdata 16 | **/.generated/ 17 | Flutter/App.framework 18 | Flutter/Flutter.framework 19 | Flutter/Flutter.podspec 20 | Flutter/Generated.xcconfig 21 | Flutter/ephemeral/ 22 | Flutter/app.flx 23 | Flutter/app.zip 24 | Flutter/flutter_assets/ 25 | Flutter/flutter_export_environment.sh 26 | ServiceDefinitions.json 27 | Runner/GeneratedPluginRegistrant.* 28 | 29 | # Exceptions to above rules. 30 | !default.mode1v3 31 | !default.mode2v3 32 | !default.pbxuser 33 | !default.perspectivev3 34 | -------------------------------------------------------------------------------- /macos/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - FlutterMacOS (1.0.0) 3 | - path_provider_macos (0.0.1): 4 | - FlutterMacOS 5 | 6 | DEPENDENCIES: 7 | - FlutterMacOS (from `Flutter/ephemeral`) 8 | - path_provider_macos (from `Flutter/ephemeral/.symlinks/plugins/path_provider_macos/macos`) 9 | 10 | EXTERNAL SOURCES: 11 | FlutterMacOS: 12 | :path: Flutter/ephemeral 13 | path_provider_macos: 14 | :path: Flutter/ephemeral/.symlinks/plugins/path_provider_macos/macos 15 | 16 | SPEC CHECKSUMS: 17 | FlutterMacOS: 57701585bf7de1b3fc2bb61f6378d73bbdea8424 18 | path_provider_macos: 160cab0d5461f0c0e02995469a98f24bdb9a3f1f 19 | 20 | PODFILE CHECKSUM: 6eac6b3292e5142cfc23bdeb71848a40ec51c14c 21 | 22 | COCOAPODS: 1.11.3 23 | -------------------------------------------------------------------------------- /macos/Runner/Configs/AppInfo.xcconfig: -------------------------------------------------------------------------------- 1 | // Application-level settings for the Runner target. 2 | // 3 | // This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the 4 | // future. If not, the values below would default to using the project name when this becomes a 5 | // 'flutter create' template. 6 | 7 | // The application's name. By default this is also the title of the Flutter window. 8 | PRODUCT_NAME = flutter_in_action_2 9 | 10 | // The application's bundle identifier 11 | PRODUCT_BUNDLE_IDENTIFIER = com.flutterchina.flutterInAction2 12 | 13 | // The copyright displayed in application information 14 | PRODUCT_COPYRIGHT = Copyright © 2021 com.flutterchina. All rights reserved. 15 | -------------------------------------------------------------------------------- /gitme/ios/.gitignore: -------------------------------------------------------------------------------- 1 | *.mode1v3 2 | *.mode2v3 3 | *.moved-aside 4 | *.pbxuser 5 | *.perspectivev3 6 | **/*sync/ 7 | .sconsign.dblite 8 | .tags* 9 | **/.vagrant/ 10 | **/DerivedData/ 11 | Icon? 12 | **/Pods/ 13 | **/.symlinks/ 14 | profile 15 | xcuserdata 16 | **/.generated/ 17 | Flutter/App.framework 18 | Flutter/Flutter.framework 19 | Flutter/Flutter.podspec 20 | Flutter/Generated.xcconfig 21 | Flutter/ephemeral/ 22 | Flutter/app.flx 23 | Flutter/app.zip 24 | Flutter/flutter_assets/ 25 | Flutter/flutter_export_environment.sh 26 | ServiceDefinitions.json 27 | Runner/GeneratedPluginRegistrant.* 28 | 29 | # Exceptions to above rules. 30 | !default.mode1v3 31 | !default.mode2v3 32 | !default.pbxuser 33 | !default.perspectivev3 34 | -------------------------------------------------------------------------------- /gitme/lib/models/cacheConfig.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'cacheConfig.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | CacheConfig _$CacheConfigFromJson(Map json) => CacheConfig() 10 | ..enable = json['enable'] as bool 11 | ..maxAge = json['maxAge'] as num 12 | ..maxCount = json['maxCount'] as num; 13 | 14 | Map _$CacheConfigToJson(CacheConfig instance) => 15 | { 16 | 'enable': instance.enable, 17 | 'maxAge': instance.maxAge, 18 | 'maxCount': instance.maxCount, 19 | }; 20 | -------------------------------------------------------------------------------- /gitme/jsons/user.json: -------------------------------------------------------------------------------- 1 | { 2 | "login": "octocat", 3 | "id": 1, 4 | "node_id": "MDQ6VXNlcjE=", 5 | "avatar_url": "https://github.com/images/error/octocat_happy.gif", 6 | "url": "https://api.github.com/users/octocat", 7 | "type": "User", 8 | "site_admin": false, 9 | "name?": "monalisa octocat", 10 | "company?": "GitHub", 11 | "blog?": "https://github.com/blog", 12 | "location?": "San Francisco", 13 | "email?": "octocat@github.com", 14 | "hireable?": false, 15 | "bio?": "There once was...", 16 | "public_repos": 2, 17 | "public_gists": 1, 18 | "followers": 20, 19 | "following": 0, 20 | "created_at": "2008-01-14T04:33:35Z", 21 | "updated_at": "2008-01-14T04:33:35Z", 22 | "total_private_repos?": 100, 23 | "owned_private_repos?": 100 24 | } -------------------------------------------------------------------------------- /lib/chapter14/constraints.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter/rendering.dart'; 3 | import 'accurate_sized_box.dart'; 4 | 5 | class ConstraintsTest extends StatelessWidget { 6 | const ConstraintsTest({Key? key}) : super(key: key); 7 | 8 | @override 9 | Widget build(BuildContext context) { 10 | var container = Container(width: 200, height: 200, color: Colors.red); 11 | return UnconstrainedBox( 12 | child: container, 13 | ); 14 | // return Align( 15 | // child: container, 16 | // alignment: Alignment.topLeft, 17 | // ); 18 | // return CustomSizedBox( 19 | // width: 200, 20 | // height: 200, 21 | // child: Container(color: Colors.green,), 22 | // ); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lib/chapter14/draw_main.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | import 'package:flutter/rendering.dart'; 4 | 5 | import '../common.dart'; 6 | 7 | void main() { 8 | //1.创建绘制记录器和Canvas 9 | PictureRecorder recorder = PictureRecorder(); 10 | Canvas canvas = Canvas(recorder); 11 | //2.开始绘制 12 | var rect = Rect.fromLTWH(30, 200, 300,300 ); 13 | drawChessboard(canvas,rect);//画棋盘 14 | drawPieces(canvas,rect);//画棋子 15 | //3.创建layer,将绘制的内容保存在layer中 16 | var pictureLayer = PictureLayer(rect); 17 | //recorder.endRecording()获取绘制产物。 18 | pictureLayer.picture = recorder.endRecording(); 19 | var rootLayer = OffsetLayer(); 20 | rootLayer.append(pictureLayer); 21 | //4.上屏,即将绘制的内容显示在屏幕上。 22 | final SceneBuilder builder = SceneBuilder(); 23 | final Scene scene = rootLayer.buildScene(builder); 24 | window.render(scene); 25 | } 26 | -------------------------------------------------------------------------------- /assets/stackoverflow_dark.css: -------------------------------------------------------------------------------- 1 | pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{color:#fff;background:#1c1b1b}.hljs-subst{color:#fff}.hljs-comment{color:#999}.hljs-attr,.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-section,.hljs-selector-tag{color:#88aece}.hljs-attribute{color:#c59bc1}.hljs-name,.hljs-number,.hljs-quote,.hljs-selector-id,.hljs-template-tag,.hljs-type{color:#f08d49}.hljs-selector-class{color:#88aece}.hljs-link,.hljs-regexp,.hljs-selector-attr,.hljs-string,.hljs-symbol,.hljs-template-variable,.hljs-variable{color:#b5bd68}.hljs-meta,.hljs-selector-pseudo{color:#88aece}.hljs-built_in,.hljs-literal,.hljs-title{color:#f08d49}.hljs-bullet,.hljs-code{color:#ccc}.hljs-meta .hljs-string{color:#b5bd68}.hljs-deletion{color:#de7176}.hljs-addition{color:#76c490}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700} -------------------------------------------------------------------------------- /assets/stackoverflow_light.css: -------------------------------------------------------------------------------- 1 | pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{color:#2f3337;background:#f6f6f6}.hljs-subst{color:#2f3337}.hljs-comment{color:#656e77}.hljs-attr,.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-section,.hljs-selector-tag{color:#015692}.hljs-attribute{color:#803378}.hljs-name,.hljs-number,.hljs-quote,.hljs-selector-id,.hljs-template-tag,.hljs-type{color:#b75501}.hljs-selector-class{color:#015692}.hljs-link,.hljs-regexp,.hljs-selector-attr,.hljs-string,.hljs-symbol,.hljs-template-variable,.hljs-variable{color:#54790d}.hljs-meta,.hljs-selector-pseudo{color:#015692}.hljs-built_in,.hljs-literal,.hljs-title{color:#b75501}.hljs-bullet,.hljs-code{color:#535a60}.hljs-meta .hljs-string{color:#54790d}.hljs-deletion{color:#c02d2e}.hljs-addition{color:#2f6f44}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700} -------------------------------------------------------------------------------- /gitme/lib/models/user.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'user.g.dart'; 4 | 5 | @JsonSerializable() 6 | class User { 7 | User(); 8 | 9 | late String login; 10 | late num id; 11 | late String node_id; 12 | late String avatar_url; 13 | late String url; 14 | late String type; 15 | late bool site_admin; 16 | String? name; 17 | String? company; 18 | String? blog; 19 | String? location; 20 | String? email; 21 | bool? hireable; 22 | String? bio; 23 | late num public_repos; 24 | late num public_gists; 25 | late num followers; 26 | late num following; 27 | late String created_at; 28 | late String updated_at; 29 | num? total_private_repos; 30 | num? owned_private_repos; 31 | 32 | factory User.fromJson(Map json) => _$UserFromJson(json); 33 | Map toJson() => _$UserToJson(this); 34 | } 35 | -------------------------------------------------------------------------------- /gitme/lib/models/commonUser.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | 3 | part 'commonUser.g.dart'; 4 | 5 | @JsonSerializable() 6 | class CommonUser { 7 | CommonUser(); 8 | 9 | late String login; 10 | late num id; 11 | late String node_id; 12 | late String avatar_url; 13 | late String gravatar_id; 14 | late String url; 15 | late String html_url; 16 | late String followers_url; 17 | late String following_url; 18 | late String gists_url; 19 | late String starred_url; 20 | late String subscriptions_url; 21 | late String organizations_url; 22 | late String repos_url; 23 | late String events_url; 24 | late String received_events_url; 25 | late String type; 26 | late bool site_admin; 27 | 28 | factory CommonUser.fromJson(Map json) => _$CommonUserFromJson(json); 29 | Map toJson() => _$CommonUserToJson(this); 30 | } 31 | -------------------------------------------------------------------------------- /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 | MinimumOSVersion 24 | 9.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /lib/chapter6/single_child_scrollview.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class SingleChildScrollViewTestRoute extends StatelessWidget { 4 | const SingleChildScrollViewTestRoute({Key? key}) : super(key: key); 5 | 6 | @override 7 | Widget build(BuildContext context) { 8 | String str = "ABCD" * 20; 9 | return Scrollbar( 10 | // 显示进度条 11 | child: SingleChildScrollView( 12 | padding: const EdgeInsets.all(16.0), 13 | child: Center( 14 | child: Column( 15 | //动态创建一个List 16 | children: str 17 | .split("") 18 | //每一个字母都用一个Text显示,字体大小为原来的两倍 19 | .map((c) => Text( 20 | c, 21 | textScaleFactor: 2.0, 22 | )) 23 | .toList(), 24 | ), 25 | ), 26 | ), 27 | ); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /gitme/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 | MinimumOSVersion 24 | 9.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | **/ios/Flutter/.last_build_id 26 | .dart_tool/ 27 | .flutter-plugins 28 | .flutter-plugins-dependencies 29 | .packages 30 | .pub-cache/ 31 | .pub/ 32 | /build/ 33 | 34 | # Web related 35 | lib/generated_plugin_registrant.dart 36 | 37 | # Symbolication related 38 | app.*.symbols 39 | 40 | # Obfuscation related 41 | app.*.map.json 42 | 43 | # Android Studio will place build artifacts here 44 | /android/app/debug 45 | /android/app/profile 46 | /android/app/release 47 | -------------------------------------------------------------------------------- /gitme/lib/routes/theme_change.dart: -------------------------------------------------------------------------------- 1 | import '../index.dart'; 2 | 3 | class ThemeChangeRoute extends StatelessWidget{ 4 | @override 5 | Widget build(BuildContext context) { 6 | return Scaffold( 7 | appBar: AppBar( 8 | title: Text(GmLocalizations.of(context).theme), 9 | ), 10 | body: ListView( //显示主题色块 11 | children: Global.themes.map((e) { 12 | return GestureDetector( 13 | child: Padding( 14 | padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 16), 15 | child: Container( 16 | color: e, 17 | height: 40, 18 | ), 19 | ), 20 | onTap: () { 21 | //主题更新后,MaterialApp会重新build 22 | Provider.of(context, listen: false).theme = e; 23 | }, 24 | ); 25 | }).toList(), 26 | ), 27 | ); 28 | } 29 | } 30 | 31 | -------------------------------------------------------------------------------- /gitme/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | **/ios/Flutter/.last_build_id 26 | .dart_tool/ 27 | .flutter-plugins 28 | .flutter-plugins-dependencies 29 | .packages 30 | .pub-cache/ 31 | .pub/ 32 | /build/ 33 | 34 | # Web related 35 | lib/generated_plugin_registrant.dart 36 | 37 | # Symbolication related 38 | app.*.symbols 39 | 40 | # Obfuscation related 41 | app.*.map.json 42 | 43 | # Android Studio will place build artifacts here 44 | /android/app/debug 45 | /android/app/profile 46 | /android/app/release 47 | -------------------------------------------------------------------------------- /lib/chapter11/socket.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'dart:io'; 3 | 4 | import 'package:flutter/material.dart'; 5 | 6 | class SocketRoute extends StatelessWidget { 7 | const SocketRoute({Key? key}) : super(key: key); 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | return FutureBuilder( 12 | future: _request(), 13 | builder: (context, snapShot) { 14 | return Text(snapShot.data.toString()); 15 | }, 16 | ); 17 | } 18 | 19 | _request() async { 20 | //建立连接 21 | var socket = await Socket.connect("baidu.com", 80); 22 | //根据http协议,发送请求头 23 | socket.writeln("GET / HTTP/1.1"); 24 | socket.writeln("Host:baidu.com"); 25 | socket.writeln("Connection:close"); 26 | socket.writeln(); 27 | await socket.flush(); //发送 28 | //读取返回内容,按照utf8解码为字符串 29 | String _response = await utf8.decoder.bind(socket).join(); 30 | await socket.close(); 31 | return _response; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /lib/chapter4/stack.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class StackRoute extends StatelessWidget { 4 | const StackRoute({Key? key}) : super(key: key); 5 | 6 | @override 7 | Widget build(BuildContext context) { 8 | return ConstrainedBox( 9 | constraints: const BoxConstraints.expand(), 10 | child: Stack( 11 | alignment: Alignment.center, //指定未定位或部分定位widget的对齐方式 12 | clipBehavior: Clip.hardEdge, 13 | children: [ 14 | Container( 15 | child: const Text( 16 | "Hello world", 17 | style: TextStyle(color: Colors.white), 18 | ), 19 | color: Colors.red, 20 | ), 21 | const Positioned( 22 | left: 18.0, 23 | child: Text("I am Jack"), 24 | ), 25 | const Positioned( 26 | top: 18.0, 27 | child: Text("Your friend"), 28 | ) 29 | ], 30 | ), 31 | ); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /lib/chapter7/willpopscope.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class WillPopScopeTestRoute extends StatefulWidget { 4 | const WillPopScopeTestRoute({Key? key}) : super(key: key); 5 | 6 | @override 7 | WillPopScopeTestRouteState createState() { 8 | return WillPopScopeTestRouteState(); 9 | } 10 | } 11 | 12 | class WillPopScopeTestRouteState extends State { 13 | DateTime? _lastPressedAt; //上次点击时间 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | return WillPopScope( 18 | onWillPop: () async { 19 | if (_lastPressedAt == null || 20 | DateTime.now().difference(_lastPressedAt!) > const Duration(seconds: 1)) { 21 | //两次点击间隔超过1秒则重新计时 22 | _lastPressedAt = DateTime.now(); 23 | return false; 24 | } 25 | return true; 26 | }, 27 | child: Container( 28 | alignment: Alignment.center, 29 | child: const Text("1秒内连续按两次返回键退出"), 30 | ), 31 | ); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /gitme/jsons/commonUser.json: -------------------------------------------------------------------------------- 1 | { 2 | "login": "wendux", 3 | "id": 20411648, 4 | "node_id": "MDQ6VXNlcjIwNDExNjQ4", 5 | "avatar_url": "https://avatars.githubusercontent.com/u/20411648?v=4", 6 | "gravatar_id": "", 7 | "url": "https://api.github.com/users/wendux", 8 | "html_url": "https://github.com/wendux", 9 | "followers_url": "https://api.github.com/users/wendux/followers", 10 | "following_url": "https://api.github.com/users/wendux/following{/other_user}", 11 | "gists_url": "https://api.github.com/users/wendux/gists{/gist_id}", 12 | "starred_url": "https://api.github.com/users/wendux/starred{/owner}{/repo}", 13 | "subscriptions_url": "https://api.github.com/users/wendux/subscriptions", 14 | "organizations_url": "https://api.github.com/users/wendux/orgs", 15 | "repos_url": "https://api.github.com/users/wendux/repos", 16 | "events_url": "https://api.github.com/users/wendux/events{/privacy}", 17 | "received_events_url": "https://api.github.com/users/wendux/received_events", 18 | "type": "User", 19 | "site_admin": false 20 | } -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /gitme/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /lib/widgets/keepalive.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/widgets.dart'; 2 | 3 | class KeepAliveWrapper extends StatefulWidget { 4 | const KeepAliveWrapper({ 5 | Key? key, 6 | this.keepAlive = true, 7 | required this.child, 8 | }) : super(key: key); 9 | final bool keepAlive; 10 | final Widget child; 11 | 12 | @override 13 | _KeepAliveWrapperState createState() => _KeepAliveWrapperState(); 14 | } 15 | 16 | class _KeepAliveWrapperState extends State 17 | with AutomaticKeepAliveClientMixin { 18 | @override 19 | Widget build(BuildContext context) { 20 | super.build(context); 21 | return widget.child; 22 | } 23 | 24 | @override 25 | void didUpdateWidget(covariant KeepAliveWrapper oldWidget) { 26 | if (oldWidget.keepAlive != widget.keepAlive) { 27 | updateKeepAlive(); 28 | } 29 | super.didUpdateWidget(oldWidget); 30 | } 31 | 32 | @override 33 | void dispose() { 34 | //print("KeepAliveWrapper dispose"); 35 | super.dispose(); 36 | } 37 | 38 | @override 39 | bool get wantKeepAlive => widget.keepAlive; 40 | } 41 | -------------------------------------------------------------------------------- /gitme/android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /lib/chapter5/padding.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class PaddingTestRoute extends StatelessWidget { 4 | const PaddingTestRoute({Key? key}) : super(key: key); 5 | 6 | @override 7 | Widget build(BuildContext context) { 8 | return Padding( 9 | //上下左右各添加16像素补白 10 | padding: const EdgeInsets.all(16), 11 | child: Column( 12 | //显式指定对齐方式为左对齐,排除对齐干扰 13 | crossAxisAlignment: CrossAxisAlignment.start, 14 | mainAxisSize: MainAxisSize.min, 15 | children: const [ 16 | Padding( 17 | //左边添加8像素补白 18 | padding: EdgeInsets.only(left: 8), 19 | child: Text("Hello world"), 20 | ), 21 | Padding( 22 | //上下各添加8像素补白 23 | padding: EdgeInsets.symmetric(vertical: 8), 24 | child: Text("I am Jack"), 25 | ), 26 | Padding( 27 | // 分别指定四个方向的补白 28 | padding: EdgeInsets.fromLTRB(20, 0, 20, 20), 29 | child: Text("Your friend"), 30 | ) 31 | ], 32 | ), 33 | ); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /gitme/lib/models/profile.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'profile.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | Profile _$ProfileFromJson(Map json) => Profile() 10 | ..user = json['user'] == null 11 | ? null 12 | : User.fromJson(json['user'] as Map) 13 | ..token = json['token'] as String? 14 | ..theme = json['theme'] as num 15 | ..cache = json['cache'] == null 16 | ? null 17 | : CacheConfig.fromJson(json['cache'] as Map) 18 | ..lastLogin = json['lastLogin'] as String? 19 | ..locale = json['locale'] as String?; 20 | 21 | Map _$ProfileToJson(Profile instance) => { 22 | 'user': instance.user, 23 | 'token': instance.token, 24 | 'theme': instance.theme, 25 | 'cache': instance.cache, 26 | 'lastLogin': instance.lastLogin, 27 | 'locale': instance.locale, 28 | }; 29 | -------------------------------------------------------------------------------- /lib/widgets/extra_info_constraints.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/widgets.dart'; 2 | 3 | class ExtraInfoBoxConstraints extends BoxConstraints { 4 | ExtraInfoBoxConstraints( 5 | this.extra, 6 | BoxConstraints constraints, 7 | ) : super( 8 | minWidth: constraints.minWidth, 9 | minHeight: constraints.minHeight, 10 | maxWidth: constraints.maxWidth, 11 | maxHeight: constraints.maxHeight, 12 | ); 13 | 14 | //滑动方向 15 | final T extra; 16 | 17 | @override 18 | bool operator ==(Object other) { 19 | assert(debugAssertIsValid()); 20 | if (identical(this, other)) return true; 21 | if (other.runtimeType != runtimeType) return false; 22 | return other is ExtraInfoBoxConstraints && 23 | other.minWidth == minWidth && 24 | other.maxWidth == maxWidth && 25 | other.minHeight == minHeight && 26 | other.maxHeight == maxHeight && 27 | other.extra == extra; 28 | } 29 | 30 | @override 31 | int get hashCode { 32 | assert(debugAssertIsValid()); 33 | return hashValues(minWidth, maxWidth, minHeight, maxHeight, extra); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /lib/widgets/event_bus.dart: -------------------------------------------------------------------------------- 1 | //订阅者回调签名 2 | typedef void EventCallback(arg); 3 | 4 | class EventBus { 5 | //私有构造函数 6 | EventBus._internal(); 7 | 8 | //保存单例 9 | static EventBus _singleton = EventBus._internal(); 10 | 11 | //工厂构造函数 12 | factory EventBus()=> _singleton; 13 | 14 | //保存事件订阅者队列,key:事件名(id),value: 对应事件的订阅者队列 15 | final _emap = Map?>(); 16 | 17 | //添加订阅者 18 | void on(eventName, EventCallback f) { 19 | _emap[eventName] ??= []; 20 | _emap[eventName]!.add(f); 21 | } 22 | 23 | //移除订阅者 24 | void off(eventName, [EventCallback? f]) { 25 | var list = _emap[eventName]; 26 | if (eventName == null || list == null) return; 27 | if (f == null) { 28 | _emap[eventName] = null; 29 | } else { 30 | list.remove(f); 31 | } 32 | } 33 | 34 | //触发事件,事件触发后该事件所有订阅者会被调用 35 | void emit(eventName,[arg]) { 36 | var list = _emap[eventName]; 37 | if (list == null) return; 38 | int len = list.length - 1; 39 | //反向遍历,防止订阅者在回调中移除自身带来的下标错位 40 | for (var i = len; i > -1; --i) { 41 | list[i](arg); 42 | } 43 | } 44 | } 45 | 46 | var bus = EventBus(); -------------------------------------------------------------------------------- /lib/chapter5/container.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class ContainerRoute extends StatelessWidget { 4 | const ContainerRoute({Key? key}) : super(key: key); 5 | 6 | @override 7 | Widget build(BuildContext context) { 8 | return Container( 9 | margin: const EdgeInsets.only(top: 50.0, left: 120.0), 10 | constraints: const BoxConstraints.tightFor(width: 200.0, height: 150.0), //卡片大小 11 | decoration: const BoxDecoration( //背景装饰 12 | gradient: RadialGradient( //背景径向渐变 13 | colors: [Colors.red, Colors.orange], 14 | center: Alignment.topLeft, 15 | radius: .98, 16 | ), 17 | boxShadow: [ 18 | //卡片阴影 19 | BoxShadow( 20 | color: Colors.black54, 21 | offset: Offset(2.0, 2.0), 22 | blurRadius: 4.0, 23 | ) 24 | ], 25 | ), 26 | transform: Matrix4.rotationZ(.2),//卡片倾斜变换 27 | alignment: Alignment.center, //卡片内文字居中 28 | child: const Text( 29 | //卡片文字 30 | "5.20", style: TextStyle(color: Colors.white, fontSize: 40.0), 31 | ), 32 | ); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /gitme/test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility that Flutter provides. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_test/flutter_test.dart'; 10 | 11 | import 'package:gitme/main.dart'; 12 | 13 | void main() { 14 | testWidgets('Counter increments smoke test', (WidgetTester tester) async { 15 | // Build our app and trigger a frame. 16 | await tester.pumpWidget(MyApp()); 17 | 18 | // Verify that our counter starts at 0. 19 | expect(find.text('0'), findsOneWidget); 20 | expect(find.text('1'), findsNothing); 21 | 22 | // Tap the '+' icon and trigger a frame. 23 | await tester.tap(find.byIcon(Icons.add)); 24 | await tester.pump(); 25 | 26 | // Verify that our counter has incremented. 27 | expect(find.text('0'), findsNothing); 28 | expect(find.text('1'), findsOneWidget); 29 | }); 30 | } 31 | -------------------------------------------------------------------------------- /test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility that Flutter provides. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_test/flutter_test.dart'; 10 | 11 | import 'package:flutter_in_action_2/main.dart'; 12 | 13 | void main() { 14 | testWidgets('Counter increments smoke test', (WidgetTester tester) async { 15 | // Build our app and trigger a frame. 16 | await tester.pumpWidget(MyApp()); 17 | 18 | // Verify that our counter starts at 0. 19 | expect(find.text('0'), findsOneWidget); 20 | expect(find.text('1'), findsNothing); 21 | 22 | // Tap the '+' icon and trigger a frame. 23 | await tester.tap(find.byIcon(Icons.add)); 24 | await tester.pump(); 25 | 26 | // Verify that our counter has incremented. 27 | expect(find.text('0'), findsNothing); 28 | expect(find.text('1'), findsOneWidget); 29 | }); 30 | } 31 | -------------------------------------------------------------------------------- /gitme/lib/models/repo.dart: -------------------------------------------------------------------------------- 1 | import 'package:json_annotation/json_annotation.dart'; 2 | import "commonUser.dart"; 3 | part 'repo.g.dart'; 4 | 5 | @JsonSerializable() 6 | class Repo { 7 | Repo(); 8 | 9 | late num id; 10 | late String node_id; 11 | late String name; 12 | late String full_name; 13 | late CommonUser owner; 14 | Repo? parent; 15 | late bool private; 16 | late String html_url; 17 | String? description; 18 | late bool fork; 19 | String? homepage; 20 | String? language; 21 | late num forks_count; 22 | late num stargazers_count; 23 | late num watchers_count; 24 | late num size; 25 | late String default_branch; 26 | late num open_issues_count; 27 | List? topics; 28 | late bool has_issues; 29 | late bool has_projects; 30 | late bool has_wiki; 31 | late bool has_pages; 32 | late bool has_downloads; 33 | late String pushed_at; 34 | late String created_at; 35 | late String updated_at; 36 | Map? permissions; 37 | num? subscribers_count; 38 | Map? license; 39 | 40 | factory Repo.fromJson(Map json) => _$RepoFromJson(json); 41 | Map toJson() => _$RepoToJson(this); 42 | } 43 | -------------------------------------------------------------------------------- /macos/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(FLUTTER_BUILD_NAME) 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSMinimumSystemVersion 24 | $(MACOSX_DEPLOYMENT_TARGET) 25 | NSHumanReadableCopyright 26 | $(PRODUCT_COPYRIGHT) 27 | NSMainNibFile 28 | MainMenu 29 | NSPrincipalClass 30 | NSApplication 31 | 32 | 33 | -------------------------------------------------------------------------------- /gitme/lib/routes/language.dart: -------------------------------------------------------------------------------- 1 | import '../index.dart'; 2 | 3 | class LanguageRoute extends StatelessWidget { 4 | @override 5 | Widget build(BuildContext context) { 6 | var color = Theme.of(context).primaryColor; 7 | var localeModel = Provider.of(context); 8 | var gm = GmLocalizations.of(context); 9 | Widget _buildLanguageItem(String lan, value) { 10 | return ListTile( 11 | title: Text( 12 | lan, 13 | // 对APP当前语言进行高亮显示 14 | style: TextStyle(color: localeModel.locale == value ? color : null), 15 | ), 16 | trailing: 17 | localeModel.locale == value ? Icon(Icons.done, color: color) : null, 18 | onTap: () { 19 | // 此行代码会通知MaterialApp重新build 20 | localeModel.locale = value; 21 | }, 22 | ); 23 | } 24 | 25 | return Scaffold( 26 | appBar: AppBar( 27 | title: Text(gm.language), 28 | ), 29 | body: ListView( 30 | children: [ 31 | _buildLanguageItem("中文简体", "zh_CN"), 32 | _buildLanguageItem("English", "en_US"), 33 | _buildLanguageItem(gm.auto, null), 34 | ], 35 | ), 36 | ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /gitme/macos/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(FLUTTER_BUILD_NAME) 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSMinimumSystemVersion 24 | $(MACOSX_DEPLOYMENT_TARGET) 25 | NSHumanReadableCopyright 26 | $(PRODUCT_COPYRIGHT) 27 | NSMainNibFile 28 | MainMenu 29 | NSPrincipalClass 30 | NSApplication 31 | 32 | 33 | -------------------------------------------------------------------------------- /lib/chapter10/donewidget_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'done_widget.dart'; 3 | import '../common.dart'; 4 | 5 | class DoneWidgetTestRoute extends StatefulWidget { 6 | const DoneWidgetTestRoute({Key? key}) : super(key: key); 7 | 8 | @override 9 | State createState() => _DoneWidgetTestRouteState(); 10 | } 11 | 12 | class _DoneWidgetTestRouteState extends State { 13 | bool show = true; 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | return GestureDetector( 18 | behavior: HitTestBehavior.opaque, 19 | onTap: () { 20 | setState(() { 21 | show = !show; 22 | }); 23 | }, 24 | child: Center( 25 | child: Visibility( 26 | visible: show, 27 | child: Row( 28 | mainAxisSize: MainAxisSize.min, 29 | children: [ 30 | DoneWidget(outline: true), 31 | Padding( 32 | padding: const EdgeInsets.symmetric(horizontal: 12), 33 | child: Text("操作成功"), 34 | ), 35 | DoneWidget(), 36 | ], 37 | ), 38 | ), 39 | ), 40 | ); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /lib/chapter10/custom_paint.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import '../common.dart'; 3 | 4 | class CustomPaintRoute extends StatelessWidget { 5 | const CustomPaintRoute({Key? key}) : super(key: key); 6 | 7 | @override 8 | Widget build(BuildContext context) { 9 | return Center( 10 | child: Column( 11 | mainAxisSize: MainAxisSize.min, 12 | children: [ 13 | RepaintBoundary( 14 | child: CustomPaint( 15 | size: const Size(300, 300), //指定画布大小 16 | painter: MyPainter(), 17 | ), 18 | ), 19 | RepaintBoundary( 20 | child: ElevatedButton( 21 | onPressed: () {}, 22 | child: const Text("刷新"), 23 | )) 24 | ], 25 | ), 26 | ); 27 | } 28 | } 29 | 30 | class MyPainter extends CustomPainter { 31 | @override 32 | void paint(Canvas canvas, Size size) { 33 | print('paint'); 34 | var rect = Offset.zero & size; 35 | //画棋盘 36 | drawChessboard(canvas, rect); 37 | //画棋子 38 | drawPieces(canvas, rect); 39 | } 40 | 41 | // 在实际场景中正确使用此方法可以避免重绘开销,我们简单的返回false 42 | @override 43 | bool shouldRepaint(CustomPainter oldDelegate) => false; 44 | } 45 | -------------------------------------------------------------------------------- /lib/chapter6/sliver_persistent_header_tobox.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import '../common.dart'; 3 | 4 | class SliverPersistentHeaderToBoxRoute extends StatelessWidget { 5 | const SliverPersistentHeaderToBoxRoute({Key? key}) : super(key: key); 6 | 7 | @override 8 | Widget build(BuildContext context) { 9 | return CustomScrollView( 10 | slivers: [ 11 | buildSliverList(5), 12 | SliverPersistentHeaderToBox.builder(builder: headerBuilder), 13 | buildSliverList(5), 14 | SliverPersistentHeaderToBox(child: wTitle('Title 2')), 15 | buildSliverList(50), 16 | ], 17 | ); 18 | } 19 | 20 | // 当 header 固定后显示阴影 21 | Widget headerBuilder(context, maxExtent, fixed) { 22 | // 获取当前应用主题,关于主题相关内容将在后面章节介绍,现在 23 | // 我们要从主题中获取一些颜色 24 | var theme = Theme.of(context); 25 | return Material( 26 | child: Container( 27 | color: fixed ? Colors.white : theme.canvasColor, 28 | child: wTitle('Title 1'), 29 | ), 30 | elevation: fixed ? 4 : 0, 31 | shadowColor: theme.appBarTheme.shadowColor, 32 | ); 33 | } 34 | 35 | // 我们约定小写字母 w 开头的函数代表是需要构建一个 Widget,这比 buildXX 会更简洁 36 | Widget wTitle(String text) => 37 | ListTile(title: Text(text), onTap: () => print(text)); 38 | } 39 | -------------------------------------------------------------------------------- /gitme/jsons/repo.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 1296269, 3 | "node_id": "MDEwOlJlcG9zaXRvcnkxMjk2MjY5", 4 | "name": "Hello-World", 5 | "full_name": "octocat/Hello-World", 6 | "owner": "$commonUser", 7 | "parent?":"$repo", 8 | "private": false, 9 | "html_url": "https://github.com/octocat/Hello-World", 10 | "description?": "This your first repo!", 11 | "fork": false, 12 | "homepage?": "https://github.com", 13 | "language?": "JavaScript", 14 | "forks_count": 9, 15 | "stargazers_count": 80, 16 | "watchers_count": 80, 17 | "size": 108, 18 | "default_branch": "master", 19 | "open_issues_count": 0, 20 | "topics?": [ 21 | "octocat", 22 | "atom", 23 | "electron", 24 | "API" 25 | ], 26 | "has_issues": true, 27 | "has_projects": true, 28 | "has_wiki": true, 29 | "has_pages": false, 30 | "has_downloads": true, 31 | "pushed_at": "2011-01-26T19:06:43Z", 32 | "created_at": "2011-01-26T19:01:12Z", 33 | "updated_at": "2011-01-26T19:14:43Z", 34 | "permissions?": { 35 | "admin": false, 36 | "push": false, 37 | "pull": true 38 | }, 39 | "subscribers_count?": 42, 40 | "license?": { 41 | "key": "mit", 42 | "name": "MIT License", 43 | "spdx_id": "MIT", 44 | "url": "https://api.github.com/licenses/mit", 45 | "node_id": "MDc6TGljZW5zZW1pdA==" 46 | } 47 | } -------------------------------------------------------------------------------- /lib/chapter10/gradient_button.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import '../widgets/index.dart'; 3 | 4 | class GradientButtonRoute extends StatefulWidget { 5 | const GradientButtonRoute({Key? key}) : super(key: key); 6 | 7 | @override 8 | _GradientButtonRouteState createState() => _GradientButtonRouteState(); 9 | } 10 | 11 | class _GradientButtonRouteState extends State { 12 | @override 13 | Widget build(BuildContext context) { 14 | return Column( 15 | mainAxisSize: MainAxisSize.min, 16 | children: [ 17 | GradientButton( 18 | colors: const [Colors.orange, Colors.red], 19 | height: 50.0, 20 | child: const Text("Submit"), 21 | onPressed: onTap, 22 | ), 23 | GradientButton( 24 | height: 50.0, 25 | colors: [Colors.lightGreen, Colors.green.shade700], 26 | child: const Text("Submit"), 27 | onPressed: onTap, 28 | ), 29 | GradientButton( 30 | height: 50.0, 31 | //borderRadius: const BorderRadius.all(Radius.circular(5)), 32 | colors: [Colors.lightBlue.shade300, Colors.blueAccent], 33 | child: const Text("Submit"), 34 | onPressed: onTap, 35 | ), 36 | ], 37 | ); 38 | } 39 | onTap() { 40 | print("button click"); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /lib/chapter14/repaintboundary.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import '../common.dart'; 3 | 4 | class RepaintBoundaryTest extends StatefulWidget { 5 | const RepaintBoundaryTest({Key? key}) : super(key: key); 6 | 7 | @override 8 | _RepaintBoundaryTestState createState() => _RepaintBoundaryTestState(); 9 | } 10 | 11 | class _RepaintBoundaryTestState extends State { 12 | @override 13 | Widget build(BuildContext context) { 14 | return Column( 15 | children: [ 16 | RepaintBoundary( 17 | child: CustomPaint( 18 | size: const Size(50, 50), 19 | painter: OutlinePainter(), 20 | ), 21 | ), 22 | ElevatedButton( 23 | onPressed: () => setState(() {}), 24 | child: const Text("setState"), 25 | ) 26 | ], 27 | ); 28 | } 29 | } 30 | 31 | class OutlinePainter extends CustomPainter { 32 | @override 33 | void paint(Canvas canvas, Size size) { 34 | print("paint"); 35 | var paint = Paint() 36 | ..strokeWidth = 2 37 | ..style = PaintingStyle.stroke 38 | ..color = Colors.black; 39 | canvas.drawRect(Offset.zero & size, paint); 40 | } 41 | 42 | // 本例中,rebuild时,painter会重新构建一个新实例,返回false, 43 | // 表示即使Painter实例发生变化也不需要重新绘制。 44 | @override 45 | bool shouldRepaint(covariant CustomPainter oldDelegate) => true; 46 | } 47 | -------------------------------------------------------------------------------- /lib/widgets/translate_with_expanded_painting_area.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/widgets.dart'; 2 | 3 | class TranslateWithExpandedPaintingArea extends StatelessWidget { 4 | const TranslateWithExpandedPaintingArea({ 5 | Key? key, 6 | required this.offset, 7 | this.clipBehavior = Clip.none, 8 | this.child, 9 | }) : super(key: key); 10 | final Widget? child; 11 | final Offset offset; 12 | final Clip clipBehavior; 13 | 14 | @override 15 | Widget build(BuildContext context) { 16 | return LayoutBuilder( 17 | builder: (context, constraints) { 18 | final dx = offset.dx.abs(); 19 | final dy = offset.dy.abs(); 20 | 21 | Widget widget = OverflowBox( 22 | //平移多少,则子组件相应轴的长度增加多少 23 | minWidth: constraints.minWidth + dx, 24 | maxWidth: constraints.maxWidth + dx, 25 | minHeight: constraints.minHeight + dy, 26 | maxHeight: constraints.maxHeight + dy, 27 | alignment: Alignment( 28 | // 不同方向的平移,要指定不同的对齐方式 29 | offset.dx <= 0 ? 1 : -1, 30 | offset.dy <= 0 ? 1 : -1, 31 | ), 32 | child: child, 33 | ); 34 | //超出组件布局空间的部分要剪裁掉 35 | if (clipBehavior != Clip.none) { 36 | widget = ClipRect(clipBehavior: clipBehavior, child: widget); 37 | } 38 | return widget; 39 | }, 40 | ); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /lib/chapter8/pointer.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart' hide Page; 2 | import '../common.dart'; 3 | 4 | class PointerRoute extends StatelessWidget { 5 | const PointerRoute({Key? key}) : super(key: key); 6 | 7 | @override 8 | Widget build(BuildContext context) { 9 | return ListPage(children: [Page('显示移动偏移', const PointerMoveIndicator())]); 10 | } 11 | } 12 | 13 | class PointerMoveIndicator extends StatefulWidget { 14 | const PointerMoveIndicator({Key? key}) : super(key: key); 15 | 16 | @override 17 | _PointerMoveIndicatorState createState() => _PointerMoveIndicatorState(); 18 | } 19 | 20 | class _PointerMoveIndicatorState extends State { 21 | PointerEvent? _event; 22 | 23 | 24 | @override 25 | Widget build(BuildContext context) { 26 | return Listener( 27 | child: Container( 28 | alignment: Alignment.center, 29 | color: Colors.blue, 30 | width: 300.0, 31 | height: 150.0, 32 | child: Text( 33 | '${_event?.localPosition ?? ''}', 34 | style: const TextStyle(color: Colors.white), 35 | ), 36 | ), 37 | onPointerDown: (PointerDownEvent event) => setState(() => _event = event), 38 | onPointerMove: (PointerMoveEvent event) => setState(() => _event = event), 39 | onPointerUp: (PointerUpEvent event) => setState(() => _event = event), 40 | ); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /lib/chapter9/scale_animation_animatedbuilder.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class ScaleAnimationRoute2 extends StatefulWidget { 4 | const ScaleAnimationRoute2({Key? key}) : super(key: key); 5 | 6 | @override 7 | _ScaleAnimationRouteState createState() => _ScaleAnimationRouteState(); 8 | } 9 | 10 | class _ScaleAnimationRouteState extends State 11 | with SingleTickerProviderStateMixin { 12 | late Animation animation; 13 | late AnimationController controller; 14 | 15 | @override 16 | initState() { 17 | super.initState(); 18 | controller = AnimationController( 19 | duration: const Duration(seconds: 2), vsync: this); 20 | //图片宽高从0变到300 21 | animation = Tween(begin: 0.0, end: 300.0).animate(controller); 22 | //启动动画 23 | controller.forward(); 24 | } 25 | 26 | @override 27 | Widget build(BuildContext context) { 28 | return AnimatedBuilder( 29 | animation: animation, 30 | child: Image.asset("imgs/avatar.png"), 31 | builder: (BuildContext ctx, child) { 32 | return Center( 33 | child: SizedBox( 34 | height: animation.value, 35 | width: animation.value, 36 | child: child, 37 | ), 38 | ); 39 | }, 40 | ); 41 | } 42 | 43 | @override 44 | dispose() { 45 | //路由销毁时需要释放动画资源 46 | controller.dispose(); 47 | super.dispose(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /lib/chapter13/webview.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:webview_flutter/webview_flutter.dart'; 3 | 4 | class WebViewTest extends StatefulWidget { 5 | const WebViewTest({Key? key}) : super(key: key); 6 | 7 | @override 8 | State createState() => _WebViewTestState(); 9 | } 10 | 11 | class _WebViewTestState extends State { 12 | late WebViewController _controller; 13 | 14 | @override 15 | Widget build(BuildContext context) { 16 | return Scaffold( 17 | body: WebView( 18 | initialUrl: 'https://m.baidu.com', 19 | onWebViewCreated: (controller) => _controller = controller, 20 | onProgress: (progress) => print(progress), 21 | onPageStarted: (url) => print('start loading: $url'), 22 | onPageFinished: (url) => print('load finished:$url'), 23 | onWebResourceError: (err)=>print(err.description), 24 | javascriptChannels: { 25 | _toasterJavascriptChannel(context), 26 | }, 27 | ), 28 | ); 29 | } 30 | 31 | JavascriptChannel _toasterJavascriptChannel(BuildContext context) { 32 | return JavascriptChannel( 33 | name: 'Toaster', 34 | onMessageReceived: (JavascriptMessage message) { 35 | // ignore: deprecated_member_use 36 | Scaffold.of(context).showSnackBar( 37 | SnackBar(content: Text(message.message)), 38 | ); 39 | }, 40 | ); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | # platform :ios, '9.0' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | project 'Runner', { 8 | 'Debug' => :debug, 9 | 'Profile' => :release, 10 | 'Release' => :release, 11 | } 12 | 13 | def flutter_root 14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) 15 | unless File.exist?(generated_xcode_build_settings_path) 16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" 17 | end 18 | 19 | File.foreach(generated_xcode_build_settings_path) do |line| 20 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 21 | return matches[1].strip if matches 22 | end 23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" 24 | end 25 | 26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 27 | 28 | flutter_ios_podfile_setup 29 | 30 | target 'Runner' do 31 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) 32 | end 33 | 34 | post_install do |installer| 35 | installer.pods_project.targets.each do |target| 36 | flutter_additional_ios_build_settings(target) 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /lib/chapter8/pointer_down_listener.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/rendering.dart'; 2 | import 'package:flutter/widgets.dart'; 3 | 4 | class PointerDownListener extends SingleChildRenderObjectWidget { 5 | const PointerDownListener({Key? key, this.onPointerDown, Widget? child}) 6 | : super(key: key, child: child); 7 | 8 | final PointerDownEventListener? onPointerDown; 9 | 10 | @override 11 | RenderObject createRenderObject(BuildContext context) => 12 | RenderPointerDownListener()..onPointerDown = onPointerDown; 13 | 14 | @override 15 | void updateRenderObject( 16 | BuildContext context, RenderPointerDownListener renderObject) { 17 | renderObject.onPointerDown = onPointerDown; 18 | } 19 | } 20 | 21 | class RenderPointerDownListener extends RenderProxyBox { 22 | PointerDownEventListener? onPointerDown; 23 | 24 | @override 25 | bool hitTestSelf(Offset position) => true; //始终通过命中测试 26 | 27 | @override 28 | void handleEvent(PointerEvent event, covariant HitTestEntry entry) { 29 | //事件分发时处理事件 30 | if (event is PointerDownEvent) onPointerDown?.call(event); 31 | } 32 | } 33 | 34 | class PointerDownListenerRoute extends StatelessWidget { 35 | const PointerDownListenerRoute({Key? key}) : super(key: key); 36 | 37 | @override 38 | Widget build(BuildContext context) { 39 | return PointerDownListener( 40 | child: const Text('Click me'), 41 | onPointerDown: (e) => print('down'), 42 | ); 43 | } 44 | } 45 | 46 | -------------------------------------------------------------------------------- /gitme/ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | # platform :ios, '9.0' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | project 'Runner', { 8 | 'Debug' => :debug, 9 | 'Profile' => :release, 10 | 'Release' => :release, 11 | } 12 | 13 | def flutter_root 14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) 15 | unless File.exist?(generated_xcode_build_settings_path) 16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" 17 | end 18 | 19 | File.foreach(generated_xcode_build_settings_path) do |line| 20 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 21 | return matches[1].strip if matches 22 | end 23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" 24 | end 25 | 26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 27 | 28 | flutter_ios_podfile_setup 29 | 30 | target 'Runner' do 31 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) 32 | end 33 | 34 | post_install do |installer| 35 | installer.pods_project.targets.each do |target| 36 | flutter_additional_ios_build_settings(target) 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /lib/chapter6/custom_pull_refresh.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import '../common.dart'; 3 | 4 | class PullRefreshBoxRoute extends StatefulWidget { 5 | const PullRefreshBoxRoute({Key? key}) : super(key: key); 6 | 7 | @override 8 | State createState() => _PullRefreshBoxRouteState(); 9 | } 10 | 11 | class _PullRefreshBoxRouteState extends State { 12 | int _itemCount = 5; 13 | 14 | @override 15 | Widget build(BuildContext context) { 16 | return PullRefreshScope( 17 | child: CustomScrollView( 18 | physics: const BouncingScrollPhysics( 19 | parent: AlwaysScrollableScrollPhysics()), 20 | slivers: [ 21 | SliverPullRefreshIndicator( 22 | refreshTriggerPullDistance: 100.0, 23 | refreshIndicatorExtent: 60.0, 24 | onRefresh: () async { 25 | await Future.delayed(const Duration(seconds: 2)); 26 | setState(() => _itemCount += 10); 27 | }, 28 | ), 29 | SliverFixedExtentList( 30 | itemExtent: 50, 31 | delegate: SliverChildBuilderDelegate( 32 | (context, index) { 33 | return ListTile( 34 | title: Text('$index'), onTap: () => print(index)); 35 | }, 36 | childCount: _itemCount, 37 | ), 38 | ), 39 | ], 40 | ), 41 | ); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /lib/widgets/after_layout.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/rendering.dart'; 2 | import 'package:flutter/scheduler.dart'; 3 | import 'package:flutter/widgets.dart'; 4 | 5 | class AfterLayout extends SingleChildRenderObjectWidget { 6 | const AfterLayout({ 7 | Key? key, 8 | required this.callback, 9 | Widget? child, 10 | }) : super(key: key, child: child); 11 | 12 | @override 13 | RenderObject createRenderObject(BuildContext context) { 14 | return RenderAfterLayout(callback); 15 | } 16 | 17 | @override 18 | void updateRenderObject( 19 | BuildContext context, RenderAfterLayout renderObject) { 20 | renderObject.callback = callback; 21 | } 22 | /// [callback] will be triggered after the layout phase ends. 23 | final ValueSetter callback; 24 | } 25 | 26 | class RenderAfterLayout extends RenderProxyBox { 27 | RenderAfterLayout(this.callback); 28 | 29 | ValueSetter callback; 30 | 31 | @override 32 | void performLayout() { 33 | super.performLayout(); 34 | // 不能直接回调callback,原因是当前组件布局完成后可能还有其它组件未完成布局 35 | // 如果callback中又触发了UI更新(比如调用了 setState)则会报错。因此,我们 36 | // 在 frame 结束的时候再去触发回调。 37 | // callback(this); 38 | SchedulerBinding.instance 39 | .addPostFrameCallback((timeStamp) => callback(this)); 40 | 41 | } 42 | 43 | /// 组件在在屏幕坐标中的起始偏移坐标 44 | Offset get offset => localToGlobal(Offset.zero); 45 | /// 组件在屏幕上占有的矩形空间区域 46 | Rect get rect => offset & size; 47 | } 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /macos/Podfile: -------------------------------------------------------------------------------- 1 | platform :osx, '10.11' 2 | 3 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 4 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 5 | 6 | project 'Runner', { 7 | 'Debug' => :debug, 8 | 'Profile' => :release, 9 | 'Release' => :release, 10 | } 11 | 12 | def flutter_root 13 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) 14 | unless File.exist?(generated_xcode_build_settings_path) 15 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" 16 | end 17 | 18 | File.foreach(generated_xcode_build_settings_path) do |line| 19 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 20 | return matches[1].strip if matches 21 | end 22 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" 23 | end 24 | 25 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 26 | 27 | flutter_macos_podfile_setup 28 | 29 | target 'Runner' do 30 | use_frameworks! 31 | use_modular_headers! 32 | 33 | flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) 34 | end 35 | 36 | post_install do |installer| 37 | installer.pods_project.targets.each do |target| 38 | flutter_additional_macos_build_settings(target) 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /gitme/macos/Podfile: -------------------------------------------------------------------------------- 1 | platform :osx, '10.11' 2 | 3 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 4 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 5 | 6 | project 'Runner', { 7 | 'Debug' => :debug, 8 | 'Profile' => :release, 9 | 'Release' => :release, 10 | } 11 | 12 | def flutter_root 13 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) 14 | unless File.exist?(generated_xcode_build_settings_path) 15 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" 16 | end 17 | 18 | File.foreach(generated_xcode_build_settings_path) do |line| 19 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 20 | return matches[1].strip if matches 21 | end 22 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" 23 | end 24 | 25 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 26 | 27 | flutter_macos_podfile_setup 28 | 29 | target 'Runner' do 30 | use_frameworks! 31 | use_modular_headers! 32 | 33 | flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) 34 | end 35 | 36 | post_install do |installer| 37 | installer.pods_project.targets.each do |target| 38 | flutter_additional_macos_build_settings(target) 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /lib/chapter9/animated_switcher_counter.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class AnimatedSwitcherCounterRoute extends StatefulWidget { 4 | const AnimatedSwitcherCounterRoute({Key? key}) : super(key: key); 5 | 6 | @override 7 | _AnimatedSwitcherCounterRouteState createState() => 8 | _AnimatedSwitcherCounterRouteState(); 9 | } 10 | 11 | class _AnimatedSwitcherCounterRouteState 12 | extends State { 13 | int _count = 0; 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | return Center( 18 | child: Column( 19 | mainAxisSize: MainAxisSize.min, 20 | children: [ 21 | AnimatedSwitcher( 22 | duration: const Duration(milliseconds: 400), 23 | transitionBuilder: (Widget child, Animation animation) { 24 | return ScaleTransition(child: child, scale: animation); 25 | }, 26 | child: Text( 27 | '$_count', 28 | //显示指定key,不同的key会被认为是不同的Text,这样才能执行动画 29 | key: ValueKey(_count), 30 | style: Theme.of(context).textTheme.headline4, 31 | ), 32 | ), 33 | ElevatedButton( 34 | child: const Text( 35 | '+1', 36 | ), 37 | onPressed: () { 38 | setState(() { 39 | _count += 1; 40 | }); 41 | }, 42 | ), 43 | ], 44 | ), 45 | ); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /gitme/lib/common/global.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:shared_preferences/shared_preferences.dart'; 4 | import '../index.dart'; 5 | 6 | // 提供四套可选主题色 7 | const _themes = [ 8 | Colors.blue, 9 | Colors.cyan, 10 | Colors.teal, 11 | Colors.green, 12 | Colors.red, 13 | ]; 14 | 15 | class Global { 16 | static late SharedPreferences _prefs; 17 | static Profile profile = Profile(); 18 | // 网络缓存对象 19 | static NetCache netCache = NetCache(); 20 | 21 | // 可选的主题列表 22 | static List get themes => _themes; 23 | 24 | // 是否为release版 25 | static bool get isRelease => bool.fromEnvironment("dart.vm.product"); 26 | 27 | //初始化全局信息 28 | static Future init() async { 29 | WidgetsFlutterBinding.ensureInitialized(); 30 | _prefs = await SharedPreferences.getInstance(); 31 | var _profile = _prefs.getString("profile"); 32 | if (_profile != null) { 33 | try { 34 | profile = Profile.fromJson(jsonDecode(_profile)); 35 | } catch (e) { 36 | print(e); 37 | } 38 | }else{ 39 | // 默认主题索引为0,代表蓝色 40 | profile= Profile()..theme=0; 41 | } 42 | 43 | // 如果没有缓存策略,设置默认缓存策略 44 | profile.cache = profile.cache ?? CacheConfig() 45 | ..enable = true 46 | ..maxAge = 3600 47 | ..maxCount = 100; 48 | 49 | //初始化网络请求相关配置 50 | Git.init(); 51 | } 52 | 53 | // 持久化Profile信息 54 | static saveProfile() => 55 | _prefs.setString("profile", jsonEncode(profile.toJson())); 56 | } 57 | -------------------------------------------------------------------------------- /lib/chapter10/turn_box.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import '../widgets/index.dart'; 3 | 4 | class TurnBoxRoute extends StatefulWidget { 5 | const TurnBoxRoute({Key? key}) : super(key: key); 6 | 7 | @override 8 | _TurnBoxRouteState createState() => _TurnBoxRouteState(); 9 | } 10 | 11 | class _TurnBoxRouteState extends State { 12 | double _turns = .0; 13 | 14 | @override 15 | Widget build(BuildContext context) { 16 | return Center( 17 | child: Column( 18 | mainAxisSize: MainAxisSize.min, 19 | children: [ 20 | TurnBox( 21 | turns: _turns, 22 | speed: 500, 23 | child: const Icon( 24 | Icons.refresh, 25 | size: 50, 26 | ), 27 | ), 28 | TurnBox( 29 | turns: _turns, 30 | speed: 1000, 31 | child: const Icon( 32 | Icons.refresh, 33 | size: 150.0, 34 | ), 35 | ), 36 | ElevatedButton( 37 | child: const Text("顺时针旋转1/5圈"), 38 | onPressed: () { 39 | setState(() { 40 | _turns += .2; 41 | }); 42 | }, 43 | ), 44 | ElevatedButton( 45 | child: const Text("逆时针旋转1/5圈"), 46 | onPressed: () { 47 | setState(() { 48 | _turns -= .2; 49 | }); 50 | }, 51 | ) 52 | ], 53 | ), 54 | ); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /lib/chapter6/infinite_gridview.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class InfiniteGridView extends StatefulWidget { 4 | const InfiniteGridView({Key? key}) : super(key: key); 5 | 6 | @override 7 | _InfiniteGridViewState createState() => _InfiniteGridViewState(); 8 | } 9 | 10 | class _InfiniteGridViewState extends State { 11 | final List _icons = []; //保存Icon数据 12 | 13 | @override 14 | void initState() { 15 | super.initState(); 16 | // 初始化数据 17 | _retrieveIcons(); 18 | } 19 | 20 | @override 21 | Widget build(BuildContext context) { 22 | return GridView.builder( 23 | gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( 24 | crossAxisCount: 3, //每行三列 25 | childAspectRatio: 1.0, //显示区域宽高相等 26 | ), 27 | itemCount: _icons.length, 28 | itemBuilder: (context, index) { 29 | //如果显示到最后一个并且Icon总数小于200时继续获取数据 30 | if (index == _icons.length - 1 && _icons.length < 200) { 31 | _retrieveIcons(); 32 | } 33 | return Icon(_icons[index]); 34 | }, 35 | ); 36 | } 37 | 38 | //模拟异步获取数据 39 | void _retrieveIcons() { 40 | Future.delayed(const Duration(milliseconds: 200)).then((e) { 41 | setState(() { 42 | _icons.addAll([ 43 | Icons.ac_unit, 44 | Icons.airport_shuttle, 45 | Icons.all_inclusive, 46 | Icons.beach_access, 47 | Icons.cake, 48 | Icons.free_breakfast, 49 | ]); 50 | }); 51 | }); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /gitme/macos/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - FlutterMacOS (1.0.0) 3 | - FMDB (2.7.5): 4 | - FMDB/standard (= 2.7.5) 5 | - FMDB/standard (2.7.5) 6 | - path_provider_macos (0.0.1): 7 | - FlutterMacOS 8 | - shared_preferences_macos (0.0.1): 9 | - FlutterMacOS 10 | - sqflite (0.0.2): 11 | - FlutterMacOS 12 | - FMDB (>= 2.7.5) 13 | 14 | DEPENDENCIES: 15 | - FlutterMacOS (from `Flutter/ephemeral`) 16 | - path_provider_macos (from `Flutter/ephemeral/.symlinks/plugins/path_provider_macos/macos`) 17 | - shared_preferences_macos (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_macos/macos`) 18 | - sqflite (from `Flutter/ephemeral/.symlinks/plugins/sqflite/macos`) 19 | 20 | SPEC REPOS: 21 | trunk: 22 | - FMDB 23 | 24 | EXTERNAL SOURCES: 25 | FlutterMacOS: 26 | :path: Flutter/ephemeral 27 | path_provider_macos: 28 | :path: Flutter/ephemeral/.symlinks/plugins/path_provider_macos/macos 29 | shared_preferences_macos: 30 | :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_macos/macos 31 | sqflite: 32 | :path: Flutter/ephemeral/.symlinks/plugins/sqflite/macos 33 | 34 | SPEC CHECKSUMS: 35 | FlutterMacOS: 57701585bf7de1b3fc2bb61f6378d73bbdea8424 36 | FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a 37 | path_provider_macos: 160cab0d5461f0c0e02995469a98f24bdb9a3f1f 38 | shared_preferences_macos: 480ce071d0666e37cef23fe6c702293a3d21799e 39 | sqflite: a5789cceda41d54d23f31d6de539d65bb14100ea 40 | 41 | PODFILE CHECKSUM: 6eac6b3292e5142cfc23bdeb71848a40ec51c14c 42 | 43 | COCOAPODS: 1.10.2 44 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # This file configures the analyzer, which statically analyzes Dart code to 2 | # check for errors, warnings, and lints. 3 | # 4 | # The issues identified by the analyzer are surfaced in the UI of Dart-enabled 5 | # IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be 6 | # invoked from the command line by running `flutter analyze`. 7 | 8 | # The following line activates a set of recommended lints for Flutter apps, 9 | # packages, and plugins designed to encourage good coding practices. 10 | include: package:flutter_lints/flutter.yaml 11 | 12 | linter: 13 | # The lint rules applied to this project can be customized in the 14 | # section below to disable rules from the `package:flutter_lints/flutter.yaml` 15 | # included above or to enable additional rules. A list of all available lints 16 | # and their documentation is published at 17 | # https://dart-lang.github.io/linter/lints/index.html. 18 | # 19 | # Instead of disabling a lint rule for the entire project in the 20 | # section below, it can also be suppressed for a single line of code 21 | # or a specific dart file by using the `// ignore: name_of_lint` and 22 | # `// ignore_for_file: name_of_lint` syntax on the line or in the file 23 | # producing the lint. 24 | rules: 25 | avoid_print: false # Uncomment to disable the `avoid_print` rule 26 | # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule 27 | 28 | # Additional information about this file can be found at 29 | # https://dart.dev/guides/language/analysis-options 30 | -------------------------------------------------------------------------------- /lib/chapter2/2.2/router.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class RouterTestRoute extends StatelessWidget { 4 | const RouterTestRoute({Key? key}) : super(key: key); 5 | 6 | @override 7 | Widget build(BuildContext context) { 8 | return Center( 9 | child: ElevatedButton( 10 | child: const Text("打开提示页"), 11 | onPressed: () async { 12 | var result = await Navigator.push( 13 | context, 14 | MaterialPageRoute( 15 | builder: (context) { 16 | return const TipRoute( 17 | text: "我是提示xxxx", 18 | ); 19 | }, 20 | ), 21 | ); 22 | print("路由返回值: $result"); 23 | }, 24 | ), 25 | ); 26 | } 27 | } 28 | 29 | class TipRoute extends StatelessWidget { 30 | const TipRoute({ 31 | Key? key, 32 | required this.text, // 接收一个text参数 33 | }) : super(key: key); 34 | final String text; 35 | 36 | @override 37 | Widget build(BuildContext context) { 38 | return Scaffold( 39 | appBar: AppBar( 40 | title: const Text("提示"), 41 | ), 42 | body: Padding( 43 | padding: const EdgeInsets.all(18), 44 | child: Center( 45 | child: Column( 46 | children: [ 47 | Text(text), 48 | ElevatedButton( 49 | onPressed: () => Navigator.pop(context, "我是返回值"), 50 | child: const Text("返回"), 51 | ) 52 | ], 53 | ), 54 | ), 55 | ), 56 | ); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /gitme/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # This file configures the analyzer, which statically analyzes Dart code to 2 | # check for errors, warnings, and lints. 3 | # 4 | # The issues identified by the analyzer are surfaced in the UI of Dart-enabled 5 | # IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be 6 | # invoked from the command line by running `flutter analyze`. 7 | 8 | # The following line activates a set of recommended lints for Flutter apps, 9 | # packages, and plugins designed to encourage good coding practices. 10 | include: package:flutter_lints/flutter.yaml 11 | analyzer: 12 | exclude: [lib/models,lib/common/third] 13 | 14 | linter: 15 | # The lint rules applied to this project can be customized in the 16 | # section below to disable rules from the `package:flutter_lints/flutter.yaml` 17 | # included above or to enable additional rules. A list of all available lints 18 | # and their documentation is published at 19 | # https://dart-lang.github.io/linter/lints/index.html. 20 | # 21 | # Instead of disabling a lint rule for the entire project in the 22 | # section below, it can also be suppressed for a single line of code 23 | # or a specific dart file by using the `// ignore: name_of_lint` and 24 | # `// ignore_for_file: name_of_lint` syntax on the line or in the file 25 | # producing the lint. 26 | rules: 27 | avoid_print: false # Uncomment to disable the `avoid_print` rule 28 | # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule 29 | 30 | # Additional information about this file can be found at 31 | # https://dart.dev/guides/language/analysis-options 32 | -------------------------------------------------------------------------------- /lib/chapter10/custom_checkbox_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import 'custom_checkbox.dart'; 4 | import 'custom_checkbox_2.dart'; 5 | 6 | class CustomCheckboxTest extends StatefulWidget { 7 | const CustomCheckboxTest({Key? key}) : super(key: key); 8 | 9 | @override 10 | State createState() => _CustomCheckboxTestState(); 11 | } 12 | 13 | class _CustomCheckboxTestState extends State { 14 | bool _checked = false; 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | return Center( 19 | child: Column(mainAxisAlignment: MainAxisAlignment.center, 20 | children: [ 21 | CustomCheckbox2( 22 | value: _checked, 23 | onChanged: _onChange, 24 | ), 25 | Padding( 26 | padding: const EdgeInsets.all(18.0), 27 | child: SizedBox( 28 | width: 16, 29 | height: 16, 30 | child: CustomCheckbox( 31 | strokeWidth: 1, 32 | radius: 1, 33 | value: _checked, 34 | onChanged: _onChange, 35 | ), 36 | ), 37 | ), 38 | SizedBox( 39 | width: 30, 40 | height: 30, 41 | child: CustomCheckbox( 42 | strokeWidth: 3, 43 | radius: 3, 44 | value: _checked, 45 | onChanged: _onChange, 46 | ), 47 | ), 48 | ], 49 | ), 50 | ); 51 | } 52 | 53 | void _onChange(value) { 54 | setState(() => _checked = value); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /lib/chapter14/state_change_update_flow.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter/scheduler.dart'; 3 | 4 | class StateChangeTest extends StatefulWidget { 5 | const StateChangeTest({Key? key}) : super(key: key); 6 | 7 | @override 8 | _StateChangeTestState createState() => _StateChangeTestState(); 9 | } 10 | 11 | class _StateChangeTestState extends State { 12 | int index = 0; 13 | 14 | void update(VoidCallback fn) { 15 | final schedulerPhase = SchedulerBinding.instance.schedulerPhase; 16 | if (schedulerPhase == SchedulerPhase.persistentCallbacks) { 17 | SchedulerBinding.instance.addPostFrameCallback((_) { 18 | setState(fn); 19 | }); 20 | } else { 21 | setState(fn); 22 | } 23 | // if (schedulerPhase == SchedulerPhase.idle || 24 | // schedulerPhase == SchedulerPhase.postFrameCallbacks) { 25 | // setState(fn); 26 | // } else { 27 | // SchedulerBinding.instance.addPostFrameCallback((_) { 28 | // setState(fn); 29 | // }); 30 | // } 31 | } 32 | 33 | @override 34 | Widget build(BuildContext context) { 35 | // 下面代码不会报错,因为在build时当前组件的dirty为true,而setState中 36 | // 会先判断当前dirty值,如果为true会直接返回 37 | setState(() { 38 | ++index; 39 | }); 40 | return Text('$index'); 41 | // //build阶段不能调用setState 42 | // return LayoutBuilder( 43 | // builder: (context, c) { 44 | // print(SchedulerBinding.instance.schedulerPhase); 45 | // setState(() { 46 | // ++index; 47 | // }); 48 | // return Text('xx'); 49 | // }, 50 | // ); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "16x16", 5 | "idiom" : "mac", 6 | "filename" : "app_icon_16.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "size" : "16x16", 11 | "idiom" : "mac", 12 | "filename" : "app_icon_32.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "32x32", 17 | "idiom" : "mac", 18 | "filename" : "app_icon_32.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "32x32", 23 | "idiom" : "mac", 24 | "filename" : "app_icon_64.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "128x128", 29 | "idiom" : "mac", 30 | "filename" : "app_icon_128.png", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "size" : "128x128", 35 | "idiom" : "mac", 36 | "filename" : "app_icon_256.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "256x256", 41 | "idiom" : "mac", 42 | "filename" : "app_icon_256.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "256x256", 47 | "idiom" : "mac", 48 | "filename" : "app_icon_512.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "512x512", 53 | "idiom" : "mac", 54 | "filename" : "app_icon_512.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "512x512", 59 | "idiom" : "mac", 60 | "filename" : "app_icon_1024.png", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /gitme/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "16x16", 5 | "idiom" : "mac", 6 | "filename" : "app_icon_16.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "size" : "16x16", 11 | "idiom" : "mac", 12 | "filename" : "app_icon_32.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "32x32", 17 | "idiom" : "mac", 18 | "filename" : "app_icon_32.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "32x32", 23 | "idiom" : "mac", 24 | "filename" : "app_icon_64.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "128x128", 29 | "idiom" : "mac", 30 | "filename" : "app_icon_128.png", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "size" : "128x128", 35 | "idiom" : "mac", 36 | "filename" : "app_icon_256.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "256x256", 41 | "idiom" : "mac", 42 | "filename" : "app_icon_256.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "256x256", 47 | "idiom" : "mac", 48 | "filename" : "app_icon_512.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "512x512", 53 | "idiom" : "mac", 54 | "filename" : "app_icon_512.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "512x512", 59 | "idiom" : "mac", 60 | "filename" : "app_icon_1024.png", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /lib/chapter9/scale_animation_animatedwidget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class AnimatedImage extends AnimatedWidget { 4 | const AnimatedImage({ 5 | Key? key, 6 | required Animation animation, 7 | }) : super(key: key, listenable: animation); 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | final animation = listenable as Animation; 12 | return Center( 13 | child: Image.asset( 14 | "imgs/avatar.png", 15 | width: animation.value, 16 | height: animation.value, 17 | ), 18 | ); 19 | } 20 | } 21 | 22 | class ScaleAnimationRoute1 extends StatefulWidget { 23 | const ScaleAnimationRoute1({Key? key}) : super(key: key); 24 | 25 | @override 26 | _ScaleAnimationRouteState createState() => _ScaleAnimationRouteState(); 27 | } 28 | 29 | class _ScaleAnimationRouteState extends State 30 | with SingleTickerProviderStateMixin { 31 | late Animation animation; 32 | late AnimationController controller; 33 | 34 | @override 35 | initState() { 36 | super.initState(); 37 | controller = AnimationController( 38 | duration: const Duration(seconds: 2), vsync: this); 39 | //图片宽高从0变到300 40 | animation = Tween(begin: 0.0, end: 300.0).animate(controller); 41 | //启动动画 42 | controller.forward(); 43 | } 44 | 45 | @override 46 | Widget build(BuildContext context) { 47 | return AnimatedImage( 48 | animation: animation, 49 | ); 50 | } 51 | 52 | @override 53 | dispose() { 54 | //路由销毁时需要释放动画资源 55 | controller.dispose(); 56 | super.dispose(); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /lib/chapter3/button.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class ButtonRoute extends StatefulWidget { 4 | const ButtonRoute({Key? key}) : super(key: key); 5 | 6 | @override 7 | _ButtonRouteState createState() => _ButtonRouteState(); 8 | } 9 | 10 | class _ButtonRouteState extends State { 11 | @override 12 | Widget build(BuildContext context) { 13 | return Column( 14 | children: [ 15 | ElevatedButton( 16 | child: const Text("normal"), 17 | onPressed: () => {}, 18 | ), 19 | OutlinedButton( 20 | child: const Text("normal"), 21 | onPressed: () => {}, 22 | ), 23 | IconButton( 24 | icon: const Icon(Icons.thumb_up), 25 | onPressed: () => {}, 26 | ), 27 | TextButton( 28 | child: const Text("Submit"), 29 | onPressed: () => {}, 30 | ), 31 | ElevatedButton.icon( 32 | icon: const Icon(Icons.send), 33 | label: const Text("发送"), 34 | onPressed: _onPressed, 35 | ), 36 | OutlinedButton.icon( 37 | icon: const Icon(Icons.add), 38 | label: const Text("添加"), 39 | onPressed: _onPressed, 40 | ), 41 | TextButton.icon( 42 | icon: const Icon(Icons.info), 43 | label: const Text("详情"), 44 | onPressed: _onPressed, 45 | ), 46 | ] 47 | .map( 48 | (e) => Padding(child: e, padding: const EdgeInsets.only(top: 20))) 49 | .toList(), 50 | ); 51 | } 52 | 53 | void _onPressed() { 54 | print("button pressed"); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /lib/chapter5/decoratedbox.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class DecoratedBoxRoute extends StatelessWidget { 4 | const DecoratedBoxRoute({Key? key}) : super(key: key); 5 | 6 | @override 7 | Widget build(BuildContext context) { 8 | return Column( 9 | mainAxisSize: MainAxisSize.min, 10 | children: [ 11 | DecoratedBox( 12 | decoration: BoxDecoration( 13 | gradient: 14 | LinearGradient(colors: [Colors.red, Colors.orange.shade700]), 15 | //背景渐变 16 | borderRadius: BorderRadius.circular(3.0), 17 | //3像素圆角 18 | boxShadow: const [ 19 | //阴影 20 | BoxShadow( 21 | color: Colors.black54, 22 | offset: Offset(2.0, 2.0), 23 | blurRadius: 4.0) 24 | ]), 25 | child: const Padding( 26 | padding: EdgeInsets.symmetric( 27 | horizontal: 80.0, 28 | vertical: 18.0, 29 | ), 30 | child: Text( 31 | "Login", 32 | style: TextStyle(color: Colors.white), 33 | ), 34 | ), 35 | ), 36 | SizedBox( 37 | width: 100, 38 | height: 100, 39 | child: DecoratedBox( 40 | decoration: BoxDecoration( 41 | borderRadius: BorderRadius.circular(80), 42 | image: const DecorationImage( 43 | image: AssetImage("imgs/avatar.png"), 44 | //alignment: Alignment.topLeft 45 | ), 46 | ), 47 | ), 48 | ) 49 | ], 50 | ); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /gitme/ios/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Flutter (1.0.0) 3 | - fluttertoast (0.0.2): 4 | - Flutter 5 | - Toast 6 | - FMDB (2.7.5): 7 | - FMDB/standard (= 2.7.5) 8 | - FMDB/standard (2.7.5) 9 | - path_provider_ios (0.0.1): 10 | - Flutter 11 | - shared_preferences_ios (0.0.1): 12 | - Flutter 13 | - sqflite (0.0.2): 14 | - Flutter 15 | - FMDB (>= 2.7.5) 16 | - Toast (4.0.0) 17 | 18 | DEPENDENCIES: 19 | - Flutter (from `Flutter`) 20 | - fluttertoast (from `.symlinks/plugins/fluttertoast/ios`) 21 | - path_provider_ios (from `.symlinks/plugins/path_provider_ios/ios`) 22 | - shared_preferences_ios (from `.symlinks/plugins/shared_preferences_ios/ios`) 23 | - sqflite (from `.symlinks/plugins/sqflite/ios`) 24 | 25 | SPEC REPOS: 26 | trunk: 27 | - FMDB 28 | - Toast 29 | 30 | EXTERNAL SOURCES: 31 | Flutter: 32 | :path: Flutter 33 | fluttertoast: 34 | :path: ".symlinks/plugins/fluttertoast/ios" 35 | path_provider_ios: 36 | :path: ".symlinks/plugins/path_provider_ios/ios" 37 | shared_preferences_ios: 38 | :path: ".symlinks/plugins/shared_preferences_ios/ios" 39 | sqflite: 40 | :path: ".symlinks/plugins/sqflite/ios" 41 | 42 | SPEC CHECKSUMS: 43 | Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a 44 | fluttertoast: 16fbe6039d06a763f3533670197d01fc73459037 45 | FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a 46 | path_provider_ios: 14f3d2fd28c4fdb42f44e0f751d12861c43cee02 47 | shared_preferences_ios: 548a61f8053b9b8a49ac19c1ffbc8b92c50d68ad 48 | sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904 49 | Toast: 91b396c56ee72a5790816f40d3a94dd357abc196 50 | 51 | PODFILE CHECKSUM: 8e679eca47255a8ca8067c4c67aab20e64cb974d 52 | 53 | COCOAPODS: 1.10.2 54 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /code.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | $title 8 | 47 | 48 | 49 | 50 |
$code
51 | 52 | 53 | 66 | -------------------------------------------------------------------------------- /gitme/ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | gitme 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(FLUTTER_BUILD_NAME) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UIViewControllerBasedStatusBarAppearance 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /gitme/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 | -------------------------------------------------------------------------------- /lib/chapter6/keepalive.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import '../common.dart'; 3 | 4 | class KeepAliveTest extends StatefulWidget { 5 | const KeepAliveTest({Key? key}) : super(key: key); 6 | 7 | @override 8 | State createState() => _KeepAliveTestState(); 9 | } 10 | 11 | class _KeepAliveTestState extends State { 12 | bool _keepAlive = false; 13 | 14 | @override 15 | Widget build(BuildContext context) { 16 | return ListView.builder(itemBuilder: (_, index) { 17 | return KeepAliveWrapper( 18 | // 为 true 后会缓存所有的列表项,列表项将不会销毁。 19 | // 为 false 时,列表项滑出预加载区域后将会别销毁。 20 | // 使用时一定要注意是否必要,因为对所有列表项都缓存的会导致更多的内存消耗 21 | keepAlive: _keepAlive, 22 | child: wItem(index), 23 | ); 24 | }); 25 | } 26 | 27 | Widget wItem(index) { 28 | if (index == 0) { 29 | return CheckboxListTile( 30 | title: const Text('是否缓存列表项'), 31 | value: _keepAlive, 32 | onChanged: (v) { 33 | setState(() { 34 | _keepAlive = v!; 35 | }); 36 | }, 37 | ); 38 | } else { 39 | return ListItem(index: index); 40 | } 41 | } 42 | } 43 | 44 | class ListItem extends StatefulWidget { 45 | const ListItem({Key? key, required this.index}) : super(key: key); 46 | final int index; 47 | 48 | @override 49 | _ListItemState createState() => _ListItemState(); 50 | } 51 | 52 | class _ListItemState extends State { 53 | @override 54 | Widget build(BuildContext context) { 55 | return ListTile(title: Text('${widget.index}')); 56 | } 57 | 58 | @override 59 | void dispose() { 60 | print('dispose ${widget.index}'); 61 | super.dispose(); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /lib/chapter7/value_listenable_builder.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class ValueListenableRoute extends StatefulWidget { 4 | const ValueListenableRoute({Key? key}) : super(key: key); 5 | 6 | @override 7 | State createState() => _ValueListenableState(); 8 | } 9 | 10 | class _ValueListenableState extends State { 11 | // 定义一个ValueNotifier,当数字变化时会通知 ValueListenableBuilder 12 | final ValueNotifier _counter = ValueNotifier(0); 13 | static const double textScaleFactor = 1.5; 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | // 添加 + 按钮不会触发整个 ValueListenableRoute 组件的 build 18 | print('build'); 19 | return Scaffold( 20 | appBar: AppBar(title: const Text('ValueListenableBuilder 测试')), 21 | body: Center( 22 | child: ValueListenableBuilder( 23 | builder: (BuildContext context, int value, Widget? child) { 24 | // builder 方法只会在 _counter 变化时被调用 25 | return Row( 26 | mainAxisAlignment: MainAxisAlignment.center, 27 | children: [ 28 | child!, 29 | Text('$value 次',textScaleFactor: textScaleFactor), 30 | ], 31 | ); 32 | }, 33 | valueListenable: _counter, 34 | // 当子组件不依赖变化的数据,且子组件收件开销比较大时,指定 child 属性来缓存子组件非常有用 35 | child: const Text('点击了 ', textScaleFactor: textScaleFactor), 36 | ), 37 | ), 38 | floatingActionButton: FloatingActionButton( 39 | child: const Icon(Icons.add), 40 | // 点击后值 +1,触发 ValueListenableBuilder 重新构建 41 | onPressed: () => _counter.value += 1, 42 | ), 43 | ); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /lib/chapter9/scale_animation.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class ScaleAnimationRoute extends StatefulWidget { 4 | const ScaleAnimationRoute({Key? key}) : super(key: key); 5 | 6 | @override 7 | _ScaleAnimationRouteState createState() => _ScaleAnimationRouteState(); 8 | } 9 | 10 | //需要继承TickerProvider,如果有多个AnimationController,则应该使用TickerProviderStateMixin。 11 | class _ScaleAnimationRouteState extends State 12 | with SingleTickerProviderStateMixin { 13 | late Animation animation; 14 | late AnimationController controller; 15 | 16 | @override 17 | initState() { 18 | super.initState(); 19 | controller = AnimationController( 20 | duration: const Duration(seconds: 2), 21 | vsync: this, 22 | ); 23 | 24 | //匀速 25 | //图片宽高从0变到300 26 | animation = Tween(begin: 0.0, end: 300.0).animate(controller) 27 | ..addListener(() { 28 | setState(() => {}); 29 | }); 30 | 31 | // //使用弹性曲线 32 | // animation=CurvedAnimation(parent: controller, curve: Curves.bounceIn); 33 | // //图片宽高从0变到300 34 | // animation = Tween(begin: 0.0, end: 300.0).animate(animation) 35 | // ..addListener(() { 36 | // setState(() { 37 | // }); 38 | // }); 39 | 40 | //启动动画(正向执行) 41 | controller.forward(); 42 | } 43 | 44 | @override 45 | Widget build(BuildContext context) { 46 | return Center( 47 | child: Image.asset( 48 | "imgs/avatar.png", 49 | width: animation.value, 50 | height: animation.value, 51 | ), 52 | ); 53 | } 54 | 55 | @override 56 | dispose() { 57 | //路由销毁时需要释放动画资源 58 | controller.dispose(); 59 | super.dispose(); 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | flutter_in_action_2 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(FLUTTER_BUILD_NAME) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UIViewControllerBasedStatusBarAppearance 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /lib/chapter6/scrollnotification.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class ScrollNotificationTestRoute extends StatefulWidget { 4 | const ScrollNotificationTestRoute({Key? key}) : super(key: key); 5 | 6 | @override 7 | _ScrollNotificationTestRouteState createState() => 8 | _ScrollNotificationTestRouteState(); 9 | } 10 | 11 | class _ScrollNotificationTestRouteState 12 | extends State { 13 | String _progress = "0%"; //保存进度百分比 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | return Scrollbar( 18 | //进度条 19 | // 监听滚动通知 20 | child: NotificationListener( 21 | onNotification: (ScrollNotification notification) { 22 | double progress = notification.metrics.pixels / 23 | notification.metrics.maxScrollExtent; 24 | //重新构建 25 | setState(() { 26 | _progress = "${(progress * 100).toInt()}%"; 27 | }); 28 | print("BottomEdge: ${notification.metrics.extentAfter == 0}"); 29 | return false; 30 | //return true; //放开此行注释后,进度条将失效 31 | }, 32 | child: Stack( 33 | alignment: Alignment.center, 34 | children: [ 35 | ListView.builder( 36 | itemCount: 100, 37 | itemExtent: 50.0, 38 | itemBuilder: (context, index) => ListTile(title: Text("$index")), 39 | ), 40 | CircleAvatar( 41 | //显示进度百分比 42 | radius: 30.0, 43 | child: Text(_progress), 44 | backgroundColor: Colors.black54, 45 | ) 46 | ], 47 | ), 48 | ), 49 | ); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /gitme/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 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '1' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.0' 22 | } 23 | 24 | apply plugin: 'com.android.application' 25 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 26 | 27 | android { 28 | compileSdkVersion 30 29 | 30 | defaultConfig { 31 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 32 | applicationId "club.flutterchina.gitme" 33 | minSdkVersion 16 34 | targetSdkVersion 30 35 | versionCode flutterVersionCode.toInteger() 36 | versionName flutterVersionName 37 | } 38 | 39 | buildTypes { 40 | release { 41 | // TODO: Add your own signing config for the release build. 42 | // Signing with the debug keys for now, so `flutter run --release` works. 43 | signingConfig signingConfigs.debug 44 | } 45 | } 46 | } 47 | 48 | flutter { 49 | source '../..' 50 | } 51 | -------------------------------------------------------------------------------- /ios/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - camera (0.0.1): 3 | - Flutter 4 | - Flutter (1.0.0) 5 | - image_picker_ios (0.0.1): 6 | - Flutter 7 | - path_provider_ios (0.0.1): 8 | - Flutter 9 | - video_player_avfoundation (0.0.1): 10 | - Flutter 11 | - webview_flutter_wkwebview (0.0.1): 12 | - Flutter 13 | 14 | DEPENDENCIES: 15 | - camera (from `.symlinks/plugins/camera/ios`) 16 | - Flutter (from `Flutter`) 17 | - image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`) 18 | - path_provider_ios (from `.symlinks/plugins/path_provider_ios/ios`) 19 | - video_player_avfoundation (from `.symlinks/plugins/video_player_avfoundation/ios`) 20 | - webview_flutter_wkwebview (from `.symlinks/plugins/webview_flutter_wkwebview/ios`) 21 | 22 | EXTERNAL SOURCES: 23 | camera: 24 | :path: ".symlinks/plugins/camera/ios" 25 | Flutter: 26 | :path: Flutter 27 | image_picker_ios: 28 | :path: ".symlinks/plugins/image_picker_ios/ios" 29 | path_provider_ios: 30 | :path: ".symlinks/plugins/path_provider_ios/ios" 31 | video_player_avfoundation: 32 | :path: ".symlinks/plugins/video_player_avfoundation/ios" 33 | webview_flutter_wkwebview: 34 | :path: ".symlinks/plugins/webview_flutter_wkwebview/ios" 35 | 36 | SPEC CHECKSUMS: 37 | camera: 3164201dc344383e62282964016528c4f5a9ad50 38 | Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a 39 | image_picker_ios: b786a5dcf033a8336a657191401bfdf12017dabb 40 | path_provider_ios: 14f3d2fd28c4fdb42f44e0f751d12861c43cee02 41 | video_player_avfoundation: e489aac24ef5cf7af82702979ed16f2a5ef84cff 42 | webview_flutter_wkwebview: b7e70ef1ddded7e69c796c7390ee74180182971f 43 | 44 | PODFILE CHECKSUM: 8e679eca47255a8ca8067c4c67aab20e64cb974d 45 | 46 | COCOAPODS: 1.10.2 47 | -------------------------------------------------------------------------------- /gitme/lib/states/profile_change_notifier.dart: -------------------------------------------------------------------------------- 1 | import '../index.dart'; 2 | 3 | class ProfileChangeNotifier extends ChangeNotifier { 4 | Profile get _profile => Global.profile; 5 | 6 | @override 7 | void notifyListeners() { 8 | Global.saveProfile(); //保存Profile变更 9 | super.notifyListeners(); //通知依赖的Widget更新 10 | } 11 | } 12 | 13 | class UserModel extends ProfileChangeNotifier { 14 | User? get user => _profile.user; 15 | 16 | // APP是否登录(如果有用户信息,则证明登录过) 17 | bool get isLogin => user != null; 18 | 19 | //用户信息发生变化,更新用户信息并通知依赖它的子孙Widgets更新 20 | set user(User? user) { 21 | if (user?.login != _profile.user?.login) { 22 | _profile.lastLogin = _profile.user?.login; 23 | _profile.user = user; 24 | notifyListeners(); 25 | } 26 | } 27 | } 28 | 29 | class ThemeModel extends ProfileChangeNotifier { 30 | // 获取当前主题,如果为设置主题,则默认使用蓝色主题 31 | MaterialColor get theme => Global.themes 32 | .firstWhere((e) => e.value == _profile.theme, orElse: () => Colors.blue); 33 | 34 | // 主题改变后,通知其依赖项,新主题会立即生效 35 | set theme(MaterialColor color) { 36 | if (color != theme) { 37 | _profile.theme = color.value; 38 | notifyListeners(); 39 | } 40 | } 41 | } 42 | 43 | class LocaleModel extends ProfileChangeNotifier { 44 | // 获取当前用户的APP语言配置Locale类,如果为null,则语言跟随系统语言 45 | Locale? getLocale() { 46 | if (_profile.locale == null) return null; 47 | var t = _profile.locale!.split("_"); 48 | return Locale(t[0], t[1]); 49 | } 50 | 51 | // 获取当前Locale的字符串表示 52 | String? get locale => _profile.locale; 53 | 54 | // 用户改变APP语言后,通知依赖项更新,新语言会立即生效 55 | set locale(String? locale) { 56 | if (locale != _profile.locale) { 57 | _profile.locale = locale; 58 | notifyListeners(); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /lib/chapter2/counter.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | typedef CounterRoute = MyApp; 4 | 5 | class MyApp extends StatelessWidget { 6 | const MyApp({Key? key}) : super(key: key); 7 | 8 | @override 9 | Widget build(BuildContext context) { 10 | return MaterialApp( 11 | title: 'Flutter Demo', 12 | theme: ThemeData( 13 | primarySwatch: Colors.blue, 14 | ), 15 | home: const MyHomePage(title: 'Flutter Demo Home Page'), 16 | ); 17 | } 18 | } 19 | 20 | class MyHomePage extends StatefulWidget { 21 | const MyHomePage({Key? key, required this.title}) : super(key: key); 22 | final String title; 23 | 24 | @override 25 | _MyHomePageState createState() => _MyHomePageState(); 26 | } 27 | 28 | class _MyHomePageState extends State { 29 | int _counter = 0; 30 | 31 | void _incrementCounter() { 32 | setState(() { 33 | _counter++; 34 | }); 35 | } 36 | 37 | @override 38 | Widget build(BuildContext context) { 39 | return Scaffold( 40 | appBar: AppBar( 41 | title: Text(widget.title), 42 | ), 43 | body: Center( 44 | child: Column( 45 | mainAxisAlignment: MainAxisAlignment.center, 46 | children: [ 47 | const Text('You have pushed the button this many times:'), 48 | Text( 49 | '$_counter', 50 | style: Theme.of(context).textTheme.headline4, 51 | ), 52 | ], 53 | ), 54 | ), 55 | floatingActionButton: FloatingActionButton( 56 | onPressed: _incrementCounter, 57 | tooltip: 'Increment', 58 | child: const Icon(Icons.add), 59 | ), // This trailing comma makes auto-formatting nicer for build methods. 60 | ); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /lib/widgets/hit_test_blocker.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/rendering.dart'; 2 | import 'package:flutter/widgets.dart'; 3 | 4 | class HitTestBlocker extends SingleChildRenderObjectWidget { 5 | HitTestBlocker({ 6 | Key? key, 7 | this.up = true, 8 | this.down = false, 9 | this.self = false, 10 | Widget? child, 11 | }) : super(key: key, child: child); 12 | 13 | /// Block hit test up. if true , `hitTest()` always return false. 14 | final bool up; 15 | 16 | /// Block hit test down. if true, skip `hitTestChildren()`. 17 | final bool down; 18 | 19 | /// The return value of `hitTestSelf` 20 | final bool self; 21 | 22 | @override 23 | RenderObject createRenderObject(BuildContext context) { 24 | return RenderHitTestBlocker(up: up, down: down, self: self); 25 | } 26 | 27 | @override 28 | void updateRenderObject( 29 | BuildContext context, RenderHitTestBlocker renderObject) { 30 | renderObject 31 | ..up = up 32 | ..down = down 33 | ..self = self; 34 | } 35 | } 36 | 37 | class RenderHitTestBlocker extends RenderProxyBox { 38 | RenderHitTestBlocker({this.up = true, this.down = true, this.self = true}); 39 | 40 | bool up; 41 | bool down; 42 | bool self; 43 | 44 | @override 45 | bool hitTest(BoxHitTestResult result, {required Offset position}) { 46 | bool hitTestDownResult = false; 47 | 48 | if (!down) { 49 | hitTestDownResult = hitTestChildren(result, position: position); 50 | } 51 | 52 | bool pass = 53 | hitTestSelf(position) || (hitTestDownResult && size.contains(position)); 54 | 55 | if (pass) { 56 | result.add(BoxHitTestEntry(this, position)); 57 | } 58 | 59 | return !up && pass; 60 | } 61 | 62 | @override 63 | bool hitTestSelf(Offset position) => self; 64 | } -------------------------------------------------------------------------------- /lib/widgets/turn_box.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/widgets.dart'; 2 | 3 | /// Animates the rotation of a widget when [turns] is changed. 4 | 5 | class TurnBox extends StatefulWidget { 6 | const TurnBox({ 7 | Key? key, 8 | this.turns = .0, 9 | this.speed = 200, 10 | required this.child, 11 | }) : super(key: key); 12 | 13 | /// Controls the rotation of the child. 14 | /// 15 | /// If the current value of the turns is v, the child will be 16 | /// rotated v * 2 * pi radians before being painted. 17 | final double turns; 18 | 19 | /// Animation duration in milliseconds 20 | final int speed; 21 | 22 | final Widget child; 23 | 24 | @override 25 | _TurnBoxState createState() => _TurnBoxState(); 26 | } 27 | 28 | class _TurnBoxState extends State with SingleTickerProviderStateMixin { 29 | late AnimationController _controller; 30 | 31 | @override 32 | void initState() { 33 | super.initState(); 34 | _controller = AnimationController( 35 | vsync: this, 36 | lowerBound: -double.infinity, 37 | upperBound: double.infinity, 38 | ); 39 | _controller.value = widget.turns; 40 | } 41 | 42 | @override 43 | void dispose() { 44 | _controller.dispose(); 45 | super.dispose(); 46 | } 47 | 48 | @override 49 | Widget build(BuildContext context) { 50 | return RotationTransition( 51 | turns: _controller, 52 | child: widget.child, 53 | ); 54 | } 55 | 56 | @override 57 | void didUpdateWidget(TurnBox oldWidget) { 58 | super.didUpdateWidget(oldWidget); 59 | if (oldWidget.turns != widget.turns) { 60 | _controller.animateTo( 61 | widget.turns, 62 | duration: Duration(milliseconds: widget.speed), 63 | curve: Curves.easeOut, 64 | ); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /lib/chapter6/sliver_flexible_header.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import '../common.dart'; 3 | 4 | class SliverFlexibleHeaderRoute extends StatefulWidget { 5 | const SliverFlexibleHeaderRoute({Key? key}) : super(key: key); 6 | 7 | @override 8 | State createState() => 9 | _SliverFlexibleHeaderRouteState(); 10 | } 11 | 12 | class _SliverFlexibleHeaderRouteState extends State { 13 | double _initHeight = 250; 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | return CustomScrollView( 18 | physics: 19 | const BouncingScrollPhysics(parent: AlwaysScrollableScrollPhysics()), 20 | slivers: [ 21 | SliverFlexibleHeader( 22 | visibleExtent: _initHeight, 23 | builder: (context, availableHeight, direction) { 24 | return GestureDetector( 25 | onTap: () => print('tap'), 26 | child: LayoutBuilder(builder: (context, cons) { 27 | return Image( 28 | image: const AssetImage("imgs/avatar.png"), 29 | width: 50.0, 30 | height: availableHeight, 31 | alignment: Alignment.bottomCenter, 32 | fit: BoxFit.cover, 33 | ); 34 | }), 35 | ); 36 | }, 37 | ), 38 | SliverToBoxAdapter( 39 | child: ListTile( 40 | onTap: () { 41 | setState(() { 42 | _initHeight = _initHeight == 250 ? 150 : 250; 43 | }); 44 | }, 45 | title: const Text('重置高度'), 46 | trailing: Text('当前高度 $_initHeight'), 47 | ), 48 | ), 49 | buildSliverList(30), 50 | ], 51 | ); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /lib/chapter11/file.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | import 'dart:async'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:path_provider/path_provider.dart'; 5 | 6 | class FileOperationRoute extends StatefulWidget { 7 | FileOperationRoute({Key? key}) : super(key: key); 8 | 9 | @override 10 | _FileOperationRouteState createState() => _FileOperationRouteState(); 11 | } 12 | 13 | class _FileOperationRouteState extends State { 14 | int _counter = 0; 15 | 16 | @override 17 | void initState() { 18 | super.initState(); 19 | //从文件读取点击次数 20 | _readCounter().then((int value) { 21 | setState(() { 22 | _counter = value; 23 | }); 24 | }); 25 | } 26 | 27 | Future _getLocalFile() async { 28 | // 获取应用目录 29 | String dir = (await getApplicationDocumentsDirectory()).path; 30 | return File('$dir/counter.txt'); 31 | } 32 | 33 | Future _readCounter() async { 34 | try { 35 | File file = await _getLocalFile(); 36 | // 读取点击次数(以字符串) 37 | String contents = await file.readAsString(); 38 | return int.parse(contents); 39 | } on FileSystemException { 40 | return 0; 41 | } 42 | } 43 | 44 | _incrementCounter() async { 45 | setState(() { 46 | _counter++; 47 | }); 48 | // 将点击次数以字符串类型写到文件中 49 | await (await _getLocalFile()).writeAsString('$_counter'); 50 | } 51 | 52 | @override 53 | Widget build(BuildContext context) { 54 | return Scaffold( 55 | appBar: AppBar(title: Text('文件操作')), 56 | body: Center( 57 | child: Text('点击了 $_counter 次'), 58 | ), 59 | floatingActionButton: FloatingActionButton( 60 | onPressed: _incrementCounter, 61 | tooltip: 'Increment', 62 | child: Icon(Icons.add), 63 | ), 64 | ); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /lib/chapter6/configuration.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter/rendering.dart'; 3 | import 'dart:math' as math; 4 | 5 | class ScrollViewConfiguration extends StatefulWidget { 6 | const ScrollViewConfiguration({Key? key}) : super(key: key); 7 | 8 | @override 9 | _ScrollViewConfigurationState createState() => 10 | _ScrollViewConfigurationState(); 11 | } 12 | 13 | class _ScrollViewConfigurationState extends State { 14 | bool reverse = false; 15 | bool vertical = true; 16 | ScrollPhysics physics = const ScrollPhysics(); 17 | 18 | @override 19 | Widget build(BuildContext context) { 20 | Widget list = ListView.builder( 21 | reverse: reverse, 22 | scrollDirection: vertical ? Axis.vertical : Axis.horizontal, 23 | // controller: , 24 | //physics: ObserveOverscrollPhysics((e)=>print(e)), 25 | physics: const ClampingScrollPhysics(), 26 | itemBuilder: (context, index) { 27 | return Padding( 28 | padding: const EdgeInsets.all(8.0), 29 | child: Center(child: Text('$index',textScaleFactor: 2,)), 30 | ); 31 | }, 32 | ); 33 | 34 | return Column(children: [ 35 | Expanded(child: list), 36 | wConfigurationPanel(), 37 | ]); 38 | } 39 | 40 | Widget wConfigurationPanel() { 41 | return ListView( 42 | shrinkWrap: true, 43 | children: [ 44 | CheckboxListTile( 45 | value: reverse, 46 | title: const Text('反向'), 47 | onChanged: (v) => setState(() => reverse = v!), 48 | ), 49 | CheckboxListTile( 50 | value: vertical, 51 | title: const Text('Vertical(滚动方向)'), 52 | onChanged: (v) => setState(() => vertical = v!), 53 | ), 54 | ], 55 | ); 56 | } 57 | } 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /lib/chapter2/state.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class StateLifecycleTest extends StatelessWidget { 4 | const StateLifecycleTest({Key? key}) : super(key: key); 5 | 6 | @override 7 | Widget build(BuildContext context) { 8 | return const CounterWidget(); 9 | } 10 | } 11 | 12 | class CounterWidget extends StatefulWidget { 13 | const CounterWidget({Key? key, this.initValue = 0}) : super(key: key); 14 | 15 | final int initValue; 16 | 17 | @override 18 | _CounterWidgetState createState() => _CounterWidgetState(); 19 | } 20 | 21 | class _CounterWidgetState extends State { 22 | int _counter = 0; 23 | 24 | @override 25 | void initState() { 26 | super.initState(); 27 | //初始化状态 28 | _counter = widget.initValue; 29 | print("initState"); 30 | } 31 | 32 | @override 33 | Widget build(BuildContext context) { 34 | print("build"); 35 | return Scaffold( 36 | body: Center( 37 | child: TextButton( 38 | child: Text('$_counter'), 39 | //点击后计数器自增 40 | onPressed: () => setState( 41 | () => ++_counter, 42 | ), 43 | ), 44 | ), 45 | ); 46 | } 47 | 48 | @override 49 | void didUpdateWidget(CounterWidget oldWidget) { 50 | super.didUpdateWidget(oldWidget); 51 | print("didUpdateWidget "); 52 | } 53 | 54 | @override 55 | void deactivate() { 56 | super.deactivate(); 57 | print("deactivate"); 58 | } 59 | 60 | @override 61 | void dispose() { 62 | super.dispose(); 63 | print("dispose"); 64 | } 65 | 66 | @override 67 | void reassemble() { 68 | super.reassemble(); 69 | print("reassemble"); 70 | } 71 | 72 | @override 73 | void didChangeDependencies() { 74 | super.didChangeDependencies(); 75 | print("didChangeDependencies"); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /lib/chapter4/layoutbuilder.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import '../common.dart'; 3 | 4 | class ResponsiveColumn extends StatelessWidget { 5 | const ResponsiveColumn({Key? key, required this.children}) : super(key: key); 6 | 7 | final List children; 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | return LayoutBuilder( 12 | builder: (BuildContext context, BoxConstraints constraints) { 13 | if (constraints.maxWidth < 200) { 14 | return Column(children: children, mainAxisSize: MainAxisSize.min); 15 | } else { 16 | var _children = []; 17 | for (var i = 0; i < children.length; i += 2) { 18 | if (i + 1 < children.length) { 19 | _children.add(Row( 20 | children: [children[i], children[i + 1]], 21 | mainAxisSize: MainAxisSize.min, 22 | )); 23 | } else { 24 | _children.add(children[i]); 25 | } 26 | } 27 | return Column(children: _children, mainAxisSize: MainAxisSize.min); 28 | } 29 | }, 30 | ); 31 | } 32 | } 33 | 34 | class LayoutBuilderRoute extends StatelessWidget { 35 | const LayoutBuilderRoute({Key? key}) : super(key: key); 36 | 37 | @override 38 | Widget build(BuildContext context) { 39 | // return LayoutLogPrint(child:Text("xx"*20000)); 40 | var _children = List.filled(6, const Text("A")); 41 | // Column在本示例中在水平方向的最大宽度为屏幕的宽度 42 | return Column( 43 | mainAxisSize: MainAxisSize.min, 44 | children: [ 45 | SizedBox(width: 190, child: ResponsiveColumn(children: _children)), 46 | ResponsiveColumn(children: _children), 47 | const LayoutLogPrint(child: Text("flutter@wendux")), 48 | //CustomSingleChildLayout 49 | ], 50 | ); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /lib/chapter3/switch_checkbox.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class SwitchAndCheckBoxRoute extends StatefulWidget { 4 | const SwitchAndCheckBoxRoute({Key? key}) : super(key: key); 5 | 6 | @override 7 | _SwitchAndCheckBoxRouteState createState() => 8 | _SwitchAndCheckBoxRouteState(); 9 | } 10 | 11 | class _SwitchAndCheckBoxRouteState extends State { 12 | bool _switchSelected = true; //维护单选开关状态 13 | bool _checkboxSelected = true; //维护复选框状态 14 | @override 15 | Widget build(BuildContext context) { 16 | return Column( 17 | children: [ 18 | Row( 19 | children: [ 20 | Switch( 21 | value: _switchSelected, //当前状态 22 | onChanged: (value) { 23 | //重新构建页面 24 | setState(() { 25 | _switchSelected = value; 26 | }); 27 | }, 28 | ), 29 | const Text("关"), 30 | Switch( 31 | value: !_switchSelected, //当前状态 32 | onChanged: (value) {}, 33 | ), 34 | const Text("开"), 35 | ], 36 | ), 37 | Row( 38 | children: [ 39 | Checkbox( 40 | value: _checkboxSelected, 41 | activeColor: Colors.red, //选中时的颜色 42 | onChanged: (value) { 43 | setState(() { 44 | _checkboxSelected = value!; 45 | }); 46 | }, 47 | ), 48 | const Text("未选中"), 49 | Checkbox( 50 | value: !_checkboxSelected, 51 | activeColor: Colors.red, //选中时的颜色 52 | onChanged: (value) {}, 53 | ), 54 | const Text("选中"), 55 | ], 56 | ) 57 | ], 58 | ); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /lib/chapter8/notification.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class NotificationRoute extends StatefulWidget { 4 | const NotificationRoute({Key? key}) : super(key: key); 5 | 6 | @override 7 | NotificationRouteState createState() { 8 | return NotificationRouteState(); 9 | } 10 | } 11 | 12 | class NotificationRouteState extends State { 13 | String _msg = ""; 14 | final pageController = PageController(); 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | //监听通知 19 | return NotificationListener( 20 | onNotification: (notification) { 21 | print(notification.msg); 22 | return false; 23 | }, 24 | child: NotificationListener( 25 | onNotification: (notification) { 26 | setState(() { 27 | _msg += notification.msg + " "; 28 | }); 29 | return false; 30 | }, 31 | child: Center( 32 | child: Column( 33 | mainAxisSize: MainAxisSize.min, 34 | children: [ 35 | // ElevatedButton( 36 | // onPressed: () => MyNotification("Hi").dispatch(context), 37 | // child: Text("Send Notification"), 38 | // ), 39 | Builder( 40 | builder: (context) { 41 | return ElevatedButton( 42 | //按钮点击时分发通知 43 | onPressed: () => MyNotification("Hi").dispatch(context), 44 | child: const Text("Send Notification"), 45 | ); 46 | }, 47 | ), 48 | Text(_msg) 49 | ], 50 | ), 51 | ), 52 | ), 53 | ); 54 | } 55 | } 56 | 57 | class MyNotification extends Notification { 58 | MyNotification(this.msg); 59 | 60 | final String msg; 61 | } 62 | -------------------------------------------------------------------------------- /lib/chapter6/pull_refresh.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | import 'package:flutter/cupertino.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | class PullRefreshTestRoute extends StatelessWidget { 6 | const PullRefreshTestRoute({Key? key}) : super(key: key); 7 | 8 | @override 9 | Widget build(BuildContext context) { 10 | return CustomScrollView( 11 | physics: 12 | const BouncingScrollPhysics(parent: AlwaysScrollableScrollPhysics()), 13 | slivers: [ 14 | CupertinoSliverRefreshControl( 15 | builder: builder, 16 | onRefresh: () => Future.delayed(const Duration(seconds: 2)), 17 | ), 18 | SliverList( 19 | delegate: SliverChildBuilderDelegate( 20 | (_, int index) => ListTile( 21 | title: Text('$index'), 22 | ), 23 | ), 24 | ) 25 | ], 26 | ); 27 | } 28 | 29 | Widget builder( 30 | BuildContext context, 31 | RefreshIndicatorMode refreshState, 32 | double pulledExtent, 33 | double refreshTriggerPullDistance, 34 | double refreshIndicatorExtent, 35 | ) { 36 | Widget widget; 37 | double width = min(25, pulledExtent); 38 | if (refreshState == RefreshIndicatorMode.refresh) { 39 | widget = SizedBox( 40 | child: const CircularProgressIndicator(strokeWidth: 2), 41 | width: width, 42 | height: width, 43 | ); 44 | } else { 45 | widget = Transform.rotate( 46 | angle: pulledExtent / 80 * 6.28, 47 | child: const CircularProgressIndicator( 48 | value: .85, 49 | strokeWidth: 2, 50 | ), 51 | ); 52 | } 53 | return Center( 54 | child: SizedBox( 55 | width: width, 56 | height: width, 57 | child: Padding(padding: const EdgeInsets.all(2.0), child: widget), 58 | ), 59 | ); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /lib/chapter9/grow_transition.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class GrowTransition extends StatelessWidget { 4 | const GrowTransition({Key? key, 5 | required this.animation, 6 | this.child, 7 | }) : super(key: key); 8 | 9 | final Widget? child; 10 | final Animation animation; 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | return Center( 15 | child: AnimatedBuilder( 16 | animation: animation, 17 | builder: (BuildContext context, child) { 18 | return SizedBox( 19 | height: animation.value, 20 | width: animation.value, 21 | child: child, 22 | ); 23 | }, 24 | child: child, 25 | ), 26 | ); 27 | } 28 | } 29 | 30 | class GrowTransitionRoute extends StatefulWidget { 31 | const GrowTransitionRoute({Key? key}) : super(key: key); 32 | 33 | @override 34 | _GrowTransitionRouteState createState() => _GrowTransitionRouteState(); 35 | } 36 | 37 | //需要继承TickerProvider,如果有多个AnimationController,则应该使用TickerProviderStateMixin。 38 | class _GrowTransitionRouteState extends State 39 | with SingleTickerProviderStateMixin { 40 | late Animation animation; 41 | late AnimationController controller; 42 | 43 | @override 44 | initState() { 45 | super.initState(); 46 | controller = 47 | AnimationController(duration: const Duration(seconds: 2), vsync: this); 48 | animation = Tween(begin: 0.0, end: 300.0).animate(controller); 49 | controller.forward(); 50 | } 51 | 52 | @override 53 | Widget build(BuildContext context) { 54 | return GrowTransition( 55 | child: Image.asset("imgs/avatar.png"), 56 | animation: animation, 57 | ); 58 | } 59 | 60 | @override 61 | dispose() { 62 | //路由销毁时需要释放动画资源 63 | controller.dispose(); 64 | super.dispose(); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /lib/widgets/gradient_button.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class GradientButton extends StatelessWidget { 4 | const GradientButton({Key? key, 5 | this.colors, 6 | this.width, 7 | this.height, 8 | this.onPressed, 9 | this.borderRadius, 10 | required this.child, 11 | }) : super(key: key); 12 | 13 | // 渐变色数组 14 | final List? colors; 15 | 16 | // 按钮宽高 17 | final double? width; 18 | final double? height; 19 | final BorderRadius? borderRadius; 20 | 21 | //点击回调 22 | final GestureTapCallback? onPressed; 23 | 24 | final Widget child; 25 | 26 | @override 27 | Widget build(BuildContext context) { 28 | ThemeData theme = Theme.of(context); 29 | 30 | //确保colors数组不空 31 | List _colors = 32 | colors ?? [theme.primaryColor, theme.primaryColorDark]; 33 | 34 | return DecoratedBox( 35 | decoration: BoxDecoration( 36 | gradient: LinearGradient(colors: _colors), 37 | borderRadius: borderRadius, 38 | //border: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20.0)), 39 | ), 40 | child: Material( 41 | type: MaterialType.transparency, 42 | child: InkWell( 43 | splashColor: _colors.last, 44 | highlightColor: Colors.transparent, 45 | borderRadius: borderRadius, 46 | onTap: onPressed, 47 | child: ConstrainedBox( 48 | constraints: BoxConstraints.tightFor(height: height, width: width), 49 | child: Center( 50 | child: Padding( 51 | padding: const EdgeInsets.all(8.0), 52 | child: DefaultTextStyle( 53 | style: const TextStyle(fontWeight: FontWeight.bold), 54 | child: child, 55 | ), 56 | ), 57 | ), 58 | ), 59 | ), 60 | ), 61 | ); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /lib/widgets/sliver_header_delegate.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/widgets.dart'; 2 | 3 | typedef SliverHeaderBuilder = Widget Function( 4 | BuildContext context, double shrinkOffset, bool overlapsContent); 5 | 6 | class SliverHeaderDelegate extends SliverPersistentHeaderDelegate { 7 | // child 为 header 8 | SliverHeaderDelegate({ 9 | required this.maxHeight, 10 | this.minHeight = 0, 11 | required Widget child, 12 | }) : builder = ((a, b, c) => child), 13 | assert(minHeight <= maxHeight && minHeight >= 0); 14 | 15 | //最大和最小高度相同 16 | SliverHeaderDelegate.fixedHeight({ 17 | required double height, 18 | required Widget child, 19 | }) : builder = ((a, b, c) => child), 20 | maxHeight = height, 21 | minHeight = height; 22 | 23 | //需要自定义builder时使用 24 | SliverHeaderDelegate.builder({ 25 | required this.maxHeight, 26 | this.minHeight = 0, 27 | required this.builder, 28 | }); 29 | 30 | final double maxHeight; 31 | final double minHeight; 32 | final SliverHeaderBuilder builder; 33 | 34 | @override 35 | Widget build( 36 | BuildContext context, 37 | double shrinkOffset, 38 | bool overlapsContent, 39 | ) { 40 | Widget child = builder(context, shrinkOffset, overlapsContent); 41 | //测试代码:如果在调试模式,且子组件设置了key,则打印日志 42 | assert(() { 43 | if (child.key != null) { 44 | print('${child.key}: shrink: $shrinkOffset,overlaps:$overlapsContent'); 45 | } 46 | return true; 47 | }()); 48 | // 让 header 尽可能充满限制的空间;宽度为 Viewport 宽度, 49 | // 高度随着用户滑动在[minHeight,maxHeight]之间变化。 50 | return SizedBox.expand(child: child); 51 | } 52 | 53 | @override 54 | double get maxExtent => maxHeight; 55 | 56 | @override 57 | double get minExtent => minHeight; 58 | 59 | @override 60 | bool shouldRebuild(SliverHeaderDelegate old) { 61 | return old.maxExtent != maxExtent || old.minExtent != minExtent; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /lib/chapter11/http.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'dart:io'; 3 | 4 | import 'package:flutter/material.dart'; 5 | 6 | class HttpTestRoute extends StatefulWidget { 7 | @override 8 | _HttpTestRouteState createState() => _HttpTestRouteState(); 9 | } 10 | 11 | class _HttpTestRouteState extends State { 12 | bool _loading = false; 13 | String _text = ""; 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | return SingleChildScrollView( 18 | child: Column( 19 | children: [ 20 | ElevatedButton( 21 | child: Text("获取百度首页"), 22 | onPressed: _loading ? null : request, 23 | ), 24 | Container( 25 | width: MediaQuery.of(context).size.width - 50.0, 26 | child: Text(_text.replaceAll(RegExp(r"\s"), "")), 27 | ) 28 | ], 29 | ), 30 | ); 31 | } 32 | 33 | request() async { 34 | setState(() { 35 | _loading = true; 36 | _text = "正在请求..."; 37 | }); 38 | try { 39 | //创建一个HttpClient 40 | HttpClient httpClient = HttpClient(); 41 | //打开Http连接 42 | HttpClientRequest request = 43 | await httpClient.getUrl(Uri.parse("https://www.baidu.com")); 44 | //使用iPhone的UA 45 | request.headers.add( 46 | "user-agent", 47 | "Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_1 like Mac OS X) AppleWebKit/603.1.30 (KHTML, like Gecko) Version/10.0 Mobile/14E304 Safari/602.1", 48 | ); 49 | //等待连接服务器(会将请求信息发送给服务器) 50 | HttpClientResponse response = await request.close(); 51 | //读取响应内容 52 | _text = await response.transform(utf8.decoder).join(); 53 | //输出响应头 54 | print(response.headers); 55 | 56 | //关闭client后,通过该client发起的所有请求都会中止。 57 | httpClient.close(); 58 | } catch (e) { 59 | _text = "请求失败:$e"; 60 | } finally { 61 | setState(() { 62 | _loading = false; 63 | }); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /lib/common.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | import 'package:flutter/material.dart'; 3 | export 'widgets/index.dart'; 4 | import 'package:flukit/flukit.dart'; 5 | 6 | final logEmitter = ValueNotifier(null); 7 | 8 | void drawChessboard(Canvas canvas, Rect rect) { 9 | //棋盘背景 10 | var paint = Paint() 11 | ..isAntiAlias = true 12 | ..style = PaintingStyle.fill //填充 13 | ..color = const Color(0xFFDCC48C); 14 | canvas.drawRect(rect, paint); 15 | 16 | //画棋盘网格 17 | paint 18 | ..style = PaintingStyle.stroke //线 19 | ..color = Colors.black38 20 | ..strokeWidth = 1.0; 21 | 22 | //画横线 23 | for (int i = 0; i <= 15; ++i) { 24 | double dy = rect.top + rect.height / 15 * i; 25 | canvas.drawLine(Offset(rect.left, dy), Offset(rect.right, dy), paint); 26 | } 27 | 28 | for (int i = 0; i <= 15; ++i) { 29 | double dx = rect.left + rect.width / 15 * i; 30 | canvas.drawLine(Offset(dx, rect.top), Offset(dx, rect.bottom), paint); 31 | } 32 | } 33 | 34 | //画棋子 35 | void drawPieces(Canvas canvas, Rect rect) { 36 | double eWidth = rect.width / 15; 37 | double eHeight = rect.height / 15; 38 | //画一个黑子 39 | var paint = Paint() 40 | ..style = PaintingStyle.fill 41 | ..color = Colors.black; 42 | //画一个黑子 43 | canvas.drawCircle( 44 | Offset(rect.center.dx - eWidth / 2, rect.center.dy - eHeight / 2), 45 | min(eWidth / 2, eHeight / 2) - 2, 46 | paint, 47 | ); 48 | //画一个白子 49 | paint.color = Colors.white; 50 | canvas.drawCircle( 51 | Offset(rect.center.dx + eWidth / 2, rect.center.dy - eHeight / 2), 52 | min(eWidth / 2, eHeight / 2) - 2, 53 | paint, 54 | ); 55 | } 56 | 57 | Widget buildSliverList([int count = 5]) { 58 | return SliverFixedExtentList( 59 | itemExtent: 50, 60 | delegate: SliverChildBuilderDelegate( 61 | (context, index) { 62 | return ListTile(title: Text('$index'), onTap: () => print(index)); 63 | }, 64 | childCount: count, 65 | ), 66 | ); 67 | } 68 | -------------------------------------------------------------------------------- /lib/chapter2/getstate.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class GetStateObjectRoute extends StatefulWidget { 4 | const GetStateObjectRoute({Key? key}) : super(key: key); 5 | 6 | @override 7 | State createState() => _GetStateObjectRouteState(); 8 | } 9 | 10 | class _GetStateObjectRouteState extends State { 11 | @override 12 | Widget build(BuildContext context) { 13 | return Scaffold( 14 | appBar: AppBar( 15 | title: const Text("子树中获取State对象"), 16 | ), 17 | body: Center( 18 | child: Column( 19 | children: [ 20 | Builder(builder: (context) { 21 | return ElevatedButton( 22 | onPressed: () { 23 | // 查找父级最近的Scaffold对应的ScaffoldState对象 24 | ScaffoldState _state = context.findAncestorStateOfType()!; 25 | // 打开抽屉菜单 26 | _state.openDrawer(); 27 | }, 28 | child: const Text('打开抽屉菜单1'), 29 | ); 30 | }), 31 | Builder(builder: (context) { 32 | return ElevatedButton( 33 | onPressed: () { 34 | // 直接通过of静态方法来获取ScaffoldState 35 | ScaffoldState _state=Scaffold.of(context); 36 | // 打开抽屉菜单 37 | _state.openDrawer(); 38 | }, 39 | child: const Text('打开抽屉菜单2'), 40 | ); 41 | }), 42 | Builder(builder: (context) { 43 | return ElevatedButton( 44 | onPressed: () { 45 | ScaffoldMessenger.of(context).showSnackBar( 46 | const SnackBar(content: Text("我是SnackBar")), 47 | ); 48 | }, 49 | child: const Text('显示SnackBar'), 50 | ); 51 | }), 52 | ], 53 | ), 54 | ), 55 | drawer: const Drawer(), 56 | ); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /gitme/l10n-arb/intl_zh_CN.arb: -------------------------------------------------------------------------------- 1 | { 2 | "@@last_modified": "2019-04-30T15:02:44.753296", 3 | "title": "Github客户端", 4 | "@title": { 5 | "description": "Title for the Demo application", 6 | "type": "text", 7 | "placeholders": {} 8 | }, 9 | "home": "Github客户端", 10 | "@home": { 11 | "type": "text", 12 | "placeholders": {} 13 | }, 14 | "language": "语言", 15 | "@language": { 16 | "type": "text", 17 | "placeholders": {} 18 | }, 19 | "login": "登录", 20 | "@login": { 21 | "type": "text", 22 | "placeholders": {} 23 | }, 24 | "auto": "跟随系统", 25 | "@auto": { 26 | "type": "text", 27 | "placeholders": {} 28 | }, 29 | "setting": "设置", 30 | "@setting": { 31 | "type": "text", 32 | "placeholders": {} 33 | }, 34 | "theme": "换肤", 35 | "@theme": { 36 | "type": "text", 37 | "placeholders": {} 38 | }, 39 | "noDescription": "暂无描述!", 40 | "@noDescription": { 41 | "type": "text", 42 | "placeholders": {} 43 | }, 44 | "userName": "用户名", 45 | "@userName": { 46 | "type": "text", 47 | "placeholders": {} 48 | }, 49 | "userNameRequired": "用户名不能为空", 50 | "@userNameRequired": { 51 | "type": "text", 52 | "placeholders": {} 53 | }, 54 | "password": "密码", 55 | "@password": { 56 | "type": "text", 57 | "placeholders": {} 58 | }, 59 | "passwordRequired": "密码不能为空", 60 | "@passwordRequired": { 61 | "type": "text", 62 | "placeholders": {} 63 | }, 64 | "userNameOrPasswordWrong": "用户名或密码不正确", 65 | "@userNameOrPasswordWrong": { 66 | "type": "text", 67 | "placeholders": {} 68 | }, 69 | "logout": "注销", 70 | "@logout": { 71 | "type": "text", 72 | "placeholders": {} 73 | }, 74 | "logoutTip": "确定要退出当前账号吗?", 75 | "@logoutTip": { 76 | "type": "text", 77 | "placeholders": {} 78 | }, 79 | "yes": "确定", 80 | "@yes": { 81 | "type": "text", 82 | "placeholders": {} 83 | }, 84 | "cancel": "取消", 85 | "@cancel": { 86 | "type": "text", 87 | "placeholders": {} 88 | } 89 | } --------------------------------------------------------------------------------