├── sample ├── ios │ ├── Flutter │ │ ├── Debug.xcconfig │ │ ├── Release.xcconfig │ │ └── AppFrameworkInfo.plist │ ├── Runner │ │ ├── Runner-Bridging-Header.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 │ │ │ │ └── Contents.json │ │ ├── AppDelegate.swift │ │ ├── Base.lproj │ │ │ ├── Main.storyboard │ │ │ └── LaunchScreen.storyboard │ │ └── Info.plist │ ├── Runner.xcodeproj │ │ ├── project.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ │ ├── WorkspaceSettings.xcsettings │ │ │ │ └── IDEWorkspaceChecks.plist │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── Runner.xcscheme │ ├── Runner.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── WorkspaceSettings.xcsettings │ │ │ └── IDEWorkspaceChecks.plist │ └── .gitignore ├── web │ ├── favicon.png │ ├── icons │ │ ├── Icon-192.png │ │ ├── Icon-512.png │ │ ├── Icon-maskable-192.png │ │ └── Icon-maskable-512.png │ ├── manifest.json │ └── index.html ├── 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 │ │ │ │ │ └── com │ │ │ │ │ │ └── flutter │ │ │ │ │ │ └── sample │ │ │ │ │ │ └── MainActivity.kt │ │ │ │ └── AndroidManifest.xml │ │ │ ├── debug │ │ │ │ └── AndroidManifest.xml │ │ │ └── profile │ │ │ │ └── AndroidManifest.xml │ │ └── build.gradle │ ├── gradle │ │ └── wrapper │ │ │ └── gradle-wrapper.properties │ ├── .gitignore │ ├── settings.gradle │ └── build.gradle ├── assets │ └── images │ │ ├── long.png │ │ ├── normal.png │ │ └── short.png ├── .metadata ├── README.md ├── .gitignore ├── lib │ ├── ui │ │ ├── page │ │ │ ├── image_preview_demo.dart │ │ │ ├── image_crop_demo.dart │ │ │ ├── switch_demo.dart │ │ │ ├── slider_demo.dart │ │ │ ├── dropdown_demo.dart │ │ │ ├── checkbox_demo.dart │ │ │ ├── widget_list.dart │ │ │ ├── color_picker_demo.dart │ │ │ ├── button_demo.dart │ │ │ ├── rate_demo.dart │ │ │ ├── radio_demo.dart │ │ │ ├── text_field_demo.dart │ │ │ ├── border_demo.dart │ │ │ ├── input_number_demo.dart │ │ │ ├── image_demo.dart │ │ │ ├── page_view_demo.dart │ │ │ └── dialog_demo.dart │ │ ├── animations │ │ │ ├── animation_list.dart │ │ │ └── collapse_transition_demo.dart │ │ └── navigator_list.dart │ └── main.dart ├── test │ └── widget_test.dart ├── analysis_options.yaml └── pubspec.yaml ├── lib ├── lib │ ├── animations.dart │ ├── src │ │ ├── widgets │ │ │ ├── theme │ │ │ │ ├── button_style.dart │ │ │ │ ├── rate_style.dart │ │ │ │ ├── page_view_style.dart │ │ │ │ ├── switch_style.dart │ │ │ │ ├── dialog_style.dart │ │ │ │ ├── slider_style.dart │ │ │ │ ├── image_crop_style.dart │ │ │ │ ├── dropdown_style.dart │ │ │ │ ├── border_style.dart │ │ │ │ ├── text_field_style.dart │ │ │ │ ├── image_style.dart │ │ │ │ ├── input_number_style.dart │ │ │ │ ├── theme.dart │ │ │ │ ├── radio_style.dart │ │ │ │ └── checkbox_style.dart │ │ │ ├── switch.dart │ │ │ ├── slider.dart │ │ │ ├── checkbox.dart │ │ │ ├── image.dart │ │ │ ├── image_preview.dart │ │ │ ├── radio.dart │ │ │ ├── border.dart │ │ │ └── button.dart │ │ └── animations │ │ │ └── collapse_transition.dart │ └── widgets.dart ├── analysis_options.yaml ├── CHANGELOG.md ├── .metadata ├── .gitignore ├── pubspec.yaml └── README.md ├── imgs ├── WX20220115-094720@2x.png ├── WX20220115-094741@2x.png ├── WX20220115-094753@2x.png ├── WX20220115-094803@2x.png ├── WX20220115-094815@2x.png ├── WX20220115-094826@2x.png ├── WX20220115-094851@2x.png ├── WX20220115-094905@2x.png ├── WX20220115-094913@2x.png ├── WX20220115-094923@2x.png ├── WX20220115-094932@2x.png ├── WX20220115-094942@2x.png └── WX20220115-094951@2x.png ├── .gitignore └── README.md /sample/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /sample/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /sample/ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /lib/lib/animations.dart: -------------------------------------------------------------------------------- 1 | library element_ui; 2 | 3 | export 'src/animations/collapse_transition.dart'; 4 | -------------------------------------------------------------------------------- /sample/web/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaoMengFlutter/flutter_element/HEAD/sample/web/favicon.png -------------------------------------------------------------------------------- /imgs/WX20220115-094720@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaoMengFlutter/flutter_element/HEAD/imgs/WX20220115-094720@2x.png -------------------------------------------------------------------------------- /imgs/WX20220115-094741@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaoMengFlutter/flutter_element/HEAD/imgs/WX20220115-094741@2x.png -------------------------------------------------------------------------------- /imgs/WX20220115-094753@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaoMengFlutter/flutter_element/HEAD/imgs/WX20220115-094753@2x.png -------------------------------------------------------------------------------- /imgs/WX20220115-094803@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaoMengFlutter/flutter_element/HEAD/imgs/WX20220115-094803@2x.png -------------------------------------------------------------------------------- /imgs/WX20220115-094815@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaoMengFlutter/flutter_element/HEAD/imgs/WX20220115-094815@2x.png -------------------------------------------------------------------------------- /imgs/WX20220115-094826@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaoMengFlutter/flutter_element/HEAD/imgs/WX20220115-094826@2x.png -------------------------------------------------------------------------------- /imgs/WX20220115-094851@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaoMengFlutter/flutter_element/HEAD/imgs/WX20220115-094851@2x.png -------------------------------------------------------------------------------- /imgs/WX20220115-094905@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaoMengFlutter/flutter_element/HEAD/imgs/WX20220115-094905@2x.png -------------------------------------------------------------------------------- /imgs/WX20220115-094913@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaoMengFlutter/flutter_element/HEAD/imgs/WX20220115-094913@2x.png -------------------------------------------------------------------------------- /imgs/WX20220115-094923@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaoMengFlutter/flutter_element/HEAD/imgs/WX20220115-094923@2x.png -------------------------------------------------------------------------------- /imgs/WX20220115-094932@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaoMengFlutter/flutter_element/HEAD/imgs/WX20220115-094932@2x.png -------------------------------------------------------------------------------- /imgs/WX20220115-094942@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaoMengFlutter/flutter_element/HEAD/imgs/WX20220115-094942@2x.png -------------------------------------------------------------------------------- /imgs/WX20220115-094951@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaoMengFlutter/flutter_element/HEAD/imgs/WX20220115-094951@2x.png -------------------------------------------------------------------------------- /sample/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /sample/assets/images/long.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaoMengFlutter/flutter_element/HEAD/sample/assets/images/long.png -------------------------------------------------------------------------------- /sample/assets/images/normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaoMengFlutter/flutter_element/HEAD/sample/assets/images/normal.png -------------------------------------------------------------------------------- /sample/assets/images/short.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaoMengFlutter/flutter_element/HEAD/sample/assets/images/short.png -------------------------------------------------------------------------------- /sample/web/icons/Icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaoMengFlutter/flutter_element/HEAD/sample/web/icons/Icon-192.png -------------------------------------------------------------------------------- /sample/web/icons/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaoMengFlutter/flutter_element/HEAD/sample/web/icons/Icon-512.png -------------------------------------------------------------------------------- /sample/web/icons/Icon-maskable-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaoMengFlutter/flutter_element/HEAD/sample/web/icons/Icon-maskable-192.png -------------------------------------------------------------------------------- /sample/web/icons/Icon-maskable-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaoMengFlutter/flutter_element/HEAD/sample/web/icons/Icon-maskable-512.png -------------------------------------------------------------------------------- /sample/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaoMengFlutter/flutter_element/HEAD/sample/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaoMengFlutter/flutter_element/HEAD/sample/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaoMengFlutter/flutter_element/HEAD/sample/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaoMengFlutter/flutter_element/HEAD/sample/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaoMengFlutter/flutter_element/HEAD/sample/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /lib/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:flutter_lints/flutter.yaml 2 | 3 | # Additional information about this file can be found at 4 | # https://dart.dev/guides/language/analysis-options 5 | -------------------------------------------------------------------------------- /sample/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaoMengFlutter/flutter_element/HEAD/sample/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /sample/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaoMengFlutter/flutter_element/HEAD/sample/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /sample/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaoMengFlutter/flutter_element/HEAD/sample/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /sample/android/app/src/main/kotlin/com/flutter/sample/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.flutter.sample 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaoMengFlutter/flutter_element/HEAD/sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaoMengFlutter/flutter_element/HEAD/sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaoMengFlutter/flutter_element/HEAD/sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaoMengFlutter/flutter_element/HEAD/sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaoMengFlutter/flutter_element/HEAD/sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaoMengFlutter/flutter_element/HEAD/sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaoMengFlutter/flutter_element/HEAD/sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaoMengFlutter/flutter_element/HEAD/sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaoMengFlutter/flutter_element/HEAD/sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaoMengFlutter/flutter_element/HEAD/sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaoMengFlutter/flutter_element/HEAD/sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaoMengFlutter/flutter_element/HEAD/sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaoMengFlutter/flutter_element/HEAD/sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaoMengFlutter/flutter_element/HEAD/sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaoMengFlutter/flutter_element/HEAD/sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /sample/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /sample/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /lib/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.0.1 2 | 3 | * add EBorder EButton ETextField widget. 4 | 5 | ## 0.1.0 6 | 7 | * add some widget and bug fixed. 8 | 9 | ## 0.1.1 10 | 11 | * bug fixed. 12 | 13 | ## 0.1.2 14 | 15 | * bug fixed. 16 | 17 | ## 0.1.3 18 | 19 | * bug fixed. -------------------------------------------------------------------------------- /sample/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 | -------------------------------------------------------------------------------- /sample/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /sample/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /sample/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /sample/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /lib/.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: 18116933e77adc82f80866c928266a5b4f1ed645 8 | channel: stable 9 | 10 | project_type: package 11 | -------------------------------------------------------------------------------- /sample/.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: 18116933e77adc82f80866c928266a5b4f1ed645 8 | channel: stable 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /sample/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 | -------------------------------------------------------------------------------- /sample/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /sample/android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /sample/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. -------------------------------------------------------------------------------- /sample/ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @UIApplicationMain 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /sample/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 | -------------------------------------------------------------------------------- /sample/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /sample/android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /sample/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 | -------------------------------------------------------------------------------- /sample/README.md: -------------------------------------------------------------------------------- 1 | # sample 2 | 3 | A new Flutter application. 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/lib/src/widgets/theme/button_style.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class EButtonStyle with Diagnosticable { 5 | final Color? loadingColor; 6 | 7 | /// radius 8 | final BorderRadius? radius; 9 | 10 | const EButtonStyle({ 11 | this.loadingColor, 12 | this.radius, 13 | }); 14 | 15 | EButtonStyle merge(EButtonStyle? other) { 16 | if (other == null) { 17 | return this; 18 | } 19 | return EButtonStyle( 20 | loadingColor: other.loadingColor ?? loadingColor, 21 | radius: other.radius ?? radius, 22 | ); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lib/lib/src/widgets/theme/rate_style.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | import 'package:flutter/cupertino.dart'; 4 | import 'package:flutter/foundation.dart'; 5 | 6 | class ERateStyle with Diagnosticable { 7 | final Color? activeColor; 8 | final Color? inactiveColor; 9 | 10 | ERateStyle({ 11 | this.activeColor, 12 | this.inactiveColor, 13 | }); 14 | 15 | ERateStyle merge(ERateStyle? other) { 16 | if (other == null) { 17 | return this; 18 | } 19 | return ERateStyle( 20 | activeColor: other.activeColor ?? activeColor, 21 | inactiveColor: other.inactiveColor ?? inactiveColor, 22 | ); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lib/lib/src/widgets/theme/page_view_style.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | import 'package:flutter/foundation.dart'; 4 | 5 | class EPageViewStyle with Diagnosticable { 6 | final Color? indicatorColor; 7 | final Color? indicatorActiveColor; 8 | 9 | EPageViewStyle({ 10 | this.indicatorColor, 11 | this.indicatorActiveColor, 12 | }); 13 | 14 | EPageViewStyle merge(EPageViewStyle? other) { 15 | if (other == null) { 16 | return this; 17 | } 18 | return EPageViewStyle( 19 | indicatorColor: other.indicatorColor ?? indicatorColor, 20 | indicatorActiveColor: other.indicatorActiveColor ?? indicatorActiveColor, 21 | ); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://www.dartlang.org/guides/libraries/private-files 2 | 3 | # Files and directories created by pub 4 | .dart_tool/ 5 | .packages 6 | build/ 7 | # If you're building an application, you may want to check-in your pubspec.lock 8 | pubspec.lock 9 | 10 | # Directory created by dartdoc 11 | # If you don't generate documentation locally you can remove this line. 12 | doc/api/ 13 | 14 | # Avoid committing generated Javascript files: 15 | *.dart.js 16 | *.info.json # Produced by the --dump-info flag. 17 | *.js # When generated by dart2js. Don't specify *.js if your 18 | # project includes source files written in JavaScript. 19 | *.js_ 20 | *.js.deps 21 | *.js.map 22 | /.idea -------------------------------------------------------------------------------- /sample/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 | -------------------------------------------------------------------------------- /sample/ios/.gitignore: -------------------------------------------------------------------------------- 1 | **/dgph 2 | *.mode1v3 3 | *.mode2v3 4 | *.moved-aside 5 | *.pbxuser 6 | *.perspectivev3 7 | **/*sync/ 8 | .sconsign.dblite 9 | .tags* 10 | **/.vagrant/ 11 | **/DerivedData/ 12 | Icon? 13 | **/Pods/ 14 | **/.symlinks/ 15 | profile 16 | xcuserdata 17 | **/.generated/ 18 | Flutter/App.framework 19 | Flutter/Flutter.framework 20 | Flutter/Flutter.podspec 21 | Flutter/Generated.xcconfig 22 | Flutter/ephemeral/ 23 | Flutter/app.flx 24 | Flutter/app.zip 25 | Flutter/flutter_assets/ 26 | Flutter/flutter_export_environment.sh 27 | ServiceDefinitions.json 28 | Runner/GeneratedPluginRegistrant.* 29 | 30 | # Exceptions to above rules. 31 | !default.mode1v3 32 | !default.mode2v3 33 | !default.pbxuser 34 | !default.perspectivev3 35 | -------------------------------------------------------------------------------- /lib/lib/src/widgets/theme/switch_style.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | import 'package:flutter/cupertino.dart'; 4 | import 'package:flutter/foundation.dart'; 5 | 6 | class ESwitchStyle with Diagnosticable { 7 | final Color? activeColor; 8 | final Color? trackColor; 9 | final Color? thumbColor; 10 | 11 | ESwitchStyle({ 12 | this.activeColor, 13 | this.trackColor, 14 | this.thumbColor, 15 | }); 16 | 17 | ESwitchStyle merge(ESwitchStyle? other) { 18 | if (other == null) { 19 | return this; 20 | } 21 | return ESwitchStyle( 22 | activeColor: other.activeColor ?? activeColor, 23 | trackColor: other.trackColor ?? trackColor, 24 | thumbColor: other.thumbColor ?? thumbColor, 25 | ); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lib/lib/src/widgets/theme/dialog_style.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/foundation.dart'; 3 | 4 | class EDialogStyle with Diagnosticable { 5 | final Color? backgroundColor; 6 | final Color? borderColor; 7 | final BorderRadius? borderRadius; 8 | 9 | EDialogStyle({ 10 | this.backgroundColor, 11 | this.borderColor, 12 | this.borderRadius, 13 | }); 14 | 15 | EDialogStyle merge(EDialogStyle? other) { 16 | if (other == null) { 17 | return this; 18 | } 19 | return EDialogStyle( 20 | backgroundColor: other.backgroundColor ?? backgroundColor, 21 | borderColor: other.borderColor ?? borderColor, 22 | borderRadius: other.borderRadius ?? borderRadius, 23 | ); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lib/lib/src/widgets/theme/slider_style.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | import 'package:flutter/cupertino.dart'; 4 | import 'package:flutter/foundation.dart'; 5 | 6 | class ESliderStyle with Diagnosticable { 7 | final Color? activeColor; 8 | final Color? inactiveColor; 9 | final Color? thumbColor; 10 | 11 | ESliderStyle({ 12 | this.activeColor, 13 | this.inactiveColor, 14 | this.thumbColor, 15 | }); 16 | 17 | ESliderStyle merge(ESliderStyle? other) { 18 | if (other == null) { 19 | return this; 20 | } 21 | return ESliderStyle( 22 | activeColor: other.activeColor ?? activeColor, 23 | inactiveColor: other.inactiveColor ?? inactiveColor, 24 | thumbColor: other.thumbColor ?? thumbColor, 25 | ); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lib/lib/src/widgets/theme/image_crop_style.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | import 'package:flutter/cupertino.dart'; 4 | import 'package:flutter/foundation.dart'; 5 | 6 | class EImageCropStyle with Diagnosticable { 7 | final Color? borderColor; 8 | 9 | final double? borderWidget; 10 | 11 | final double? borderRadius; 12 | 13 | EImageCropStyle({ 14 | this.borderColor, 15 | this.borderWidget, 16 | this.borderRadius, 17 | }); 18 | 19 | EImageCropStyle merge(EImageCropStyle? other) { 20 | if (other == null) { 21 | return this; 22 | } 23 | return EImageCropStyle( 24 | borderColor: other.borderColor ?? borderColor, 25 | borderWidget: other.borderWidget ?? borderWidget, 26 | borderRadius: other.borderRadius ?? borderRadius, 27 | ); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /sample/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 | -------------------------------------------------------------------------------- /sample/.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/lib/src/widgets/theme/dropdown_style.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | import 'package:flutter/cupertino.dart'; 4 | import 'package:flutter/foundation.dart'; 5 | 6 | class EDropdownStyle with Diagnosticable { 7 | final Color? dropdownBorderColor; 8 | final Color? dropdownFocusBorderColor; 9 | final Color? fontColor; 10 | final Color? selectFontColor; 11 | 12 | EDropdownStyle({ 13 | this.fontColor, 14 | this.selectFontColor, 15 | this.dropdownBorderColor, 16 | this.dropdownFocusBorderColor, 17 | }); 18 | 19 | EDropdownStyle merge(EDropdownStyle? other) { 20 | if (other == null) { 21 | return this; 22 | } 23 | return EDropdownStyle( 24 | fontColor: other.fontColor ?? fontColor, 25 | selectFontColor: other.selectFontColor ?? selectFontColor, 26 | dropdownBorderColor: other.dropdownBorderColor ?? dropdownBorderColor, 27 | dropdownFocusBorderColor: 28 | other.dropdownFocusBorderColor ?? dropdownFocusBorderColor, 29 | ); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /sample/web/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sample", 3 | "short_name": "sample", 4 | "start_url": ".", 5 | "display": "standalone", 6 | "background_color": "#0175C2", 7 | "theme_color": "#0175C2", 8 | "description": "A new Flutter application.", 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 | "src": "icons/Icon-maskable-192.png", 24 | "sizes": "192x192", 25 | "type": "image/png", 26 | "purpose": "maskable" 27 | }, 28 | { 29 | "src": "icons/Icon-maskable-512.png", 30 | "sizes": "512x512", 31 | "type": "image/png", 32 | "purpose": "maskable" 33 | } 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /sample/lib/ui/page/image_preview_demo.dart: -------------------------------------------------------------------------------- 1 | // import 'package:flutter/material.dart'; 2 | // import 'package:element_ui/widgets.dart'; 3 | // 4 | // class ImagePreviewDemo extends StatefulWidget { 5 | // const ImagePreviewDemo({Key? key}) : super(key: key); 6 | // 7 | // @override 8 | // State createState() => _ImagePreviewDemoState(); 9 | // } 10 | // 11 | // class _ImagePreviewDemoState extends State { 12 | // // final cropKey = GlobalKey(); 13 | // 14 | // @override 15 | // Widget build(BuildContext context) { 16 | // return Scaffold( 17 | // appBar: AppBar(), 18 | // body: Container( 19 | // padding: EdgeInsets.all(30), 20 | // child: 21 | // // Crop( 22 | // // key: cropKey, 23 | // // image: AssetImage('assets/images/short.png'), 24 | // // aspectRatio: 4.0 / 3.0, 25 | // // ), 26 | // EImagePreview( 27 | // imageProvider: AssetImage('assets/images/long.png'), 28 | // ), 29 | // ), 30 | // ); 31 | // } 32 | // } 33 | -------------------------------------------------------------------------------- /sample/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /sample/android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /lib/lib/src/widgets/theme/border_style.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class EBorderStyle with Diagnosticable { 5 | /// 线的颜色 6 | final Color? color; 7 | 8 | /// 宽 9 | final double? strokeWidth; 10 | 11 | /// 虚线空白处宽 12 | final double? dashGap; 13 | 14 | /// 虚线处宽 15 | final double? dashWidth; 16 | 17 | /// 虚线处宽 18 | final EdgeInsetsGeometry? padding; 19 | 20 | /// 圆角 21 | final BorderRadius? radius; 22 | 23 | const EBorderStyle({ 24 | this.color, 25 | this.strokeWidth, 26 | this.dashGap, 27 | this.dashWidth, 28 | this.radius, 29 | this.padding, 30 | }); 31 | 32 | EBorderStyle merge(EBorderStyle? other) { 33 | if (other == null) { 34 | return this; 35 | } 36 | return EBorderStyle( 37 | color: other.color ?? color, 38 | strokeWidth: other.strokeWidth ?? strokeWidth, 39 | dashGap: other.dashGap ?? dashGap, 40 | dashWidth: other.dashWidth ?? dashWidth, 41 | radius: other.radius ?? radius, 42 | padding: other.padding ?? padding, 43 | ); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /sample/lib/ui/animations/animation_list.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import 'collapse_transition_demo.dart'; 4 | 5 | class AnimationList extends StatelessWidget { 6 | AnimationList({Key? key}) : super(key: key); 7 | 8 | final List _data = [ 9 | {'title': 'CollapseTransition', 'page': const CollapseTransitionDemo()}, 10 | ]; 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | return Scaffold( 15 | appBar: AppBar(), 16 | body: ListView.separated( 17 | itemBuilder: (context, index) { 18 | return GestureDetector( 19 | onTap: () { 20 | Navigator.of(context) 21 | .push(MaterialPageRoute(builder: (context) { 22 | return _data[index]['page']; 23 | })); 24 | }, 25 | child: ListTile( 26 | title: Text('${_data[index]['title']}'), 27 | ), 28 | ); 29 | }, 30 | separatorBuilder: (context, index) { 31 | return const Divider(); 32 | }, 33 | itemCount: _data.length), 34 | ); 35 | } 36 | } -------------------------------------------------------------------------------- /sample/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:sample/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(const 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 | -------------------------------------------------------------------------------- /sample/lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import 'package:element_ui/widgets.dart'; 4 | import 'package:sample/ui/navigator_list.dart'; 5 | 6 | import 'ui/page/widget_list.dart'; 7 | 8 | void main() { 9 | runApp(const MyApp()); 10 | } 11 | 12 | class MyApp extends StatelessWidget { 13 | const MyApp({Key? key}) : super(key: key); 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | return MaterialApp( 18 | title: 'Flutter Demo', 19 | theme: ThemeData(primarySwatch: Colors.blue), 20 | home: EleTheme( 21 | data: EleThemeData( 22 | primaryColor: Colors.blue, 23 | imageStyle: EImageStyle( 24 | errorWidget: Container( 25 | color: Colors.grey.withOpacity(.3), 26 | alignment: Alignment.center, 27 | child: Text( 28 | '加载失败', 29 | style: TextStyle(color: Colors.white), 30 | ), 31 | ), 32 | placeholderWidget: Container( 33 | color: Colors.grey.withOpacity(.3), 34 | ), 35 | ), 36 | ), 37 | child: NavigatorList(), 38 | ), 39 | ); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /sample/lib/ui/navigator_list.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import 'animations/animation_list.dart'; 4 | import 'page/widget_list.dart'; 5 | 6 | class NavigatorList extends StatelessWidget { 7 | NavigatorList({Key? key}) : super(key: key); 8 | 9 | final List _data = [ 10 | {'title': 'Widget', 'page': WidgetList()}, 11 | {'title': 'Animation', 'page': AnimationList()}, 12 | ]; 13 | 14 | @override 15 | Widget build(BuildContext context) { 16 | return Scaffold( 17 | appBar: AppBar(), 18 | body: ListView.separated( 19 | itemBuilder: (context, index) { 20 | return GestureDetector( 21 | onTap: () { 22 | Navigator.of(context) 23 | .push(MaterialPageRoute(builder: (context) { 24 | return _data[index]['page']; 25 | })); 26 | }, 27 | child: ListTile( 28 | title: Text('${_data[index]['title']}'), 29 | ), 30 | ); 31 | }, 32 | separatorBuilder: (context, index) { 33 | return const Divider(); 34 | }, 35 | itemCount: _data.length), 36 | ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /lib/lib/src/widgets/theme/text_field_style.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/foundation.dart'; 3 | 4 | class ETextFieldStyle with Diagnosticable { 5 | final Color? fontColor; 6 | final Color? backgroundColor; 7 | final Color? placeholderColor; 8 | final Color? borderColor; 9 | final Color? focusBorderColor; 10 | final Color? clearColor; 11 | final BorderRadius? borderRadius; 12 | 13 | ETextFieldStyle({ 14 | this.fontColor, 15 | this.backgroundColor, 16 | this.placeholderColor, 17 | this.borderColor, 18 | this.focusBorderColor, 19 | this.borderRadius, 20 | this.clearColor, 21 | }); 22 | 23 | ETextFieldStyle merge(ETextFieldStyle? other) { 24 | if (other == null) { 25 | return this; 26 | } 27 | return ETextFieldStyle( 28 | fontColor: other.fontColor ?? fontColor, 29 | backgroundColor: other.backgroundColor ?? backgroundColor, 30 | placeholderColor: other.placeholderColor ?? placeholderColor, 31 | borderColor: other.borderColor ?? borderColor, 32 | focusBorderColor: other.focusBorderColor ?? focusBorderColor, 33 | borderRadius: other.borderRadius ?? borderRadius, 34 | clearColor: other.clearColor ?? clearColor, 35 | ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /sample/lib/ui/page/image_crop_demo.dart: -------------------------------------------------------------------------------- 1 | // import 'package:flutter/material.dart'; 2 | // import 'package:element_ui/widgets.dart'; 3 | // import 'package:image_crop/image_crop.dart'; 4 | // 5 | // class ImageCropDemo extends StatefulWidget { 6 | // const ImageCropDemo({Key? key}) : super(key: key); 7 | // 8 | // @override 9 | // _ImageCropDemoState createState() => _ImageCropDemoState(); 10 | // } 11 | // 12 | // class _ImageCropDemoState extends State { 13 | // final cropKey = GlobalKey(); 14 | // 15 | // @override 16 | // Widget build(BuildContext context) { 17 | // return Scaffold( 18 | // appBar: AppBar(), 19 | // body: Container( 20 | // color: Colors.black, 21 | // padding: const EdgeInsets.all(20.0), 22 | // child: 23 | // // EImageCrop( 24 | // // image: NetworkImage( 25 | // // 'https://img0.baidu.com/it/u=1868816884,3782068186&fm=26&fmt=auto'), 26 | // // ) 27 | // Crop( 28 | // key: cropKey, 29 | // image: NetworkImage( 30 | // 'https://avatars0.githubusercontent.com/u/8264639?s=460&v=4'), 31 | // aspectRatio: 4.0 / 3.0, 32 | // ), 33 | // ), 34 | // ); 35 | // } 36 | // } 37 | -------------------------------------------------------------------------------- /lib/lib/src/widgets/theme/image_style.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/foundation.dart'; 3 | 4 | Widget _kPlaceholderWidget = Container(); 5 | 6 | class EImageStyle with Diagnosticable { 7 | /// placeholderWidget 8 | final Widget? placeholderWidget; 9 | 10 | /// errorWidget 11 | final Widget? errorWidget; 12 | 13 | const EImageStyle({ 14 | this.placeholderWidget, 15 | this.errorWidget, 16 | }); 17 | 18 | EImageStyle copyWith({ 19 | Widget? placeholderWidget, 20 | Widget? errorWidget, 21 | }) { 22 | return EImageStyle( 23 | placeholderWidget: placeholderWidget ?? this.placeholderWidget, 24 | errorWidget: errorWidget ?? this.errorWidget, 25 | ); 26 | } 27 | 28 | EImageStyle merge(EImageStyle? other) { 29 | if (other == null) { 30 | return this; 31 | } 32 | return EImageStyle( 33 | placeholderWidget: other.placeholderWidget ?? placeholderWidget, 34 | errorWidget: other.errorWidget ?? errorWidget, 35 | ); 36 | } 37 | 38 | factory EImageStyle.from(Color color) { 39 | return EImageStyle( 40 | placeholderWidget: Container( 41 | color: color, 42 | ), 43 | errorWidget: Container( 44 | color: color, 45 | )); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /lib/lib/src/widgets/theme/input_number_style.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class EInputNumberStyle with Diagnosticable { 5 | final Color? fontColor; 6 | final Color? backgroundColor; 7 | final Color? borderColor; 8 | final Color? focusBorderColor; 9 | final Color? iconColor; 10 | final Color? iconBackgroundColor; 11 | final BorderRadius? borderRadius; 12 | 13 | const EInputNumberStyle({ 14 | this.fontColor, 15 | this.backgroundColor, 16 | this.borderColor, 17 | this.focusBorderColor, 18 | this.iconColor, 19 | this.iconBackgroundColor, 20 | this.borderRadius, 21 | }); 22 | 23 | EInputNumberStyle merge(EInputNumberStyle? other) { 24 | if (other == null) { 25 | return this; 26 | } 27 | return EInputNumberStyle( 28 | fontColor: other.fontColor ?? fontColor, 29 | backgroundColor: other.backgroundColor ?? backgroundColor, 30 | borderColor: other.borderColor ?? borderColor, 31 | focusBorderColor: other.focusBorderColor ?? focusBorderColor, 32 | iconColor: other.iconColor ?? iconColor, 33 | iconBackgroundColor: other.iconBackgroundColor ?? iconBackgroundColor, 34 | borderRadius: other.borderRadius ?? borderRadius, 35 | ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /sample/lib/ui/page/switch_demo.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:element_ui/widgets.dart'; 3 | 4 | class SwitchDemo extends StatelessWidget { 5 | const SwitchDemo({Key? key}) : super(key: key); 6 | 7 | @override 8 | Widget build(BuildContext context) { 9 | return Scaffold( 10 | appBar: AppBar(), 11 | backgroundColor: Colors.white, 12 | body: Padding( 13 | padding: EdgeInsets.all(12), 14 | child: Column( 15 | children: [ 16 | SizedBox(height: 12), 17 | ESwitch(), 18 | SizedBox(height: 12), 19 | ESwitch( 20 | value: true, 21 | ), 22 | SizedBox(height: 12), 23 | ESwitch( 24 | value: true, 25 | onChanged: (value) {}, 26 | ), 27 | SizedBox(height: 12), 28 | ESwitch( 29 | enable: false, 30 | ), 31 | SizedBox(height: 12), 32 | ESwitch( 33 | style: ESwitchStyle( 34 | activeColor: Colors.green, 35 | trackColor: Colors.red, 36 | thumbColor: Colors.blue, 37 | ), 38 | ), 39 | ], 40 | ), 41 | ), 42 | ); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /lib/lib/src/widgets/theme/theme.dart: -------------------------------------------------------------------------------- 1 | 2 | 3 | import 'package:flutter/cupertino.dart'; 4 | import 'package:flutter/foundation.dart'; 5 | 6 | import 'theme_data.dart'; 7 | 8 | 9 | class EleTheme extends StatelessWidget { 10 | const EleTheme({ 11 | Key? key, 12 | required this.data, 13 | required this.child, 14 | }) : super(key: key); 15 | 16 | /// theme data 17 | final EleThemeData data; 18 | 19 | /// child 20 | final Widget child; 21 | 22 | static final EleThemeData _kDefaultTheme = EleThemeData.light(); 23 | 24 | static EleThemeData of(BuildContext context) { 25 | final _InheritedTheme? inheritedTheme = 26 | context.dependOnInheritedWidgetOfExactType<_InheritedTheme>(); 27 | return inheritedTheme?.theme.data ?? _kDefaultTheme; 28 | } 29 | 30 | @override 31 | Widget build(BuildContext context) { 32 | return _InheritedTheme( 33 | theme: this, 34 | child: child, 35 | ); 36 | } 37 | } 38 | 39 | class _InheritedTheme extends InheritedTheme { 40 | const _InheritedTheme({ 41 | Key? key, 42 | required this.theme, 43 | required Widget child, 44 | }) : assert(theme != null), 45 | super(key: key, child: child); 46 | 47 | final EleTheme theme; 48 | 49 | @override 50 | Widget wrap(BuildContext context, Widget child) { 51 | return EleTheme(data: theme.data, child: child); 52 | } 53 | 54 | @override 55 | bool updateShouldNotify(_InheritedTheme old) => theme.data != old.theme.data; 56 | } 57 | -------------------------------------------------------------------------------- /lib/lib/widgets.dart: -------------------------------------------------------------------------------- 1 | library element_ui; 2 | 3 | export 'src/widgets/theme/theme.dart'; 4 | export 'src/widgets/theme/theme_data.dart'; 5 | export 'src/widgets/theme/border_style.dart'; 6 | export 'src/widgets/theme/button_style.dart'; 7 | export 'src/widgets/theme/image_style.dart'; 8 | export 'src/widgets/theme/radio_style.dart'; 9 | export 'src/widgets/theme/checkbox_style.dart'; 10 | export 'src/widgets/theme/text_field_style.dart'; 11 | export 'src/widgets/theme/input_number_style.dart'; 12 | export 'src/widgets/theme/switch_style.dart'; 13 | export 'src/widgets/theme/slider_style.dart'; 14 | export 'src/widgets/theme/rate_style.dart'; 15 | export 'src/widgets/theme/image_crop_style.dart'; 16 | export 'src/widgets/theme/dropdown_style.dart'; 17 | export 'src/widgets/theme/page_view_style.dart'; 18 | export 'src/widgets/theme/dialog_style.dart'; 19 | 20 | export 'src/widgets/border.dart'; 21 | export 'src/widgets/button.dart'; 22 | export 'src/widgets/image.dart'; 23 | export 'src/widgets/progress.dart'; 24 | export 'src/widgets/radio.dart'; 25 | export 'src/widgets/checkbox.dart'; 26 | export 'src/widgets/text_field.dart'; 27 | export 'src/widgets/input_number.dart'; 28 | export 'src/widgets/switch.dart'; 29 | export 'src/widgets/slider.dart'; 30 | export 'src/widgets/rate.dart'; 31 | 32 | // export 'src/widgets/image_crop.dart'; 33 | // export 'src/widgets/image_preview.dart'; 34 | export 'src/widgets/dropdown.dart'; 35 | export 'src/widgets/color_picker.dart'; 36 | export 'src/widgets/page_view.dart'; 37 | export 'src/widgets/dialog.dart'; 38 | -------------------------------------------------------------------------------- /sample/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/lib/src/widgets/theme/radio_style.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | import 'package:flutter/cupertino.dart'; 4 | import 'package:flutter/foundation.dart'; 5 | 6 | class ERadioStyle with Diagnosticable { 7 | final Color? fontColor; 8 | final Color? checkedFontColor; 9 | final Color? backgroundColor; 10 | final Color? checkedBackgroundColor; 11 | final Color? borderColor; 12 | final Color? checkedBorderColor; 13 | final BorderRadius? borderRadius; 14 | final EdgeInsets? padding; 15 | 16 | /// The distance between the radio and the label 17 | final double? space; 18 | 19 | ERadioStyle({ 20 | this.fontColor, 21 | this.checkedFontColor, 22 | this.backgroundColor, 23 | this.checkedBackgroundColor, 24 | this.borderColor, 25 | this.checkedBorderColor, 26 | this.borderRadius, 27 | this.padding, 28 | this.space, 29 | }); 30 | 31 | ERadioStyle merge(ERadioStyle? other) { 32 | if (other == null) { 33 | return this; 34 | } 35 | return ERadioStyle( 36 | fontColor: other.fontColor ?? fontColor, 37 | checkedFontColor: other.checkedFontColor ?? checkedFontColor, 38 | backgroundColor: other.backgroundColor ?? backgroundColor, 39 | checkedBackgroundColor: 40 | other.checkedBackgroundColor ?? checkedBackgroundColor, 41 | borderColor: other.borderColor ?? borderColor, 42 | checkedBorderColor: other.checkedBorderColor ?? checkedBorderColor, 43 | borderRadius: other.borderRadius ?? borderRadius, 44 | padding: other.padding ?? padding, 45 | space: other.space ?? space, 46 | ); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /lib/lib/src/widgets/theme/checkbox_style.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | import 'package:flutter/cupertino.dart'; 4 | import 'package:flutter/foundation.dart'; 5 | 6 | class ECheckboxStyle with Diagnosticable { 7 | final Color? fontColor; 8 | final Color? checkedFontColor; 9 | final Color? backgroundColor; 10 | final Color? checkedBackgroundColor; 11 | final Color? borderColor; 12 | final Color? checkedBorderColor; 13 | final EdgeInsets? padding; 14 | final BorderRadius? borderRadius; 15 | 16 | /// The distance between the checkbox and the label 17 | final double? space; 18 | 19 | ECheckboxStyle({ 20 | this.fontColor, 21 | this.checkedFontColor, 22 | this.backgroundColor, 23 | this.checkedBackgroundColor, 24 | this.borderColor, 25 | this.checkedBorderColor, 26 | this.borderRadius, 27 | this.padding, 28 | this.space, 29 | }); 30 | 31 | ECheckboxStyle merge(ECheckboxStyle? other) { 32 | if (other == null) { 33 | return this; 34 | } 35 | return ECheckboxStyle( 36 | fontColor: other.fontColor ?? fontColor, 37 | checkedFontColor: other.checkedFontColor ?? checkedFontColor, 38 | backgroundColor: other.backgroundColor ?? backgroundColor, 39 | checkedBackgroundColor: 40 | other.checkedBackgroundColor ?? checkedBackgroundColor, 41 | borderColor: other.borderColor ?? borderColor, 42 | checkedBorderColor: other.checkedBorderColor ?? checkedBorderColor, 43 | borderRadius: other.borderRadius ?? borderRadius, 44 | padding: other.padding ?? padding, 45 | space: other.space ?? space, 46 | ); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /sample/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 | -------------------------------------------------------------------------------- /sample/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 | sample 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 | -------------------------------------------------------------------------------- /sample/lib/ui/page/slider_demo.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:element_ui/widgets.dart'; 3 | 4 | class SliderDemo extends StatelessWidget { 5 | const SliderDemo({Key? key}) : super(key: key); 6 | 7 | @override 8 | Widget build(BuildContext context) { 9 | return Scaffold( 10 | appBar: AppBar(), 11 | backgroundColor: Colors.white, 12 | body: Padding( 13 | padding: EdgeInsets.all(12), 14 | child: Column( 15 | children: [ 16 | SizedBox(height: 12), 17 | ESlider(), 18 | SizedBox(height: 12), 19 | ESlider(value: .5), 20 | SizedBox(height: 12), 21 | ESlider( 22 | value: 0, 23 | min: 0, 24 | max: 10, 25 | divisions: 10, 26 | ), 27 | SizedBox(height: 12), 28 | ESlider( 29 | value: .3, 30 | enable: false, 31 | ), 32 | SizedBox(height: 12), 33 | ESlider( 34 | range: true, 35 | rangeValues: RangeValues(.1, .5), 36 | ), 37 | SizedBox(height: 12), 38 | ESlider( 39 | range: true, 40 | rangeValues: RangeValues(.1, .5), 41 | divisions: 10, 42 | ), 43 | SizedBox(height: 12), 44 | ESlider( 45 | value: .3, 46 | style: ESliderStyle( 47 | activeColor: Colors.blue, 48 | inactiveColor: Colors.black, 49 | thumbColor: Colors.green, 50 | ), 51 | ), 52 | ], 53 | ), 54 | ), 55 | ); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /lib/lib/src/widgets/switch.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'theme/switch_style.dart'; 4 | import 'theme/theme.dart'; 5 | import 'theme/theme_data.dart'; 6 | 7 | class ESwitch extends StatefulWidget { 8 | final bool value; 9 | final ValueChanged? onChanged; 10 | final ESwitchStyle? style; 11 | final bool enable; 12 | 13 | const ESwitch({ 14 | Key? key, 15 | this.value = false, 16 | this.onChanged, 17 | this.style, 18 | this.enable = true, 19 | }) : super(key: key); 20 | 21 | @override 22 | _ESwitchState createState() => _ESwitchState(); 23 | } 24 | 25 | class _ESwitchState extends State { 26 | late bool _value; 27 | 28 | @override 29 | initState() { 30 | _value = widget.value; 31 | super.initState(); 32 | } 33 | 34 | @override 35 | void didUpdateWidget(covariant ESwitch oldWidget) { 36 | if (oldWidget.value != widget.value) { 37 | _value = widget.value; 38 | } 39 | super.didUpdateWidget(oldWidget); 40 | } 41 | 42 | @override 43 | Widget build(BuildContext context) { 44 | EleThemeData eleTheme = EleTheme.of(context); 45 | var _style = eleTheme.switchStyle?.merge(widget.style) ?? widget.style; 46 | 47 | return CupertinoSwitch( 48 | value: _value, 49 | onChanged: widget.enable ? _onChanged : null, 50 | activeColor: _style?.activeColor ?? eleTheme.primaryColor, 51 | trackColor: _style?.trackColor ?? eleTheme.borderColorBase, 52 | thumbColor: _style?.thumbColor ?? eleTheme.backgroundColorWhite, 53 | ); 54 | } 55 | 56 | void _onChanged(bool value) { 57 | if (!mounted) { 58 | return; 59 | } 60 | setState(() { 61 | _value = !_value; 62 | }); 63 | widget.onChanged?.call(value); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /lib/.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 | .dart_tool/ 26 | .flutter-plugins 27 | .flutter-plugins-dependencies 28 | .packages 29 | .pub-cache/ 30 | .pub/ 31 | build/ 32 | 33 | # Android related 34 | **/android/**/gradle-wrapper.jar 35 | **/android/.gradle 36 | **/android/captures/ 37 | **/android/gradlew 38 | **/android/gradlew.bat 39 | **/android/local.properties 40 | **/android/**/GeneratedPluginRegistrant.java 41 | 42 | # iOS/XCode related 43 | **/ios/**/*.mode1v3 44 | **/ios/**/*.mode2v3 45 | **/ios/**/*.moved-aside 46 | **/ios/**/*.pbxuser 47 | **/ios/**/*.perspectivev3 48 | **/ios/**/*sync/ 49 | **/ios/**/.sconsign.dblite 50 | **/ios/**/.tags* 51 | **/ios/**/.vagrant/ 52 | **/ios/**/DerivedData/ 53 | **/ios/**/Icon? 54 | **/ios/**/Pods/ 55 | **/ios/**/.symlinks/ 56 | **/ios/**/profile 57 | **/ios/**/xcuserdata 58 | **/ios/.generated/ 59 | **/ios/Flutter/App.framework 60 | **/ios/Flutter/Flutter.framework 61 | **/ios/Flutter/Flutter.podspec 62 | **/ios/Flutter/Generated.xcconfig 63 | **/ios/Flutter/ephemeral 64 | **/ios/Flutter/app.flx 65 | **/ios/Flutter/app.zip 66 | **/ios/Flutter/flutter_assets/ 67 | **/ios/Flutter/flutter_export_environment.sh 68 | **/ios/ServiceDefinitions.json 69 | **/ios/Runner/GeneratedPluginRegistrant.* 70 | 71 | # Exceptions to above rules. 72 | !**/ios/**/default.mode1v3 73 | !**/ios/**/default.mode2v3 74 | !**/ios/**/default.pbxuser 75 | !**/ios/**/default.perspectivev3 76 | -------------------------------------------------------------------------------- /lib/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: element_ui 2 | description: Element UI, a set of Flutter-based component libraries for developers. 3 | version: 0.1.3 4 | homepage: http://element.laomengit.com/ 5 | repository: https://github.com/LaoMengFlutter/flutter_element 6 | issue_tracker: https://github.com/LaoMengFlutter/flutter_element/issues 7 | 8 | environment: 9 | sdk: ">=2.12.0 <3.0.0" 10 | flutter: ">=1.17.0" 11 | 12 | dependencies: 13 | flutter: 14 | sdk: flutter 15 | 16 | dev_dependencies: 17 | flutter_test: 18 | sdk: flutter 19 | flutter_lints: ^1.0.0 20 | 21 | # For information on the generic Dart part of this file, see the 22 | # following page: https://dart.dev/tools/pub/pubspec 23 | 24 | # The following section is specific to Flutter. 25 | flutter: 26 | 27 | # To add assets to your package, add an assets section, like this: 28 | # assets: 29 | # - images/a_dot_burr.jpeg 30 | # - images/a_dot_ham.jpeg 31 | # 32 | # For details regarding assets in packages, see 33 | # https://flutter.dev/assets-and-images/#from-packages 34 | # 35 | # An image asset can refer to one or more resolution-specific "variants", see 36 | # https://flutter.dev/assets-and-images/#resolution-aware. 37 | 38 | # To add custom fonts to your package, add a fonts section here, 39 | # in this "flutter" section. Each entry in this list should have a 40 | # "family" key with the font family name, and a "fonts" key with a 41 | # list giving the asset and other descriptors for the font. For 42 | # example: 43 | # fonts: 44 | # - family: Schyler 45 | # fonts: 46 | # - asset: fonts/Schyler-Regular.ttf 47 | # - asset: fonts/Schyler-Italic.ttf 48 | # style: italic 49 | # - family: Trajan Pro 50 | # fonts: 51 | # - asset: fonts/TrajanPro.ttf 52 | # - asset: fonts/TrajanPro_Bold.ttf 53 | # weight: 700 54 | # 55 | # For details regarding fonts in packages, see 56 | # https://flutter.dev/custom-fonts/#from-packages 57 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 13 | 14 | ## Element UI 15 | 16 | Element UI, a set of Flutter-based component libraries for developers. 17 | 18 | ## Resource 19 | 20 | [API Doc](http://element.laomengit.com/) 21 | 22 | ## Feature 23 | 24 | ![](https://github.com/LaoMengFlutter/flutter_element/blob/main/imgs/WX20220115-094720@2x.png) 25 | ![](https://github.com/LaoMengFlutter/flutter_element/blob/main/imgs/WX20220115-094741@2x.png) 26 | ![](https://github.com/LaoMengFlutter/flutter_element/blob/main/imgs/WX20220115-094753@2x.png) 27 | ![](https://github.com/LaoMengFlutter/flutter_element/blob/main/imgs/WX20220115-094803@2x.png) 28 | ![](https://github.com/LaoMengFlutter/flutter_element/blob/main/imgs/WX20220115-094815@2x.png) 29 | ![](https://github.com/LaoMengFlutter/flutter_element/blob/main/imgs/WX20220115-094826@2x.png) 30 | ![](https://github.com/LaoMengFlutter/flutter_element/blob/main/imgs/WX20220115-094851@2x.png) 31 | ![](https://github.com/LaoMengFlutter/flutter_element/blob/main/imgs/WX20220115-094905@2x.png) 32 | ![](https://github.com/LaoMengFlutter/flutter_element/blob/main/imgs/WX20220115-094913@2x.png) 33 | ![](https://github.com/LaoMengFlutter/flutter_element/blob/main/imgs/WX20220115-094923@2x.png) 34 | ![](https://github.com/LaoMengFlutter/flutter_element/blob/main/imgs/WX20220115-094932@2x.png) 35 | ![](https://github.com/LaoMengFlutter/flutter_element/blob/main/imgs/WX20220115-094942@2x.png) 36 | ![](https://github.com/LaoMengFlutter/flutter_element/blob/main/imgs/WX20220115-094951@2x.png) 37 | 38 | -------------------------------------------------------------------------------- /lib/README.md: -------------------------------------------------------------------------------- 1 | 13 | 14 | ## Element UI 15 | 16 | Element UI, a set of Flutter-based component libraries for developers. 17 | 18 | ## Resource 19 | 20 | [API Doc](http://element.laomengit.com/) 21 | 22 | ## Feature 23 | 24 | ![](https://github.com/LaoMengFlutter/flutter_element/blob/main/imgs/WX20220115-094720@2x.png) 25 | ![](https://github.com/LaoMengFlutter/flutter_element/blob/main/imgs/WX20220115-094741@2x.png) 26 | ![](https://github.com/LaoMengFlutter/flutter_element/blob/main/imgs/WX20220115-094753@2x.png) 27 | ![](https://github.com/LaoMengFlutter/flutter_element/blob/main/imgs/WX20220115-094803@2x.png) 28 | ![](https://github.com/LaoMengFlutter/flutter_element/blob/main/imgs/WX20220115-094815@2x.png) 29 | ![](https://github.com/LaoMengFlutter/flutter_element/blob/main/imgs/WX20220115-094826@2x.png) 30 | ![](https://github.com/LaoMengFlutter/flutter_element/blob/main/imgs/WX20220115-094851@2x.png) 31 | ![](https://github.com/LaoMengFlutter/flutter_element/blob/main/imgs/WX20220115-094905@2x.png) 32 | ![](https://github.com/LaoMengFlutter/flutter_element/blob/main/imgs/WX20220115-094913@2x.png) 33 | ![](https://github.com/LaoMengFlutter/flutter_element/blob/main/imgs/WX20220115-094923@2x.png) 34 | ![](https://github.com/LaoMengFlutter/flutter_element/blob/main/imgs/WX20220115-094932@2x.png) 35 | ![](https://github.com/LaoMengFlutter/flutter_element/blob/main/imgs/WX20220115-094942@2x.png) 36 | ![](https://github.com/LaoMengFlutter/flutter_element/blob/main/imgs/WX20220115-094951@2x.png) 37 | 38 | -------------------------------------------------------------------------------- /sample/lib/ui/page/dropdown_demo.dart: -------------------------------------------------------------------------------- 1 | import 'package:element_ui/widgets.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class DropdownDemo extends StatelessWidget { 5 | const DropdownDemo({Key? key}) : super(key: key); 6 | 7 | @override 8 | Widget build(BuildContext context) { 9 | var items = List.generate( 10 | 100, 11 | (index) => EDropdownMenuItem( 12 | child: Text('上海:$index'), 13 | value: '$index', 14 | )).toList(); 15 | return Scaffold( 16 | appBar: AppBar(), 17 | backgroundColor: Colors.white, 18 | body: Padding( 19 | padding: const EdgeInsets.all(30.0), 20 | child: Column( 21 | children: [ 22 | SizedBox(height: 12, width: double.infinity), 23 | EDropdown( 24 | items: items, 25 | ), 26 | SizedBox(height: 12), 27 | EDropdown( 28 | hint: Text('请选择'), 29 | items: items, 30 | ), 31 | SizedBox(height: 12), 32 | EDropdown( 33 | value: '1', 34 | items: items, 35 | ), 36 | SizedBox(height: 12), 37 | EDropdown( 38 | onChanged: (value) { 39 | print('$value'); 40 | }, 41 | items: items, 42 | ), 43 | SizedBox(height: 12), 44 | EDropdown( 45 | value: '1', 46 | isExpanded: false, 47 | items: items, 48 | ), 49 | SizedBox(height: 12), 50 | EDropdown( 51 | items: items, 52 | dropdownStyle: EDropdownStyle( 53 | dropdownBorderColor: Colors.green, 54 | dropdownFocusBorderColor: Colors.red, 55 | fontColor: Colors.yellow, 56 | selectFontColor: Colors.blue, 57 | ), 58 | ), 59 | 60 | SizedBox( 61 | height: 12, 62 | ), 63 | ], 64 | ), 65 | ), 66 | ); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /lib/lib/src/animations/collapse_transition.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class ECollapseTransition extends AnimatedWidget { 4 | ECollapseTransition({ 5 | Key? key, 6 | required this.collapse, 7 | required this.child, 8 | this.direction = CollapseDirection.down, 9 | }) : super(key: key, listenable: collapse); 10 | 11 | final Widget child; 12 | final Animation collapse; 13 | final CollapseDirection direction; 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | return ClipRect( 18 | child: Align( 19 | alignment: _getAlignment(direction), 20 | heightFactor: _getHeightFactor(direction, collapse.value), 21 | widthFactor: _getWidthFactor(direction, collapse.value), 22 | child: child, 23 | ), 24 | ); 25 | } 26 | 27 | Alignment _getAlignment(CollapseDirection direction) { 28 | switch (direction) { 29 | case CollapseDirection.down: 30 | return Alignment.topCenter; 31 | case CollapseDirection.top: 32 | return Alignment.bottomCenter; 33 | case CollapseDirection.left: 34 | return Alignment.centerRight; 35 | case CollapseDirection.right: 36 | return Alignment.centerLeft; 37 | } 38 | } 39 | 40 | double _getHeightFactor(CollapseDirection direction, double value) { 41 | switch (direction) { 42 | case CollapseDirection.down: 43 | return value; 44 | case CollapseDirection.top: 45 | return value; 46 | case CollapseDirection.left: 47 | return 1; 48 | case CollapseDirection.right: 49 | return 1; 50 | } 51 | } 52 | 53 | double _getWidthFactor(CollapseDirection direction, double value) { 54 | switch (direction) { 55 | case CollapseDirection.down: 56 | return 1; 57 | case CollapseDirection.top: 58 | return 1; 59 | case CollapseDirection.left: 60 | return 1 - value; 61 | case CollapseDirection.right: 62 | return value; 63 | } 64 | } 65 | } 66 | 67 | enum CollapseDirection { 68 | //向下 69 | down, 70 | //向上 71 | top, 72 | //向左 73 | left, 74 | //向右 75 | right, 76 | } 77 | -------------------------------------------------------------------------------- /sample/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 plugin: 'kotlin-android' 26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 27 | 28 | android { 29 | compileSdkVersion 30 30 | 31 | compileOptions { 32 | sourceCompatibility JavaVersion.VERSION_1_8 33 | targetCompatibility JavaVersion.VERSION_1_8 34 | } 35 | 36 | kotlinOptions { 37 | jvmTarget = '1.8' 38 | } 39 | 40 | sourceSets { 41 | main.java.srcDirs += 'src/main/kotlin' 42 | } 43 | 44 | defaultConfig { 45 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 46 | applicationId "com.flutter.sample" 47 | minSdkVersion 16 48 | targetSdkVersion 30 49 | versionCode flutterVersionCode.toInteger() 50 | versionName flutterVersionName 51 | } 52 | 53 | buildTypes { 54 | release { 55 | // TODO: Add your own signing config for the release build. 56 | // Signing with the debug keys for now, so `flutter run --release` works. 57 | signingConfig signingConfigs.debug 58 | } 59 | } 60 | } 61 | 62 | flutter { 63 | source '../..' 64 | } 65 | 66 | dependencies { 67 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 68 | } 69 | -------------------------------------------------------------------------------- /sample/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 13 | 17 | 21 | 26 | 30 | 31 | 32 | 33 | 34 | 35 | 37 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /sample/lib/ui/page/checkbox_demo.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:element_ui/widgets.dart'; 3 | 4 | class CheckboxDemo extends StatelessWidget { 5 | const CheckboxDemo({Key? key}) : super(key: key); 6 | 7 | @override 8 | Widget build(BuildContext context) { 9 | return Scaffold( 10 | appBar: AppBar(), 11 | backgroundColor: Colors.white, 12 | body: Column( 13 | children: [ 14 | SizedBox(height: 12, width: double.infinity), 15 | ECheckbox( 16 | value: false, 17 | label: '复选框', 18 | ), 19 | SizedBox(height: 12), 20 | ECheckbox( 21 | value: false, 22 | label: '复选框', 23 | border: true, 24 | ), 25 | SizedBox(height: 12), 26 | ECheckbox( 27 | value: true, 28 | label: '复选框', 29 | tristate: true, 30 | ), 31 | SizedBox(height: 12), 32 | ECheckbox( 33 | value: false, 34 | label: '复选框', 35 | style: ECheckboxStyle( 36 | backgroundColor: Colors.grey.withOpacity(.3), 37 | checkedBackgroundColor: Colors.blue, 38 | ), 39 | ), 40 | SizedBox(height: 12), 41 | ECheckbox( 42 | value: false, 43 | label: '复选框', 44 | border: true, 45 | style: ECheckboxStyle( 46 | borderColor: Colors.green, 47 | checkedBorderColor: Colors.red, 48 | borderRadius: BorderRadius.circular(10), 49 | ), 50 | ), 51 | SizedBox(height: 12), 52 | ECheckbox( 53 | value: false, 54 | label: '复选框', 55 | border: true, 56 | style: ECheckboxStyle( 57 | padding: EdgeInsets.symmetric(horizontal: 32, vertical: 24), 58 | space: 30), 59 | ), 60 | SizedBox(height: 12), 61 | ECheckbox( 62 | value: false, 63 | label: '禁用', 64 | enable: false, 65 | ), 66 | SizedBox(height: 12), 67 | ECheckbox( 68 | value: true, 69 | shape: CircleBorder(), 70 | label: '圆形复选框', 71 | ), 72 | ], 73 | ), 74 | ); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /sample/lib/ui/page/widget_list.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:sample/ui/page/input_number_demo.dart'; 3 | import 'package:sample/ui/page/text_field_demo.dart'; 4 | import 'button_demo.dart'; 5 | import 'checkbox_demo.dart'; 6 | import 'color_picker_demo.dart'; 7 | import 'dialog_demo.dart'; 8 | import 'dropdown_demo.dart'; 9 | import 'image_crop_demo.dart'; 10 | import 'image_demo.dart'; 11 | import 'image_preview_demo.dart'; 12 | import 'page_view_demo.dart'; 13 | import 'prgress_demo.dart'; 14 | import 'radio_demo.dart'; 15 | 16 | import 'border_demo.dart'; 17 | import 'rate_demo.dart'; 18 | import 'slider_demo.dart'; 19 | import 'switch_demo.dart'; 20 | 21 | class WidgetList extends StatelessWidget { 22 | WidgetList({Key? key}) : super(key: key); 23 | 24 | final List _data = [ 25 | {'title': 'Border', 'page': const BorderDemo()}, 26 | {'title': 'Button', 'page': const ButtonDemo()}, 27 | {'title': 'Image', 'page': const ImageDemo()}, 28 | {'title': 'Progress', 'page': const ProgressDemo()}, 29 | {'title': 'Radio', 'page': const RadioDemo()}, 30 | {'title': 'Checkbox', 'page': const CheckboxDemo()}, 31 | {'title': 'TextField', 'page': const TextFieldDemo()}, 32 | {'title': 'Dropdown', 'page': const DropdownDemo()}, 33 | {'title': 'InputNumber', 'page': InputNumberDemo()}, 34 | {'title': 'Switch', 'page': const SwitchDemo()}, 35 | {'title': 'Slider', 'page': const SliderDemo()}, 36 | {'title': 'Rate', 'page': const RateDemo()}, 37 | {'title': 'ColorPicker', 'page': const ColorPickerDemo()}, 38 | {'title': 'PageView', 'page': const PageViewDemo()}, 39 | {'title': 'Dialog', 'page': const DialogDemo()}, 40 | ]; 41 | 42 | @override 43 | Widget build(BuildContext context) { 44 | return Scaffold( 45 | appBar: AppBar(), 46 | body: ListView.separated( 47 | itemBuilder: (context, index) { 48 | return GestureDetector( 49 | onTap: () { 50 | Navigator.of(context) 51 | .push(MaterialPageRoute(builder: (context) { 52 | return _data[index]['page']; 53 | })); 54 | }, 55 | child: ListTile( 56 | title: Text('${_data[index]['title']}'), 57 | ), 58 | ); 59 | }, 60 | separatorBuilder: (context, index) { 61 | return const Divider(); 62 | }, 63 | itemCount: _data.length), 64 | ); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /sample/ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /sample/lib/ui/page/color_picker_demo.dart: -------------------------------------------------------------------------------- 1 | import 'package:element_ui/widgets.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class ColorPickerDemo extends StatefulWidget { 5 | const ColorPickerDemo({Key? key}) : super(key: key); 6 | 7 | @override 8 | _ColorPickerDemoState createState() => _ColorPickerDemoState(); 9 | } 10 | 11 | class _ColorPickerDemoState extends State { 12 | @override 13 | initState() { 14 | super.initState(); 15 | } 16 | 17 | @override 18 | Widget build(BuildContext context) { 19 | return Scaffold( 20 | appBar: AppBar(), 21 | backgroundColor: Colors.grey, 22 | body: Center( 23 | child: SingleChildScrollView( 24 | child: Column( 25 | children: [ 26 | SizedBox(height: 12), 27 | Container( 28 | height: 300, 29 | width: 300, 30 | color: Colors.white, 31 | child: EColorPicker( 32 | showAlpha: true, 33 | showClearButton: true, 34 | predefineColors: [ 35 | Color(0xFFff4500), 36 | Color(0xFFff8c00), 37 | Color(0xFFffd700), 38 | Color(0xFF90ee90), 39 | Color(0xFF00ced1), 40 | Color(0xFF1e90ff), 41 | Color(0xFFc71585), 42 | Color(0xFFc71585), 43 | Color(0x88c71585), 44 | Color(0x11c71585), 45 | Color(0xFF00ced1), 46 | Color(0xFF1e90ff), 47 | ], 48 | ), 49 | ), 50 | SizedBox(height: 12), 51 | EColorPickerButton( 52 | height: 45, 53 | width: 45, 54 | color: Colors.blue, 55 | ), 56 | SizedBox(height: 12), 57 | // Row( 58 | // children: [ 59 | // EColorPickerButton( 60 | // height: 45, 61 | // width: 45, 62 | // color: Colors.blue.withOpacity(.3), 63 | // ), 64 | // Expanded(child: Container()), 65 | // EColorPickerButton( 66 | // height: 45, 67 | // width: 45, 68 | // color: Colors.blue.withOpacity(.3), 69 | // ), 70 | // ], 71 | // ), 72 | // SizedBox(height: 600), 73 | // EColorPickerButton( 74 | // height: 45, 75 | // width: 45, 76 | // color: Colors.blue.withOpacity(.3), 77 | // ), 78 | ], 79 | ), 80 | ), 81 | ), 82 | ); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /sample/lib/ui/page/button_demo.dart: -------------------------------------------------------------------------------- 1 | import 'package:element_ui/widgets.dart'; 2 | 3 | import 'package:flutter/cupertino.dart'; 4 | import 'package:flutter/material.dart'; 5 | 6 | class ButtonDemo extends StatelessWidget { 7 | const ButtonDemo({Key? key}) : super(key: key); 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | return Scaffold( 12 | appBar: AppBar(), 13 | body: Padding( 14 | padding: const EdgeInsets.all(8.0), 15 | child: Column( 16 | // runSpacing: 10, 17 | // spacing: 10, 18 | children: [ 19 | SizedBox(width: double.infinity,), 20 | EButton( 21 | onPressed: () {}, 22 | child: Text('默认按钮'), 23 | ), 24 | EButton( 25 | onPressed: () {}, 26 | shape: BoxShape.rectangle, 27 | radius: BorderRadius.all(Radius.circular(0)), 28 | child: Text('矩形按钮'), 29 | ), 30 | EButton( 31 | onPressed: () {}, 32 | shape: BoxShape.rectangle, 33 | radius: BorderRadius.all(Radius.circular(5)), 34 | child: Text('圆角矩形按钮'), 35 | ), 36 | EButton( 37 | onPressed: () {}, 38 | shape: BoxShape.rectangle, 39 | radius: BorderRadius.circular(30), 40 | child: Text('按钮'), 41 | ), 42 | EButton( 43 | onPressed: () {}, 44 | shape: BoxShape.circle, 45 | child: Text('圆形'), 46 | ), 47 | EButton( 48 | onPressed: () {}, 49 | borderStyle: EButtonBorderStyle.stroke, 50 | child: Text('边框按钮'), 51 | ), 52 | EButton( 53 | onPressed: () {}, 54 | borderStyle: EButtonBorderStyle.none, 55 | child: Text('文字按钮'), 56 | ), 57 | 58 | EButton( 59 | onPressed: () { 60 | print('onPressed'); 61 | }, 62 | loading: true, 63 | child: Text('加载中'), 64 | ), 65 | EButton( 66 | onPressed: () {}, 67 | gradientColors: [Colors.red, Colors.blue], 68 | child: Text('渐变按钮'), 69 | ), 70 | EButton( 71 | onPressed: () {}, 72 | shape: BoxShape.circle, 73 | gradientColors: [Colors.red, Colors.blue], 74 | child: Text('渐变按钮'), 75 | ), 76 | EButton( 77 | onPressed: () {}, 78 | gradientColors: [Colors.red, Colors.blue], 79 | radius: BorderRadius.circular(20), 80 | child: Text('渐变按钮'), 81 | ), 82 | ], 83 | ), 84 | ), 85 | ); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /sample/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /sample/lib/ui/page/rate_demo.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:element_ui/widgets.dart'; 3 | 4 | class RateDemo extends StatefulWidget { 5 | const RateDemo({Key? key}) : super(key: key); 6 | 7 | @override 8 | State createState() => _RateDemoState(); 9 | } 10 | 11 | class _RateDemoState extends State { 12 | @override 13 | Widget build(BuildContext context) { 14 | return Scaffold( 15 | appBar: AppBar(), 16 | backgroundColor: Colors.white, 17 | body: Padding( 18 | padding: EdgeInsets.all(12), 19 | child: Column( 20 | children: [ 21 | SizedBox( 22 | height: 12, 23 | width: double.infinity, 24 | ), 25 | ERate(value: 3.7), 26 | SizedBox(height: 12), 27 | ERate( 28 | value: 5.5, 29 | count: 6, 30 | ), 31 | SizedBox(height: 12), 32 | ERate( 33 | value: 3.7, 34 | showLabel: true, 35 | ), 36 | SizedBox(height: 12), 37 | ERate( 38 | value: 3.7, 39 | itemSize: 60, 40 | ), 41 | SizedBox(height: 12), 42 | ERate( 43 | value: 5, 44 | iconType: RateIconType.sentiment, 45 | ), 46 | SizedBox(height: 12), 47 | ERate( 48 | value: 5, 49 | iconType: RateIconType.sameSentiment, 50 | ), 51 | SizedBox(height: 12), 52 | ERate( 53 | value: 5, 54 | showLabel: true, 55 | labelBuilder: (double value) { 56 | String s = ''; 57 | if (value <= 1) { 58 | s = '极差'; 59 | } else if (value <= 2) { 60 | s = '失望'; 61 | } else if (value <= 3) { 62 | s = '一般'; 63 | } else if (value <= 4) { 64 | s = '满意'; 65 | } else if (value <= 5) { 66 | s = '惊喜'; 67 | } 68 | return Text(s); 69 | }, 70 | ), 71 | SizedBox(height: 12), 72 | ERate( 73 | value: 3.5, 74 | space: 12, 75 | ), 76 | SizedBox(height: 12), 77 | ERate( 78 | value: 3.5, 79 | enable: false, 80 | ), 81 | SizedBox(height: 12), 82 | ERate( 83 | value: 3.5, 84 | onChanged: (value) { 85 | print('$value'); 86 | }, 87 | ), 88 | SizedBox(height: 12), 89 | ERate( 90 | value: 3.5, 91 | child: SizedBox( 92 | width: 40, 93 | height: 40, 94 | child: ColoredBox( 95 | color: Colors.white, 96 | ), 97 | ), 98 | ), 99 | SizedBox(height: 12), 100 | ERate( 101 | value: 3.5, 102 | itemBuilder: (context, index) { 103 | return Text('$index'); 104 | }, 105 | ), 106 | SizedBox(height: 12), 107 | ERate( 108 | value: 3.5, 109 | style: ERateStyle( 110 | activeColor: Colors.red, 111 | inactiveColor: Colors.black, 112 | ), 113 | ), 114 | ], 115 | ), 116 | ), 117 | ); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /lib/lib/src/widgets/slider.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'theme/slider_style.dart'; 3 | import 'theme/theme.dart'; 4 | import 'theme/theme_data.dart'; 5 | 6 | class ESlider extends StatefulWidget { 7 | final double value; 8 | final RangeValues? rangeValues; 9 | final ValueChanged? onChanged; 10 | final double min; 11 | final double max; 12 | final ESliderStyle? style; 13 | final bool enable; 14 | final String? label; 15 | final int? divisions; 16 | final bool range; 17 | final RangeLabels? rangeLabels; 18 | final ValueChanged? onRangeChanged; 19 | 20 | const ESlider({ 21 | Key? key, 22 | this.value = 0, 23 | this.rangeValues, 24 | this.onChanged, 25 | this.min = 0, 26 | this.max = 1, 27 | this.style, 28 | this.enable = true, 29 | this.label, 30 | this.divisions, 31 | this.range = false, 32 | this.rangeLabels, 33 | this.onRangeChanged, 34 | }) : super(key: key); 35 | 36 | @override 37 | State createState() => _ESliderState(); 38 | } 39 | 40 | class _ESliderState extends State { 41 | late double _value; 42 | late RangeValues _rangeValues; 43 | 44 | @override 45 | initState() { 46 | _value = widget.value; 47 | _rangeValues = widget.rangeValues ?? RangeValues(widget.min, widget.max); 48 | super.initState(); 49 | } 50 | 51 | @override 52 | void didUpdateWidget(covariant ESlider oldWidget) { 53 | if (oldWidget.value != widget.value) { 54 | _value = widget.value; 55 | } 56 | if (oldWidget.rangeValues != widget.rangeValues) { 57 | _rangeValues = widget.rangeValues ?? RangeValues(widget.min, widget.max); 58 | } 59 | super.didUpdateWidget(oldWidget); 60 | } 61 | 62 | _onChanged(double value) { 63 | if (!mounted) { 64 | return; 65 | } 66 | setState(() { 67 | _value = value; 68 | }); 69 | widget.onChanged?.call(_value); 70 | } 71 | 72 | _onRangeChanged(RangeValues values) { 73 | if (!mounted) { 74 | return; 75 | } 76 | setState(() { 77 | _rangeValues = values; 78 | }); 79 | widget.onRangeChanged?.call(_rangeValues); 80 | } 81 | 82 | @override 83 | Widget build(BuildContext context) { 84 | EleThemeData eleTheme = EleTheme.of(context); 85 | var _style = eleTheme.sliderStyle?.merge(widget.style) ?? widget.style; 86 | if (widget.range) { 87 | return SliderTheme( 88 | data: SliderTheme.of(context).copyWith( 89 | activeTrackColor: 90 | _style?.activeColor ?? EleTheme.of(context).primaryColor, 91 | thumbColor: 92 | _style?.thumbColor ?? EleTheme.of(context).backgroundColorWhite, 93 | ), 94 | child: RangeSlider( 95 | values: _rangeValues, 96 | onChanged: widget.enable ? _onRangeChanged : null, 97 | inactiveColor: 98 | _style?.inactiveColor ?? EleTheme.of(context).borderColorLight, 99 | labels: widget.rangeLabels ?? 100 | RangeLabels('${_rangeValues.start}', '${_rangeValues.end}'), 101 | divisions: widget.divisions, 102 | min: widget.min, 103 | max: widget.max, 104 | ), 105 | ); 106 | } 107 | 108 | return Slider( 109 | value: _value, 110 | onChanged: widget.enable ? _onChanged : null, 111 | activeColor: _style?.activeColor ?? EleTheme.of(context).primaryColor, 112 | inactiveColor: 113 | _style?.inactiveColor ?? EleTheme.of(context).borderColorLight, 114 | thumbColor: 115 | _style?.thumbColor ?? EleTheme.of(context).backgroundColorWhite, 116 | label: widget.label ?? '$_value', 117 | divisions: widget.divisions, 118 | min: widget.min, 119 | max: widget.max, 120 | ); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /lib/lib/src/widgets/checkbox.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'border.dart'; 3 | import 'theme/border_style.dart'; 4 | import 'theme/checkbox_style.dart'; 5 | import 'theme/theme.dart'; 6 | import 'theme/theme_data.dart'; 7 | 8 | class ECheckbox extends StatefulWidget { 9 | final bool? value; 10 | final bool tristate; 11 | final String? label; 12 | final bool border; 13 | final ECheckboxStyle? style; 14 | final ValueChanged? onChanged; 15 | final bool enable; 16 | final OutlinedBorder? shape; 17 | 18 | const ECheckbox({ 19 | Key? key, 20 | this.value, 21 | this.label, 22 | this.onChanged, 23 | this.tristate = false, 24 | this.border = false, 25 | this.style, 26 | this.enable = true, 27 | this.shape, 28 | }) : super(key: key); 29 | 30 | @override 31 | _ECheckboxState createState() => _ECheckboxState(); 32 | } 33 | 34 | class _ECheckboxState extends State { 35 | bool? _value; 36 | 37 | @override 38 | initState() { 39 | _value = widget.value; 40 | super.initState(); 41 | } 42 | 43 | @override 44 | void didUpdateWidget(covariant ECheckbox oldWidget) { 45 | if (oldWidget.value != widget.value) { 46 | _value = widget.value; 47 | } 48 | super.didUpdateWidget(oldWidget); 49 | } 50 | 51 | _onChanged(bool? value) { 52 | if (!mounted) { 53 | return; 54 | } 55 | setState(() { 56 | _value = value; 57 | }); 58 | widget.onChanged?.call(value); 59 | } 60 | 61 | @override 62 | Widget build(BuildContext context) { 63 | EleThemeData eleTheme = EleTheme.of(context); 64 | var style = eleTheme.checkboxStyle?.merge(widget.style) ?? widget.style; 65 | 66 | Widget child = Row( 67 | mainAxisSize: MainAxisSize.min, 68 | children: [ 69 | Checkbox( 70 | value: _value, 71 | tristate: widget.tristate, 72 | onChanged: widget.enable ? _onChanged : null, 73 | visualDensity: const VisualDensity( 74 | horizontal: VisualDensity.minimumDensity, 75 | vertical: VisualDensity.minimumDensity), 76 | shape: widget.shape, 77 | fillColor: MaterialStateProperty.resolveWith((states) { 78 | if (states.contains(MaterialState.selected)) { 79 | return EleTheme.of(context).primaryColor; 80 | } 81 | return EleTheme.of(context).borderColorBase; 82 | }), 83 | ), 84 | SizedBox(width: style?.space), 85 | if (widget.label != null) 86 | Text( 87 | '${widget.label}', 88 | style: TextStyle( 89 | color: (_value ?? false) 90 | ? style?.checkedFontColor ?? EleTheme.of(context).primaryColor 91 | : style?.fontColor ?? EleTheme.of(context).regularTextColor, 92 | ), 93 | ), 94 | ], 95 | ); 96 | if (widget.border) { 97 | return Container( 98 | color: (_value ?? false) 99 | ? style?.checkedBackgroundColor 100 | : style?.backgroundColor, 101 | child: EBorder( 102 | mainAxisSize: MainAxisSize.min, 103 | style: EBorderStyle( 104 | color: (_value ?? false) 105 | ? style?.checkedBorderColor ?? EleTheme.of(context).primaryColor 106 | : style?.borderColor, 107 | radius: style?.borderRadius, 108 | padding: style?.padding, 109 | ), 110 | child: child, 111 | ), 112 | ); 113 | } 114 | return Container( 115 | padding: widget.border ? style?.padding : EdgeInsets.zero, 116 | color: (_value ?? false) 117 | ? style?.checkedBackgroundColor 118 | : style?.backgroundColor, 119 | child: child, 120 | ); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /sample/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: sample 2 | description: A new Flutter application. 3 | 4 | # The following line prevents the package from being accidentally published to 5 | # pub.dev using `flutter pub publish`. This is preferred for private packages. 6 | publish_to: 'none' # Remove this line if you wish to publish to pub.dev 7 | 8 | # The following defines the version and build number for your application. 9 | # A version number is three numbers separated by dots, like 1.2.43 10 | # followed by an optional build number separated by a +. 11 | # Both the version and the builder number may be overridden in flutter 12 | # build by specifying --build-name and --build-number, respectively. 13 | # In Android, build-name is used as versionName while build-number used as versionCode. 14 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning 15 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. 16 | # Read more about iOS versioning at 17 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html 18 | version: 1.0.0+1 19 | 20 | environment: 21 | sdk: ">=2.12.0 <3.0.0" 22 | 23 | # Dependencies specify other packages that your package needs in order to work. 24 | # To automatically upgrade your package dependencies to the latest versions 25 | # consider running `flutter pub upgrade --major-versions`. Alternatively, 26 | # dependencies can be manually updated by changing the version numbers below to 27 | # the latest version available on pub.dev. To see which dependencies have newer 28 | # versions available, run `flutter pub outdated`. 29 | dependencies: 30 | flutter: 31 | sdk: flutter 32 | 33 | # The following adds the Cupertino Icons font to your application. 34 | # Use with the CupertinoIcons class for iOS style icons. 35 | cupertino_icons: ^1.0.2 36 | 37 | element_ui: 38 | path: ../lib 39 | # flutter_rating_bar: ^4.0.0 40 | # image_crop: ^0.4.0 41 | # extended_image: ^5.1.3 42 | # flutter_colorpicker: ^1.0.2 43 | 44 | dev_dependencies: 45 | flutter_test: 46 | sdk: flutter 47 | 48 | # The "flutter_lints" package below contains a set of recommended lints to 49 | # encourage good coding practices. The lint set provided by the package is 50 | # activated in the `analysis_options.yaml` file located at the root of your 51 | # package. See that file for information about deactivating specific lint 52 | # rules and activating additional ones. 53 | flutter_lints: ^1.0.0 54 | 55 | # For information on the generic Dart part of this file, see the 56 | # following page: https://dart.dev/tools/pub/pubspec 57 | 58 | # The following section is specific to Flutter. 59 | flutter: 60 | 61 | # The following line ensures that the Material Icons font is 62 | # included with your application, so that you can use the icons in 63 | # the material Icons class. 64 | uses-material-design: true 65 | 66 | # To add assets to your application, add an assets section, like this: 67 | assets: 68 | - assets/images/ 69 | 70 | # An image asset can refer to one or more resolution-specific "variants", see 71 | # https://flutter.dev/assets-and-images/#resolution-aware. 72 | 73 | # For details regarding adding assets from package dependencies, see 74 | # https://flutter.dev/assets-and-images/#from-packages 75 | 76 | # To add custom fonts to your application, add a fonts section here, 77 | # in this "flutter" section. Each entry in this list should have a 78 | # "family" key with the font family name, and a "fonts" key with a 79 | # list giving the asset and other descriptors for the font. For 80 | # example: 81 | # fonts: 82 | # - family: Schyler 83 | # fonts: 84 | # - asset: fonts/Schyler-Regular.ttf 85 | # - asset: fonts/Schyler-Italic.ttf 86 | # style: italic 87 | # - family: Trajan Pro 88 | # fonts: 89 | # - asset: fonts/TrajanPro.ttf 90 | # - asset: fonts/TrajanPro_Bold.ttf 91 | # weight: 700 92 | # 93 | # For details regarding fonts from package dependencies, 94 | # see https://flutter.dev/custom-fonts/#from-packages 95 | -------------------------------------------------------------------------------- /sample/web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | sample 30 | 31 | 32 | 33 | 36 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /sample/lib/ui/animations/collapse_transition_demo.dart: -------------------------------------------------------------------------------- 1 | import 'package:element_ui/animations.dart'; 2 | import 'package:element_ui/widgets.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | class CollapseTransitionDemo extends StatefulWidget { 6 | const CollapseTransitionDemo({Key? key}) : super(key: key); 7 | 8 | @override 9 | _CollapseTransitionDemoState createState() => _CollapseTransitionDemoState(); 10 | } 11 | 12 | class _CollapseTransitionDemoState extends State 13 | with TickerProviderStateMixin { 14 | late AnimationController _controller1, 15 | _controller2, 16 | _controller3, 17 | _controller4; 18 | 19 | bool _isCollapse1 = false; 20 | bool _isCollapse2 = false; 21 | bool _isCollapse3 = false; 22 | bool _isCollapse4 = false; 23 | 24 | @override 25 | void initState() { 26 | super.initState(); 27 | _controller1 = 28 | AnimationController(vsync: this, duration: Duration(seconds: 2)); 29 | _controller2 = 30 | AnimationController(vsync: this, duration: Duration(seconds: 2)); 31 | _controller3 = 32 | AnimationController(vsync: this, duration: Duration(seconds: 2)); 33 | _controller4 = 34 | AnimationController(vsync: this, duration: Duration(seconds: 2)); 35 | } 36 | 37 | @override 38 | void dispose() { 39 | _controller1.dispose(); 40 | _controller2.dispose(); 41 | _controller3.dispose(); 42 | _controller4.dispose(); 43 | super.dispose(); 44 | } 45 | 46 | @override 47 | Widget build(BuildContext context) { 48 | var child = Container( 49 | color: Colors.white, 50 | height: 200, 51 | width: 300, 52 | child: EBorder( 53 | style: EBorderStyle(color: EleTheme.of(context).borderColorBase), 54 | child: EColorPicker(), 55 | ), 56 | ); 57 | return Scaffold( 58 | appBar: AppBar(), 59 | body: SingleChildScrollView( 60 | child: Column( 61 | children: [ 62 | SizedBox( 63 | height: 20, 64 | width: double.infinity, 65 | ), 66 | ECollapseTransition( 67 | collapse: _controller1, 68 | child: child, 69 | ), 70 | EButton( 71 | child: Text('向下'), 72 | onPressed: () { 73 | _isCollapse1 = !_isCollapse1; 74 | if (_isCollapse1) { 75 | _controller1.forward(); 76 | } else { 77 | _controller1.reverse(); 78 | } 79 | }, 80 | ), 81 | ECollapseTransition( 82 | collapse: _controller4, 83 | direction: CollapseDirection.top, 84 | child: child, 85 | ), 86 | EButton( 87 | child: Text('向上'), 88 | onPressed: () { 89 | _isCollapse4 = !_isCollapse4; 90 | if (_isCollapse4) { 91 | _controller4.forward(); 92 | } else { 93 | _controller4.reverse(); 94 | } 95 | }, 96 | ), 97 | Row( 98 | children: [ 99 | ECollapseTransition( 100 | collapse: _controller2, 101 | direction: CollapseDirection.right, 102 | child: child, 103 | ), 104 | EButton( 105 | child: Text('向右'), 106 | onPressed: () { 107 | _isCollapse2 = !_isCollapse2; 108 | if (_isCollapse2) { 109 | _controller2.forward(); 110 | } else { 111 | _controller2.reverse(); 112 | } 113 | }, 114 | ), 115 | ], 116 | ), 117 | Row( 118 | children: [ 119 | EButton( 120 | child: Text('向左'), 121 | onPressed: () { 122 | _isCollapse3 = !_isCollapse3; 123 | if (_isCollapse3) { 124 | _controller3.forward(); 125 | } else { 126 | _controller3.reverse(); 127 | } 128 | }, 129 | ), 130 | ECollapseTransition( 131 | collapse: _controller3, 132 | direction: CollapseDirection.left, 133 | child: child, 134 | ), 135 | ], 136 | ), 137 | ], 138 | ), 139 | ), 140 | ); 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /sample/lib/ui/page/radio_demo.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:element_ui/widgets.dart'; 4 | 5 | class RadioDemo extends StatelessWidget { 6 | const RadioDemo({Key? key}) : super(key: key); 7 | 8 | @override 9 | Widget build(BuildContext context) { 10 | return Scaffold( 11 | appBar: AppBar(), 12 | backgroundColor: Colors.white, 13 | body: Padding( 14 | padding: EdgeInsets.all(12), 15 | child: Column( 16 | crossAxisAlignment: CrossAxisAlignment.start, 17 | children: [ 18 | ERadioGroup( 19 | radios: [ 20 | ERadioItem( 21 | value: '1', 22 | label: '备选项1', 23 | ), 24 | ERadioItem( 25 | value: '2', 26 | label: '备选项2', 27 | ), 28 | ], 29 | ), 30 | SizedBox( 31 | height: 12, 32 | ), 33 | ERadioGroup( 34 | radios: [ 35 | ERadioItem( 36 | value: '1', 37 | label: '禁用', 38 | enable: false, 39 | ), 40 | ERadioItem( 41 | value: '2', 42 | label: '备选项', 43 | ), 44 | ], 45 | ), 46 | SizedBox( 47 | height: 12, 48 | ), 49 | ERadioGroup( 50 | selectValue: '1', 51 | onChanged: (value) { 52 | print('ERadioGroup onChanged value:$value'); 53 | }, 54 | radios: [ 55 | ERadioItem( 56 | value: '1', 57 | label: '备选项1', 58 | ), 59 | ERadioItem( 60 | value: '2', 61 | label: '备选项2', 62 | ), 63 | ERadioItem( 64 | value: '3', 65 | label: '备选项3', 66 | ) 67 | ], 68 | ), 69 | SizedBox( 70 | height: 12, 71 | ), 72 | Container( 73 | child: ERadioButtonGroup( 74 | style: ERadioStyle( 75 | padding: 76 | EdgeInsets.symmetric(horizontal: 24, vertical: 12)), 77 | radios: [ 78 | ERadioItem( 79 | value: '1', 80 | label: '北京', 81 | ), 82 | ERadioItem( 83 | value: '2', 84 | label: '上海', 85 | ), 86 | ERadioItem( 87 | value: '3', 88 | label: '广州', 89 | ), 90 | ERadioItem( 91 | value: '4', 92 | label: '深圳', 93 | ), 94 | ], 95 | ), 96 | ), 97 | SizedBox( 98 | height: 12, 99 | ), 100 | ERadioGroup( 101 | style: ERadioStyle( 102 | fontColor: Colors.black, checkedFontColor: Colors.red), 103 | radios: [ 104 | ERadioItem( 105 | value: '1', 106 | label: '备选项1', 107 | ), 108 | ERadioItem( 109 | value: '2', 110 | label: '备选项2', 111 | ), 112 | ], 113 | ), 114 | SizedBox( 115 | height: 12, 116 | ), 117 | ERadioGroup( 118 | style: ERadioStyle( 119 | backgroundColor: Colors.grey.withOpacity(.5), 120 | checkedBackgroundColor: Colors.red, 121 | checkedFontColor: Colors.blue), 122 | radios: [ 123 | ERadioItem( 124 | value: '1', 125 | label: '备选项1', 126 | ), 127 | ERadioItem( 128 | value: '2', 129 | label: '备选项2', 130 | ), 131 | ], 132 | ), 133 | SizedBox( 134 | height: 12, 135 | ), 136 | ERadioGroup( 137 | style: ERadioStyle( 138 | borderColor: Colors.grey.withOpacity(.3), 139 | checkedBorderColor: Colors.red, 140 | borderRadius: BorderRadius.all(Radius.circular(3))), 141 | border: true, 142 | radios: [ 143 | ERadioItem( 144 | value: '1', 145 | label: '备选项1', 146 | ), 147 | ERadioItem( 148 | value: '2', 149 | label: '备选项2', 150 | ), 151 | ], 152 | ), 153 | SizedBox( 154 | height: 12, 155 | ), 156 | ], 157 | ), 158 | ), 159 | ); 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /sample/lib/ui/page/text_field_demo.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:element_ui/widgets.dart'; 3 | 4 | class TextFieldDemo extends StatefulWidget { 5 | const TextFieldDemo({Key? key}) : super(key: key); 6 | 7 | @override 8 | State createState() => _TextFieldDemoState(); 9 | } 10 | 11 | class _TextFieldDemoState extends State { 12 | @override 13 | Widget build(BuildContext context) { 14 | return Scaffold( 15 | appBar: AppBar(), 16 | backgroundColor: Colors.white, 17 | body: SingleChildScrollView( 18 | child: Padding( 19 | padding: const EdgeInsets.all(8.0), 20 | child: Column( 21 | children: [ 22 | SizedBox(height: 12, width: double.infinity), 23 | ETextField(), 24 | SizedBox(height: 12), 25 | ETextField( 26 | placeholder: 'please input', 27 | ), 28 | SizedBox(height: 12), 29 | ETextField( 30 | placeholder: 'please input', 31 | placeholderTextStyle: TextStyle(color: Colors.red), 32 | ), 33 | SizedBox(height: 12), 34 | ETextField( 35 | value: 'Flutter Element1', 36 | height: 30, 37 | textStyle: TextStyle(fontSize: 15), 38 | ), 39 | SizedBox(height: 12), 40 | ETextField( 41 | value: 'Flutter Element', 42 | textStyle: TextStyle(color: Colors.blue), 43 | ), 44 | SizedBox(height: 12), 45 | ETextField( 46 | height: 30, 47 | value: 'Flutter Element', 48 | ), 49 | SizedBox(height: 12), 50 | ETextField( 51 | height: 140, 52 | value: 'Flutter Element', 53 | ), 54 | SizedBox(height: 12), 55 | ETextField( 56 | height: 130, 57 | placeholder: 'please input', 58 | ), 59 | SizedBox(height: 12), 60 | ETextField( 61 | value: 'Flutter Element', 62 | placeholder: 'please input', 63 | style: ETextFieldStyle( 64 | fontColor: Colors.red, 65 | backgroundColor: Colors.yellow, 66 | placeholderColor: Colors.red.withOpacity(.5), 67 | borderColor: Colors.green, 68 | focusBorderColor: Colors.blue, 69 | borderRadius: BorderRadius.circular(100), 70 | ), 71 | ), 72 | SizedBox(height: 12), 73 | ETextField( 74 | placeholder: 'please input', 75 | clear: true, 76 | ), 77 | SizedBox(height: 12), 78 | ETextField( 79 | obscureText: true, 80 | ), 81 | SizedBox(height: 12), 82 | ETextField( 83 | obscureText: true, 84 | showPassword: true, 85 | ), 86 | SizedBox(height: 12), 87 | ETextField( 88 | placeholder: 'please input', 89 | obscureText: true, 90 | showPassword: true, 91 | clear: true, 92 | ), 93 | SizedBox(height: 12), 94 | ETextField( 95 | placeholder: 'please input', 96 | obscureText: true, 97 | showPassword: true, 98 | clear: true, 99 | suffix: Icon(Icons.date_range_sharp), 100 | ), 101 | SizedBox(height: 12), 102 | ETextField( 103 | placeholder: 'please input', 104 | prefix: Icon(Icons.search), 105 | ), 106 | SizedBox(height: 12), 107 | ETextField( 108 | height: 200, 109 | placeholder: 'please input', 110 | maxLines: 10, 111 | ), 112 | SizedBox(height: 12), 113 | ETextField( 114 | showWordLimit: true, 115 | maxLength: 10, 116 | ), 117 | SizedBox(height: 12), 118 | ETextField( 119 | height: 200, 120 | maxLines: 10, 121 | showWordLimit: true, 122 | maxLength: 100, 123 | ), 124 | SizedBox(height: 12), 125 | ETextField( 126 | height: 200, 127 | maxLines: 10, 128 | showWordLimit: true, 129 | maxLength: 100, 130 | limitBuilder: (context, length, maxLength) { 131 | return Row( 132 | children: [ 133 | Text( 134 | '$length', 135 | style: const TextStyle(color: Colors.red), 136 | ), 137 | Text('/$maxLength'), 138 | ], 139 | ); 140 | }, 141 | ), 142 | 143 | SizedBox(height: 120), 144 | ], 145 | ), 146 | ), 147 | ), 148 | ); 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /sample/lib/ui/page/border_demo.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:element_ui/widgets.dart'; 3 | 4 | class BorderDemo extends StatelessWidget { 5 | const BorderDemo({Key? key}) : super(key: key); 6 | 7 | @override 8 | Widget build(BuildContext context) { 9 | return Scaffold( 10 | appBar: AppBar(), 11 | backgroundColor: Colors.white, 12 | body: Padding( 13 | padding: const EdgeInsets.all(24.0), 14 | child: Column( 15 | crossAxisAlignment: CrossAxisAlignment.start, 16 | children: [ 17 | SizedBox(height: 12, width: double.infinity), 18 | SizedBox( 19 | height: 40, 20 | width: 100, 21 | child: const EBorder( 22 | style: EBorderStyle( 23 | strokeWidth: 10, 24 | ), 25 | child: Text('data'), 26 | ), 27 | ), 28 | SizedBox(height: 12), 29 | const EBorder( 30 | child: Text('data'), 31 | ), 32 | SizedBox(height: 12), 33 | const EBorder( 34 | mainAxisSize: MainAxisSize.min, 35 | child: Text('data min'), 36 | ), 37 | SizedBox(height: 12), 38 | const EBorder( 39 | mainAxisSize: MainAxisSize.min, 40 | style: EBorderStyle( 41 | padding: EdgeInsets.symmetric(vertical: 20, horizontal: 30)), 42 | child: Text('data'), 43 | ), 44 | SizedBox(height: 12), 45 | Container( 46 | height: 40, 47 | width: 100, 48 | child: EBorder( 49 | type: BorderType.dashed, 50 | shape: BorderShape.round, 51 | child: Text('data'), 52 | ), 53 | ), 54 | SizedBox( 55 | height: 12, 56 | ), 57 | SizedBox(height: 12), 58 | Container( 59 | height: 40, 60 | width: 100, 61 | child: const EBorder( 62 | type: BorderType.dashed, 63 | child: Text('data1'), 64 | ), 65 | ), 66 | SizedBox(height: 12), 67 | Container( 68 | height: 40, 69 | width: 100, 70 | child: const EBorder( 71 | type: BorderType.dashed, 72 | shape: BorderShape.circle, 73 | child: Text('data2'), 74 | ), 75 | ), 76 | SizedBox(height: 12), 77 | Container( 78 | height: 40, 79 | width: 100, 80 | child: const EBorder( 81 | type: BorderType.dashed, 82 | shape: BorderShape.rrect, 83 | style: EBorderStyle(), 84 | child: Text('data3'), 85 | ), 86 | ), 87 | SizedBox(height: 12), 88 | Container( 89 | height: 40, 90 | width: 100, 91 | child: const EBorder( 92 | type: BorderType.dashed, 93 | shape: BorderShape.rrect, 94 | style: EBorderStyle(color: Colors.red), 95 | child: Text('data'), 96 | ), 97 | ), 98 | SizedBox(height: 12), 99 | Container( 100 | height: 40, 101 | width: 100, 102 | child: const EBorder( 103 | type: BorderType.dashed, 104 | shape: BorderShape.rrect, 105 | style: EBorderStyle( 106 | color: Colors.red, 107 | strokeWidth: 3, 108 | ), 109 | child: Text('data'), 110 | ), 111 | ), 112 | SizedBox(height: 12), 113 | Container( 114 | height: 40, 115 | width: 200, 116 | child: const EBorder( 117 | type: BorderType.dashed, 118 | shape: BorderShape.rrect, 119 | style: EBorderStyle( 120 | color: Colors.red, 121 | strokeWidth: 3, 122 | dashGap: 5, 123 | dashWidth: 5, 124 | ), 125 | child: Text('data'), 126 | ), 127 | ), 128 | SizedBox(height: 12), 129 | Container( 130 | height: 40, 131 | width: 200, 132 | child: EBorder( 133 | type: BorderType.dashed, 134 | shape: BorderShape.rrect, 135 | style: EBorderStyle( 136 | color: Colors.red, 137 | strokeWidth: 1, 138 | dashGap: 5, 139 | dashWidth: 10, 140 | ), 141 | child: Text('data'), 142 | ), 143 | ), 144 | SizedBox(height: 12), 145 | Container( 146 | height: 40, 147 | width: 200, 148 | child: EBorder( 149 | type: BorderType.dashed, 150 | shape: BorderShape.rrect, 151 | style: EBorderStyle( 152 | color: Colors.red, radius: BorderRadius.circular(5)), 153 | child: Text('data'), 154 | ), 155 | ), 156 | ], 157 | ), 158 | ), 159 | ); 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /sample/lib/ui/page/input_number_demo.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:element_ui/widgets.dart'; 3 | import 'package:flutter/services.dart'; 4 | 5 | class InputNumberDemo extends StatefulWidget { 6 | InputNumberDemo({Key? key}) : super(key: key); 7 | 8 | @override 9 | State createState() => _InputNumberDemoState(); 10 | } 11 | 12 | class _InputNumberDemoState extends State { 13 | double? _value = 20.0; 14 | late TextEditingController _controller; 15 | 16 | @override 17 | initState() { 18 | _controller = TextEditingController() 19 | ..value = TextEditingValue(text: _value?.toStringAsFixed(2) ?? ''); 20 | super.initState(); 21 | } 22 | 23 | @override 24 | Widget build(BuildContext context) { 25 | return Scaffold( 26 | appBar: AppBar(), 27 | backgroundColor: Colors.white, 28 | body: Padding( 29 | padding: const EdgeInsets.all(8.0), 30 | child: SingleChildScrollView( 31 | child: Column( 32 | children: [ 33 | SizedBox(height: 12, width: double.infinity), 34 | Container( 35 | height: 45, 36 | width: 150, 37 | child: const EInputNumber( 38 | height: 45, 39 | ), 40 | ), 41 | SizedBox(height: 12), 42 | Container( 43 | height: 45, 44 | width: 150, 45 | child: const EInputNumber( 46 | height: 45, 47 | value: 2, 48 | ), 49 | ), 50 | SizedBox(height: 12), 51 | Container( 52 | height: 45, 53 | width: 150, 54 | child: const EInputNumber( 55 | height: 45, 56 | max: 10, 57 | min: 0, 58 | ), 59 | ), 60 | SizedBox(height: 12), 61 | SizedBox(height: 12), 62 | Container( 63 | height: 45, 64 | width: 150, 65 | child: const EInputNumber( 66 | height: 45, 67 | step: 5, 68 | ), 69 | ), 70 | SizedBox(height: 12), 71 | Container( 72 | height: 45, 73 | width: 150, 74 | child: const EInputNumber( 75 | height: 45, 76 | precision: 1, 77 | ), 78 | ), 79 | SizedBox(height: 12), 80 | Container( 81 | height: 45, 82 | width: 150, 83 | child: const EInputNumber( 84 | height: 45, 85 | type: InputNumberControlType.right, 86 | ), 87 | ), 88 | SizedBox(height: 12), 89 | Container( 90 | height: 100, 91 | width: 300, 92 | child: const EInputNumber( 93 | height: 100, 94 | ), 95 | ), 96 | SizedBox(height: 12), 97 | Container( 98 | height: 45, 99 | width: 150, 100 | child: const EInputNumber( 101 | height: 45, 102 | step: .1, 103 | precision: 2, 104 | ), 105 | ), 106 | SizedBox(height: 12), 107 | const EInputNumber( 108 | height: 45, 109 | step: .3, 110 | precision: 2, 111 | max: 0.8, 112 | ), 113 | SizedBox(height: 12), 114 | Container( 115 | height: 45, 116 | width: 150, 117 | child: const EInputNumber( 118 | height: 45, 119 | style: EInputNumberStyle( 120 | fontColor: Colors.red, 121 | backgroundColor: Colors.green, 122 | borderColor: Colors.blue, 123 | ), 124 | ), 125 | ), 126 | SizedBox(height: 12), 127 | Container( 128 | height: 45, 129 | width: 150, 130 | child: const EInputNumber( 131 | height: 45, 132 | style: EInputNumberStyle( 133 | focusBorderColor: Colors.red, 134 | iconColor: Colors.red, 135 | iconBackgroundColor: Colors.green, 136 | borderRadius: BorderRadius.all(Radius.circular(25))), 137 | ), 138 | ), 139 | SizedBox(height: 12), 140 | Container( 141 | height: 45, 142 | width: 150, 143 | child: EInputNumber( 144 | height: 45, 145 | onChanged: (value) { 146 | print('value:$value'); 147 | }, 148 | ), 149 | ), 150 | Container( 151 | height: 45, 152 | width: 150, 153 | child: EInputNumber( 154 | height: 45, 155 | value: 30.00, 156 | onChanged: (value) { 157 | print('value:$value'); 158 | }, 159 | ), 160 | ), 161 | SizedBox(height: 120), 162 | ], 163 | ), 164 | ), 165 | ), 166 | ); 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /sample/lib/ui/page/image_demo.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | 3 | import 'package:element_ui/widgets.dart'; 4 | 5 | import 'package:flutter/material.dart'; 6 | 7 | class ImageDemo extends StatelessWidget { 8 | const ImageDemo({Key? key}) : super(key: key); 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | return Scaffold( 13 | appBar: AppBar(), 14 | body: SingleChildScrollView( 15 | child: Padding( 16 | padding: const EdgeInsets.all(18.0), 17 | child: Column( 18 | children: [ 19 | Container( 20 | width: 200, 21 | child: EImage( 22 | image: AssetImage('assets/images/img_demo.jpeg'), 23 | ), 24 | ), 25 | SizedBox(height: 12), 26 | Container( 27 | width: 200, 28 | child: EImage( 29 | image: AssetImage('assets/images/img_demo.jpeg'), 30 | radius: BorderRadius.all(Radius.circular(12)), 31 | ), 32 | ), 33 | SizedBox(height: 12), 34 | Container( 35 | width: 200, 36 | child: EImage( 37 | image: AssetImage('assets/images/img_demo.jpeg'), 38 | radius: BorderRadius.vertical(top: Radius.circular(12)), 39 | ), 40 | ), 41 | SizedBox(height: 12), 42 | Container( 43 | width: 200, 44 | child: EImage( 45 | image: AssetImage('assets/images/img_demo.jpeg'), 46 | shape: ImageShape.circle, 47 | ), 48 | ), 49 | SizedBox(height: 12), 50 | Container( 51 | width: 200, 52 | child: EImage( 53 | image: AssetImage('assets/images/img_demo.jpeg'), 54 | borderWidth: 3, 55 | borderColor: Colors.red, 56 | ), 57 | ), 58 | SizedBox(height: 12), 59 | Container( 60 | width: 200, 61 | child: EImage( 62 | image: AssetImage('assets/images/img_demo.jpeg'), 63 | clipper: StarPath(), 64 | ), 65 | ), 66 | SizedBox(height: 12), 67 | Container( 68 | width: 200, 69 | child: EImage( 70 | image: AssetImage('assets/images/img_demo.jpeg'), 71 | borderWidth: 3, 72 | borderColor: Colors.red, 73 | clipper: StarPath(), 74 | ), 75 | ), 76 | SizedBox(height: 12), 77 | Container( 78 | width: 200, 79 | height: 150, 80 | child: EImage( 81 | image: NetworkImage( 82 | 'http://pic1.win4000.com/wallpaper/2018-06-02/5b1204212b018.jpg'), 83 | loadingBuilder: (context, child, progress) { 84 | if (progress == null) { 85 | return child; 86 | } 87 | return Center(child: CircularProgressIndicator()); 88 | }, 89 | ), 90 | ), 91 | Container( 92 | width: 150, 93 | height: 150, 94 | child: EImage( 95 | image: AssetImage('assets/images/img_demo1.jpeg'), 96 | errorWidget: Container( 97 | color: Colors.grey.withOpacity(.3), 98 | alignment: Alignment.center, 99 | child: Text( 100 | '加载失败', 101 | style: TextStyle(color: Colors.white), 102 | ), 103 | ), 104 | ), 105 | ), 106 | Container( 107 | width: 200, 108 | height: 150, 109 | child: EImage( 110 | radius: BorderRadius.all(Radius.circular(20)), 111 | image: NetworkImage( 112 | 'http://pic1.win4000.com/wallpaper/2018-06-02/5b1204212b018.jpg'), 113 | ), 114 | ), 115 | ], 116 | )), 117 | ), 118 | ); 119 | } 120 | } 121 | 122 | class StarPath extends CustomClipper { 123 | StarPath({this.scale = 2}); 124 | 125 | final double scale; 126 | 127 | double perDegree = 36; 128 | 129 | /// 角度转弧度公式 130 | double degree2Radian(double degree) { 131 | return (pi * degree / 180); 132 | } 133 | 134 | @override 135 | Path getClip(Size size) { 136 | var R = min(size.width / 2, size.height / 2); 137 | var r = R / scale; 138 | var x = size.width / 2; 139 | var y = size.height / 2; 140 | 141 | var path = Path(); 142 | path.moveTo(x, y - R); 143 | path.lineTo(x - sin(degree2Radian(perDegree)) * r, 144 | y - cos(degree2Radian(perDegree)) * r); 145 | path.lineTo(x - sin(degree2Radian(perDegree * 2)) * R, 146 | y - cos(degree2Radian(perDegree * 2)) * R); 147 | path.lineTo(x - sin(degree2Radian(perDegree * 3)) * r, 148 | y - cos(degree2Radian(perDegree * 3)) * r); 149 | path.lineTo(x - sin(degree2Radian(perDegree * 4)) * R, 150 | y - cos(degree2Radian(perDegree * 4)) * R); 151 | path.lineTo(x - sin(degree2Radian(perDegree * 5)) * r, 152 | y - cos(degree2Radian(perDegree * 5)) * r); 153 | path.lineTo(x - sin(degree2Radian(perDegree * 6)) * R, 154 | y - cos(degree2Radian(perDegree * 6)) * R); 155 | path.lineTo(x - sin(degree2Radian(perDegree * 7)) * r, 156 | y - cos(degree2Radian(perDegree * 7)) * r); 157 | path.lineTo(x - sin(degree2Radian(perDegree * 8)) * R, 158 | y - cos(degree2Radian(perDegree * 8)) * R); 159 | path.lineTo(x - sin(degree2Radian(perDegree * 9)) * r, 160 | y - cos(degree2Radian(perDegree * 9)) * r); 161 | path.lineTo(x - sin(degree2Radian(perDegree * 10)) * R, 162 | y - cos(degree2Radian(perDegree * 10)) * R); 163 | return path; 164 | } 165 | 166 | @override 167 | bool shouldReclip(StarPath oldClipper) { 168 | return oldClipper.scale != this.scale; 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /sample/lib/ui/page/page_view_demo.dart: -------------------------------------------------------------------------------- 1 | import 'package:element_ui/widgets.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class PageViewDemo extends StatelessWidget { 5 | const PageViewDemo({Key? key}) : super(key: key); 6 | 7 | @override 8 | Widget build(BuildContext context) { 9 | var itemBuilder = (context, index) { 10 | return Container( 11 | color: index % 2 == 0 ? Color(0xFF99a9bf) : Color(0xFFd3dce6), 12 | alignment: Alignment.center, 13 | child: Text( 14 | 'PageView:$index', 15 | style: TextStyle(color: Colors.white, fontSize: 26), 16 | ), 17 | ); 18 | }; 19 | 20 | return Scaffold( 21 | appBar: AppBar(), 22 | body: SingleChildScrollView( 23 | child: Column( 24 | children: [ 25 | SizedBox( 26 | height: 200, 27 | child: EPageView( 28 | itemBuilder: itemBuilder, 29 | itemCount: 5, 30 | ), 31 | ), 32 | SizedBox(height: 12), 33 | SizedBox( 34 | height: 200, 35 | child: EPageView( 36 | itemBuilder: itemBuilder, 37 | itemCount: 5, 38 | scrollDirection: Axis.vertical, 39 | ), 40 | ), 41 | SizedBox(height: 12), 42 | SizedBox( 43 | height: 200, 44 | child: EPageView( 45 | itemBuilder: itemBuilder, 46 | itemCount: 5, 47 | type: PageViewType.card, 48 | viewportFraction: .8, 49 | cardScale: .9, 50 | ), 51 | ), 52 | SizedBox(height: 12), 53 | SizedBox( 54 | height: 200, 55 | child: EPageView( 56 | itemBuilder: itemBuilder, 57 | itemCount: 5, 58 | autoPlay: true, 59 | loop: true, 60 | ), 61 | ), 62 | SizedBox(height: 12), 63 | SizedBox( 64 | height: 200, 65 | child: EPageView( 66 | itemBuilder: itemBuilder, 67 | itemCount: 5, 68 | autoPlay: true, 69 | loop: true, 70 | ), 71 | ), 72 | SizedBox(height: 12), 73 | SizedBox( 74 | height: 200, 75 | child: EPageView( 76 | itemBuilder: itemBuilder, 77 | itemCount: 5, 78 | autoPlay: true, 79 | loop: true, 80 | autoPlayDuration: Duration(seconds: 5), 81 | nextPageDuration: Duration(microseconds: 800), 82 | ), 83 | ), 84 | SizedBox(height: 12), 85 | SizedBox( 86 | height: 200, 87 | child: EPageView( 88 | itemBuilder: itemBuilder, 89 | itemCount: 5, 90 | showIndicator: true, 91 | ), 92 | ), 93 | SizedBox( 94 | height: 200, 95 | child: EPageView( 96 | itemBuilder: itemBuilder, 97 | itemCount: 5, 98 | showIndicator: true, 99 | style: EPageViewStyle( 100 | indicatorColor: Colors.black, 101 | indicatorActiveColor: Colors.red, 102 | ), 103 | ), 104 | ), 105 | SizedBox(height: 12), 106 | SizedBox( 107 | height: 200, 108 | child: EPageView( 109 | itemBuilder: itemBuilder, 110 | itemCount: 5, 111 | showIndicator: true, 112 | indicatorType: PageViewIndicatorType.line, 113 | ), 114 | ), 115 | SizedBox( 116 | height: 200, 117 | color: Colors.grey.withOpacity(.4), 118 | child: EPageView( 119 | itemBuilder: itemBuilder, 120 | itemCount: 5, 121 | showIndicator: true, 122 | indicatorPosition: PageViewIndicatorPosition.outside, 123 | ), 124 | ), 125 | SizedBox(height: 12), 126 | SizedBox( 127 | height: 200, 128 | color: Colors.grey.withOpacity(.4), 129 | child: EPageView( 130 | itemBuilder: itemBuilder, 131 | itemCount: 5, 132 | showIndicator: true, 133 | scrollDirection: Axis.vertical, 134 | ), 135 | ), 136 | SizedBox(height: 12), 137 | SizedBox( 138 | height: 200, 139 | child: EPageView( 140 | itemBuilder: itemBuilder, 141 | itemCount: 5, 142 | showIndicator: true, 143 | indicatorType: PageViewIndicatorType.line, 144 | scrollDirection: Axis.vertical, 145 | ), 146 | ), 147 | SizedBox(height: 12), 148 | Container( 149 | height: 200, 150 | color: Colors.grey.withOpacity(.4), 151 | child: EPageView( 152 | itemBuilder: itemBuilder, 153 | itemCount: 5, 154 | showIndicator: true, 155 | scrollDirection: Axis.vertical, 156 | ), 157 | ), 158 | SizedBox(height: 12), 159 | Container( 160 | height: 200, 161 | child: EPageView( 162 | itemBuilder: itemBuilder, 163 | itemCount: 5, 164 | showControl: true, 165 | ), 166 | ), 167 | SizedBox(height: 12), 168 | SizedBox( 169 | height: 200, 170 | child: EPageView( 171 | itemBuilder: itemBuilder, 172 | itemCount: 5, 173 | showControl: true, 174 | scrollDirection: Axis.vertical, 175 | loop: true, 176 | ), 177 | ), 178 | SizedBox(height: 12), 179 | SizedBox( 180 | height: 200, 181 | child: EPageView( 182 | itemBuilder: itemBuilder, 183 | itemCount: 5, 184 | showControl: true, 185 | nextWidget: Text( 186 | '下一页', 187 | style: TextStyle(color: Colors.white), 188 | ), 189 | previousWidget: Text( 190 | '上一页', 191 | style: TextStyle(color: Colors.white), 192 | ), 193 | showIndicator: true, 194 | ), 195 | ), 196 | SizedBox(height: 50), 197 | ], 198 | ), 199 | ), 200 | ); 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /lib/lib/src/widgets/image.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'theme/theme.dart'; 5 | import 'theme/theme_data.dart'; 6 | 7 | class EImage extends StatelessWidget { 8 | const EImage({ 9 | Key? key, 10 | required this.image, 11 | this.borderColor, 12 | this.borderWidth = 0, 13 | this.radius = BorderRadius.zero, 14 | this.shape = ImageShape.rrect, 15 | this.clipper, 16 | this.fit, 17 | this.width, 18 | this.height, 19 | this.placeholderWidget, 20 | this.loadingBuilder, 21 | this.errorWidget, 22 | this.errorBuilder, 23 | this.frameBuilder, 24 | this.semanticLabel, 25 | this.excludeFromSemantics = false, 26 | this.color, 27 | this.opacity, 28 | this.colorBlendMode, 29 | this.alignment = Alignment.center, 30 | this.repeat = ImageRepeat.noRepeat, 31 | this.centerSlice, 32 | this.matchTextDirection = false, 33 | this.gaplessPlayback = false, 34 | this.isAntiAlias = false, 35 | this.filterQuality = FilterQuality.low, 36 | }) : super(key: key); 37 | 38 | final ImageProvider image; 39 | 40 | /// border color 41 | final Color? borderColor; 42 | 43 | /// border width 44 | final double borderWidth; 45 | 46 | /// border radius 47 | final BorderRadius radius; 48 | 49 | /// shape 50 | final ImageShape shape; 51 | 52 | /// custom path 53 | final CustomClipper? clipper; 54 | 55 | /// fit 56 | final BoxFit? fit; 57 | 58 | /// width 59 | final double? width; 60 | 61 | /// width 62 | final double? height; 63 | 64 | /// loadingBuilder 65 | final ImageLoadingBuilder? loadingBuilder; 66 | 67 | /// loadingBuilder 68 | final Widget? placeholderWidget; 69 | 70 | /// errorBuilder 71 | final ImageErrorWidgetBuilder? errorBuilder; 72 | 73 | /// errorWidget 74 | final Widget? errorWidget; 75 | final String? semanticLabel; 76 | 77 | /// Whether to exclude this image from semantics. 78 | /// 79 | /// Useful for images which do not contribute meaningful information to an 80 | /// application. 81 | final bool excludeFromSemantics; 82 | 83 | /// Whether to paint the image with anti-aliasing. 84 | /// 85 | /// Anti-aliasing alleviates the sawtooth artifact when the image is rotated. 86 | final bool isAntiAlias; 87 | final AlignmentGeometry alignment; 88 | 89 | /// How to paint any portions of the layout bounds not covered by the image. 90 | final ImageRepeat repeat; 91 | final bool matchTextDirection; 92 | final Rect? centerSlice; 93 | final Color? color; 94 | final bool gaplessPlayback; 95 | final Animation? opacity; 96 | final FilterQuality filterQuality; 97 | final BlendMode? colorBlendMode; 98 | final ImageFrameBuilder? frameBuilder; 99 | 100 | @override 101 | Widget build(BuildContext context) { 102 | EleThemeData eleTheme = EleTheme.of(context); 103 | var _clipper = _getClipper(clipper, shape, radius); 104 | var _borderColor = 105 | borderColor ?? eleTheme.borderColorLight ?? Colors.transparent; 106 | 107 | var _loadingBuilder = loadingBuilder ?? 108 | (context, child, loadingProgress) { 109 | if (loadingProgress == null) { 110 | return child; 111 | } 112 | return placeholderWidget ?? 113 | eleTheme.imageStyle?.placeholderWidget ?? 114 | child; 115 | }; 116 | 117 | var _errorBuilder = errorBuilder ?? 118 | (BuildContext context, Object error, StackTrace? stackTrace) { 119 | return errorWidget ?? eleTheme.imageStyle?.errorWidget ?? Container(); 120 | }; 121 | var child = Image( 122 | key: key, 123 | image: image, 124 | fit: fit, 125 | width: width, 126 | height: height, 127 | loadingBuilder: _loadingBuilder, 128 | errorBuilder: _errorBuilder, 129 | frameBuilder: frameBuilder, 130 | semanticLabel: semanticLabel, 131 | excludeFromSemantics: excludeFromSemantics, 132 | color: color, 133 | opacity: opacity, 134 | colorBlendMode: colorBlendMode, 135 | alignment: alignment, 136 | repeat: repeat, 137 | centerSlice: centerSlice, 138 | matchTextDirection: matchTextDirection, 139 | gaplessPlayback: gaplessPlayback, 140 | isAntiAlias: isAntiAlias, 141 | filterQuality: filterQuality, 142 | ); 143 | 144 | return ClipPath( 145 | clipper: _clipper, 146 | child: CustomPaint( 147 | foregroundPainter: _BorderPainter( 148 | clipper: _clipper, strokeWidth: borderWidth, color: _borderColor), 149 | child: child, 150 | ), 151 | ); 152 | } 153 | 154 | CustomClipper _getClipper( 155 | CustomClipper? clipper, ImageShape shape, BorderRadius radius) { 156 | CustomClipper _clipper; 157 | if (clipper != null) { 158 | _clipper = clipper; 159 | } else { 160 | switch (shape) { 161 | case ImageShape.rrect: 162 | _clipper = _RRectClipper( 163 | topRight: radius.topRight, 164 | topLeft: radius.topLeft, 165 | bottomLeft: radius.bottomLeft, 166 | bottomRight: radius.bottomRight, 167 | ); 168 | break; 169 | case ImageShape.circle: 170 | _clipper = _CircleClipper(); 171 | break; 172 | } 173 | } 174 | return _clipper; 175 | } 176 | } 177 | 178 | class _RRectClipper extends CustomClipper { 179 | final Radius topLeft; 180 | 181 | final Radius topRight; 182 | 183 | final Radius bottomRight; 184 | 185 | final Radius bottomLeft; 186 | 187 | _RRectClipper({ 188 | required this.topLeft, 189 | required this.topRight, 190 | required this.bottomRight, 191 | required this.bottomLeft, 192 | }); 193 | 194 | @override 195 | Path getClip(Size size) { 196 | final path = Path() 197 | ..addRRect( 198 | RRect.fromLTRBAndCorners( 199 | 0, 200 | 0, 201 | size.width, 202 | size.height, 203 | topLeft: topLeft, 204 | topRight: topRight, 205 | bottomLeft: bottomLeft, 206 | bottomRight: bottomRight, 207 | ), 208 | ); 209 | return path; 210 | } 211 | 212 | @override 213 | bool shouldReclip(_RRectClipper oldClipper) { 214 | return topLeft != oldClipper.topRight || 215 | topRight != oldClipper.topRight || 216 | bottomLeft != oldClipper.bottomLeft || 217 | bottomRight != oldClipper.bottomRight; 218 | } 219 | } 220 | 221 | class _CircleClipper extends CustomClipper { 222 | _CircleClipper(); 223 | 224 | @override 225 | Path getClip(Size size) { 226 | double radius = min(size.width, size.height) / 2; 227 | final path = Path() 228 | ..addOval(Rect.fromCircle( 229 | center: Offset(size.width / 2, size.height / 2), radius: radius)); 230 | return path; 231 | } 232 | 233 | @override 234 | bool shouldReclip(_CircleClipper oldClipper) => false; 235 | } 236 | 237 | class _BorderPainter extends CustomPainter { 238 | final Color color; 239 | final CustomClipper clipper; 240 | final double strokeWidth; 241 | 242 | _BorderPainter( 243 | {required this.clipper, required this.color, required this.strokeWidth}); 244 | 245 | @override 246 | void paint(Canvas canvas, Size size) { 247 | if (strokeWidth <= 0) { 248 | return; 249 | } 250 | final paint = Paint() 251 | ..color = color 252 | ..strokeWidth = strokeWidth 253 | ..style = PaintingStyle.stroke; 254 | canvas.drawPath(clipper.getClip(size), paint); 255 | } 256 | 257 | @override 258 | bool shouldRepaint(_BorderPainter oldDelegate) => 259 | color != oldDelegate.color || 260 | clipper != oldDelegate.clipper || 261 | strokeWidth != oldDelegate.strokeWidth; 262 | } 263 | 264 | enum ImageShape { 265 | /// rrect 266 | rrect, 267 | 268 | /// circle 269 | circle, 270 | } 271 | -------------------------------------------------------------------------------- /lib/lib/src/widgets/image_preview.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'dart:ui' as ui; 3 | 4 | class EImagePreview extends StatefulWidget { 5 | final ImageProvider imageProvider; 6 | 7 | const EImagePreview({ 8 | Key? key, 9 | required this.imageProvider, 10 | }) : super(key: key); 11 | 12 | @override 13 | _EImagePreviewState createState() => _EImagePreviewState(); 14 | } 15 | 16 | class _EImagePreviewState extends State 17 | with SingleTickerProviderStateMixin { 18 | ImageStream? _imageStream; 19 | ImageInfo? _imageInfo; 20 | 21 | /// 图片显示区域的rect 22 | Rect _imageRect = Rect.zero; 23 | 24 | /// rect 25 | Rect _viewRect = Rect.zero; 26 | 27 | late AnimationController _controller; 28 | Animation? _imageRectLeftAnimation, 29 | _imageRectTopAnimation, 30 | _imageRectRightAnimation, 31 | _imageRectBottomAnimation; 32 | 33 | /// 最大偏移量 34 | final double _maxImageOffset = 100; 35 | 36 | @override 37 | initState() { 38 | _controller = AnimationController( 39 | vsync: this, duration: const Duration(milliseconds: 100)) 40 | ..addListener(() { 41 | resetImageRect(); 42 | }); 43 | super.initState(); 44 | } 45 | 46 | @override 47 | void didChangeDependencies() { 48 | super.didChangeDependencies(); 49 | _getImage(); 50 | } 51 | 52 | @override 53 | void didUpdateWidget(EImagePreview oldWidget) { 54 | super.didUpdateWidget(oldWidget); 55 | if (widget.imageProvider != oldWidget.imageProvider) { 56 | _getImage(); 57 | } 58 | } 59 | 60 | Size? get _size => context.size; 61 | 62 | void _getImage() { 63 | final ImageStream? oldImageStream = _imageStream; 64 | _imageStream = 65 | widget.imageProvider.resolve(createLocalImageConfiguration(context)); 66 | if (_imageStream!.key != oldImageStream?.key) { 67 | final ImageStreamListener listener = ImageStreamListener(_updateImage); 68 | oldImageStream?.removeListener(listener); 69 | _imageStream!.addListener(listener); 70 | } 71 | } 72 | 73 | _updateValue() { 74 | if (!mounted) { 75 | return; 76 | } 77 | setState(() {}); 78 | } 79 | 80 | void _updateImage(ImageInfo imageInfo, bool synchronousCall) { 81 | // 避免图片在 build 之前加载完成出现异常 82 | WidgetsBinding.instance?.addPostFrameCallback((timeStamp) { 83 | _imageInfo?.dispose(); 84 | _imageInfo = imageInfo; 85 | var imageRatio = 86 | imageInfo.image.width.toDouble() / imageInfo.image.height; 87 | var sizeRatio = _size!.width / _size!.height; 88 | if (imageRatio < sizeRatio) { 89 | //图片的宽高比小于组件的宽高比 90 | _imageRect = Rect.fromLTWH(0, 0, _imageInfo!.image.width.toDouble(), 91 | _imageInfo!.image.width.toDouble() / sizeRatio); 92 | _viewRect = Rect.fromLTWH(0, 0, _size!.width, _size!.height); 93 | } else { 94 | //图片的宽高比大于组件的宽高比 95 | _imageRect = Rect.fromLTWH(0, 0, _imageInfo!.image.width.toDouble(), 96 | _imageInfo!.image.height.toDouble()); 97 | var _viewHeight = _size!.width / imageRatio; 98 | _viewRect = 99 | Rect.fromLTWH(0, 0, (_size!.height - _viewHeight / 2), _viewHeight); 100 | } 101 | _updateValue(); 102 | }); 103 | } 104 | 105 | @override 106 | void dispose() { 107 | _controller.dispose(); 108 | _imageStream?.removeListener(ImageStreamListener(_updateImage)); 109 | _imageInfo?.dispose(); 110 | _imageInfo = null; 111 | super.dispose(); 112 | } 113 | 114 | @override 115 | Widget build(BuildContext context) { 116 | return _imageInfo?.image == null 117 | ? Container() 118 | : Listener( 119 | onPointerMove: _onPointerMove, 120 | onPointerUp: (event) { 121 | _onPointerUp(); 122 | }, 123 | onPointerCancel: (event) { 124 | _onPointerUp(); 125 | }, 126 | child: GestureDetector( 127 | onScaleStart: (ScaleStartDetails details) {}, 128 | onScaleUpdate: (ScaleUpdateDetails details) {}, 129 | onScaleEnd: (ScaleEndDetails details) {}, 130 | child: CustomPaint( 131 | size: const Size(double.infinity, double.infinity), 132 | painter: _ImageCustomPainter( 133 | image: _imageInfo!.image, 134 | imageRect: _imageRect, 135 | viewRect: _viewRect, 136 | ), 137 | ), 138 | ), 139 | ); 140 | } 141 | 142 | void _onPointerMove(PointerMoveEvent event) { 143 | if (_controller.isAnimating) { 144 | return; 145 | } 146 | var _dx = -event.delta.dx; 147 | var _dy = -event.delta.dy; 148 | if (_imageRect.left < 0 && event.delta.dx > 0) { 149 | _dx = _applyFriction(_maxImageOffset, -_imageRect.left, _dx); 150 | } 151 | if ((_imageRect.width - _imageRect.right) < 0 && event.delta.dx < 0) { 152 | _dx = _applyFriction( 153 | _maxImageOffset, _imageRect.right - _imageRect.width, _dx); 154 | } 155 | if (_imageRect.top < 0 && event.delta.dy > 0) { 156 | _dy = _applyFriction(_maxImageOffset, -_imageRect.top, _dy); 157 | } 158 | if ((_imageInfo!.image.height - _imageRect.bottom) < 0 && 159 | event.delta.dy < 0) { 160 | _dy = _applyFriction( 161 | _maxImageOffset, _imageRect.bottom - _imageInfo!.image.height, _dy); 162 | } 163 | _imageRect = _imageRect.translate(_dx, _dy); 164 | _updateValue(); 165 | } 166 | 167 | void _onPointerUp() { 168 | if (_controller.isAnimating) { 169 | return; 170 | } 171 | if (_imageRect.left < 0) { 172 | //水平向左移 173 | _imageRectLeftAnimation = 174 | Tween(begin: _imageRect.left, end: 0).animate(_controller); 175 | } 176 | if (_imageRect.right > _imageRect.width) { 177 | //水平向右移 178 | _imageRectLeftAnimation = 179 | Tween(begin: _imageRect.right, end: _imageRect.width) 180 | .animate(_controller); 181 | } 182 | if (_imageRect.top < 0) { 183 | //向下移 184 | _imageRectTopAnimation = 185 | Tween(begin: _imageRect.top, end: 0).animate(_controller); 186 | } 187 | if (_imageRect.bottom > _imageRect.height) { 188 | //向上移 189 | _imageRectTopAnimation = 190 | Tween(begin: _imageRect.bottom, end: _imageRect.height) 191 | .animate(_controller); 192 | } 193 | // _imageRectRightAnimation = 194 | // Tween(begin: _imageRect.right, end: 0).animate(_controller); 195 | // _imageRectBottomAnimation = 196 | // Tween(begin: _imageRect.bottom, end: 0).animate(_controller); 197 | _controller.reset(); 198 | _controller.forward(); 199 | } 200 | 201 | /// 阻尼效果 202 | /// 203 | /// 返回增加阻尼效果后的偏移 204 | double _applyFriction(double maxOffset, double alreadyOffset, double delta) { 205 | if (alreadyOffset + delta.abs() >= maxOffset) { 206 | //超过最大偏移量 207 | return maxOffset - alreadyOffset; 208 | } 209 | return (1 - (delta.abs() + alreadyOffset) / maxOffset) * delta; 210 | } 211 | 212 | /// 复位, 213 | void resetImageRect() { 214 | _imageRect = Rect.fromLTWH(_imageRectLeftAnimation!.value, 215 | _imageRectTopAnimation!.value, _imageRect.width, _imageRect.height); 216 | _updateValue(); 217 | } 218 | } 219 | 220 | class _ImageCustomPainter extends CustomPainter { 221 | final ui.Image image; 222 | final Rect imageRect; 223 | final Rect viewRect; 224 | late Paint _paint; 225 | 226 | _ImageCustomPainter({ 227 | required this.image, 228 | required this.imageRect, 229 | required this.viewRect, 230 | }) { 231 | _paint = Paint() 232 | ..isAntiAlias = false 233 | ..style = PaintingStyle.fill 234 | ..color = Colors.black; 235 | } 236 | 237 | @override 238 | void paint(Canvas canvas, Size size) { 239 | //background 240 | canvas.drawRect( 241 | Rect.fromLTWH( 242 | 0, 243 | 0, 244 | size.width, 245 | size.height, 246 | ), 247 | _paint); 248 | //image 249 | canvas.drawImageRect(image, imageRect, viewRect, _paint); 250 | } 251 | 252 | @override 253 | bool shouldRepaint(covariant _ImageCustomPainter oldDelegate) { 254 | return oldDelegate.image != image || 255 | oldDelegate.imageRect != imageRect || 256 | oldDelegate.viewRect != viewRect; 257 | } 258 | } 259 | -------------------------------------------------------------------------------- /lib/lib/src/widgets/radio.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/cupertino.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'border.dart'; 4 | import 'theme/border_style.dart'; 5 | import 'theme/radio_style.dart'; 6 | import 'theme/theme.dart'; 7 | import 'theme/theme_data.dart'; 8 | 9 | const double _kSpace = 3.0; 10 | 11 | class ERadioItem { 12 | final T value; 13 | final String? label; 14 | final ValueChanged? onChanged; 15 | final ERadioStyle? style; 16 | final bool enable; 17 | 18 | ERadioItem({ 19 | required this.value, 20 | this.label, 21 | this.onChanged, 22 | this.style, 23 | this.enable = true, 24 | }); 25 | } 26 | 27 | class ERadioGroup extends StatefulWidget { 28 | final T? selectValue; 29 | final List> radios; 30 | final ValueChanged? onChanged; 31 | final ERadioStyle? style; 32 | final bool border; 33 | final double spacing; 34 | final double runSpacing; 35 | final Axis direction; 36 | final WrapAlignment alignment; 37 | final WrapAlignment runAlignment; 38 | final WrapCrossAlignment crossAxisAlignment; 39 | final VerticalDirection verticalDirection; 40 | 41 | const ERadioGroup({ 42 | Key? key, 43 | required this.radios, 44 | this.selectValue, 45 | this.onChanged, 46 | this.style, 47 | this.border = false, 48 | this.spacing = 12.0, 49 | this.runSpacing = 6.0, 50 | this.direction = Axis.horizontal, 51 | this.alignment = WrapAlignment.start, 52 | this.runAlignment = WrapAlignment.start, 53 | this.crossAxisAlignment = WrapCrossAlignment.start, 54 | this.verticalDirection = VerticalDirection.down, 55 | }) : super(key: key); 56 | 57 | @override 58 | _ERadioGroupState createState() => _ERadioGroupState(); 59 | } 60 | 61 | class _ERadioGroupState extends State> { 62 | T? _selectValue; 63 | 64 | @override 65 | initState() { 66 | _selectValue = widget.selectValue; 67 | super.initState(); 68 | } 69 | 70 | @override 71 | void didUpdateWidget(covariant ERadioGroup oldWidget) { 72 | if (oldWidget.selectValue != widget.selectValue) { 73 | _selectValue = widget.selectValue; 74 | } 75 | super.didUpdateWidget(oldWidget); 76 | } 77 | 78 | void _onChanged(T? value) { 79 | if (!mounted) { 80 | return; 81 | } 82 | setState(() { 83 | _selectValue = value; 84 | }); 85 | widget.onChanged?.call(value); 86 | } 87 | 88 | @override 89 | Widget build(BuildContext context) { 90 | EleThemeData eleTheme = EleTheme.of(context); 91 | var style = eleTheme.radioStyle?.merge(widget.style) ?? widget.style; 92 | 93 | return Wrap( 94 | spacing: widget.spacing, 95 | runSpacing: widget.runSpacing, 96 | direction: widget.direction, 97 | alignment: widget.alignment, 98 | runAlignment: widget.runAlignment, 99 | crossAxisAlignment: widget.crossAxisAlignment, 100 | children: [ 101 | ...widget.radios.map((e) { 102 | return _ERadio( 103 | value: e.value, 104 | checked: _selectValue == e.value, 105 | label: e.label, 106 | onChanged: _onChanged, 107 | style: style?.merge(e.style) ?? e.style, 108 | border: widget.border, 109 | enable: e.enable, 110 | ); 111 | }).toList() 112 | ], 113 | ); 114 | } 115 | } 116 | 117 | class ERadioButtonGroup extends StatefulWidget { 118 | final T? selectValue; 119 | final List> radios; 120 | final ValueChanged? onChanged; 121 | final ERadioStyle? style; 122 | 123 | const ERadioButtonGroup({ 124 | Key? key, 125 | required this.radios, 126 | this.selectValue, 127 | this.onChanged, 128 | this.style, 129 | }) : super(key: key); 130 | 131 | @override 132 | State> createState() => _ERadioButtonGroupState(); 133 | } 134 | 135 | class _ERadioButtonGroupState 136 | extends State> { 137 | T? _selectValue; 138 | 139 | @override 140 | initState() { 141 | _selectValue = widget.selectValue; 142 | super.initState(); 143 | } 144 | 145 | @override 146 | void didUpdateWidget(covariant ERadioButtonGroup oldWidget) { 147 | if (oldWidget.selectValue != widget.selectValue) { 148 | _selectValue = widget.selectValue; 149 | } 150 | super.didUpdateWidget(oldWidget); 151 | } 152 | 153 | void _onChanged(T? value) { 154 | if (!mounted) { 155 | return; 156 | } 157 | setState(() { 158 | _selectValue = value; 159 | }); 160 | widget.onChanged?.call(value); 161 | } 162 | 163 | @override 164 | Widget build(BuildContext context) { 165 | EleThemeData eleTheme = EleTheme.of(context); 166 | ERadioStyle? _style = 167 | eleTheme.radioStyle?.merge(widget.style) ?? widget.style; 168 | 169 | Map _children = {}; 170 | for (var element in widget.radios) { 171 | _children.putIfAbsent( 172 | element.value, 173 | () => Padding( 174 | padding: _style?.padding ?? EdgeInsets.zero, 175 | child: Text( 176 | '${element.label}', 177 | style: TextStyle( 178 | color: element.value == _selectValue 179 | ? _style?.checkedFontColor ?? 180 | EleTheme.of(context).backgroundColorWhite 181 | : _style?.fontColor ?? 182 | EleTheme.of(context).regularTextColor), 183 | ), 184 | )); 185 | } 186 | 187 | return CupertinoSegmentedControl( 188 | groupValue: _selectValue, 189 | children: _children, 190 | selectedColor: 191 | _style?.checkedBackgroundColor ?? EleTheme.of(context).primaryColor, 192 | unselectedColor: 193 | _style?.backgroundColor ?? EleTheme.of(context).backgroundColorWhite, 194 | borderColor: _style?.borderColor ?? EleTheme.of(context).borderColorBase, 195 | onValueChanged: _onChanged, 196 | padding: EdgeInsets.zero, 197 | ); 198 | } 199 | } 200 | 201 | class _ERadio extends StatelessWidget { 202 | final T value; 203 | final String? label; 204 | final ValueChanged? onChanged; 205 | final bool checked; 206 | final bool border; 207 | final ERadioStyle? style; 208 | final bool enable; 209 | 210 | const _ERadio({ 211 | Key? key, 212 | required this.value, 213 | required this.checked, 214 | this.onChanged, 215 | this.label, 216 | this.border = false, 217 | this.style, 218 | this.enable = true, 219 | }) : super(key: key); 220 | 221 | @override 222 | Widget build(BuildContext context) { 223 | var child = Row( 224 | mainAxisSize: MainAxisSize.min, 225 | children: [ 226 | Radio( 227 | value: value, 228 | onChanged: enable ? onChanged : null, 229 | groupValue: checked ? value : null, 230 | visualDensity: const VisualDensity( 231 | horizontal: VisualDensity.minimumDensity, 232 | vertical: VisualDensity.minimumDensity), 233 | materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, 234 | fillColor: MaterialStateProperty.resolveWith((states) { 235 | if (states.contains(MaterialState.selected)) { 236 | return EleTheme.of(context).primaryColor; 237 | } 238 | return EleTheme.of(context).borderColorBase; 239 | }), 240 | ), 241 | SizedBox(width: style?.space ?? _kSpace), 242 | if (label != null) 243 | Text( 244 | '$label', 245 | style: TextStyle( 246 | color: checked 247 | ? style?.checkedFontColor ?? EleTheme.of(context).primaryColor 248 | : style?.fontColor ?? EleTheme.of(context).regularTextColor, 249 | ), 250 | ), 251 | ], 252 | ); 253 | if (border) { 254 | return Container( 255 | color: checked ? style?.checkedBackgroundColor : style?.backgroundColor, 256 | child: EBorder( 257 | mainAxisSize: MainAxisSize.min, 258 | style: EBorderStyle( 259 | color: checked 260 | ? style?.checkedBorderColor ?? EleTheme.of(context).primaryColor 261 | : style?.borderColor, 262 | radius: style?.borderRadius ?? 263 | BorderRadius.circular( 264 | EleTheme.of(context).borderRadiusBase ?? 4.0), 265 | padding: style?.padding, 266 | ), 267 | child: child, 268 | ), 269 | ); 270 | } 271 | return child; 272 | } 273 | } 274 | -------------------------------------------------------------------------------- /lib/lib/src/widgets/border.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | import 'dart:ui'; 3 | 4 | import 'theme/border_style.dart'; 5 | import 'theme/theme.dart'; 6 | import 'theme/theme_data.dart'; 7 | import 'package:flutter/material.dart'; 8 | 9 | const double _kStrokeWidth = 1; 10 | const double _kDashGap = 3; 11 | const double _kDashWidth = 3; 12 | const EdgeInsetsGeometry _kPadding = 13 | EdgeInsets.symmetric(vertical: 6.0, horizontal: 12); 14 | 15 | class EBorder extends StatelessWidget { 16 | /// 线的类型 17 | final BorderType type; 18 | 19 | /// 子组件, 20 | final Widget? child; 21 | 22 | /// border style 23 | final EBorderStyle? style; 24 | 25 | ///形状 26 | final BorderShape shape; 27 | 28 | /// child alignment 29 | /// 30 | /// default center 31 | final Alignment alignment; 32 | 33 | /// mainAxisSize 34 | final MainAxisSize mainAxisSize; 35 | 36 | /// 方向 37 | /// 38 | /// shape == line 时,表示方向 line 使用 Divide 39 | // BorderLineDirection direction = BorderLineDirection.horizontal; 40 | 41 | const EBorder({ 42 | Key? key, 43 | this.child, 44 | this.style, 45 | this.alignment = Alignment.center, 46 | this.type = BorderType.solid, 47 | this.shape = BorderShape.rrect, 48 | this.mainAxisSize = MainAxisSize.max, 49 | }) : super(key: key); 50 | 51 | @override 52 | Widget build(BuildContext context) { 53 | const BorderLineDirection direction = BorderLineDirection.horizontal; 54 | final EleThemeData eleTheme = EleTheme.of(context); 55 | var _style = eleTheme.borderStyle?.merge(style) ?? style; 56 | 57 | final Color color = 58 | _style?.color ?? eleTheme.borderColorBase ?? Colors.transparent; 59 | 60 | final double strokeWidth = _style?.strokeWidth ?? _kStrokeWidth; 61 | final BorderRadius radius = _style?.radius ?? 62 | BorderRadius.circular(eleTheme.borderRadiusBase ?? 0.0); 63 | 64 | final double dashWidth = _style?.dashWidth ?? _kDashWidth; 65 | final double dashGap = _style?.dashGap ?? _kDashGap; 66 | 67 | var painter = type == BorderType.solid 68 | ? _SolidPainter( 69 | color: color, 70 | strokeWidth: strokeWidth, 71 | radius: radius, 72 | shape: shape, 73 | direction: direction, 74 | ) 75 | : _DashedPainter( 76 | color: color, 77 | strokeWidth: strokeWidth, 78 | dashWidth: dashWidth, 79 | dashGap: dashGap, 80 | radius: radius, 81 | shape: shape, 82 | direction: direction, 83 | ); 84 | 85 | if (mainAxisSize == MainAxisSize.max) { 86 | return CustomPaint( 87 | painter: painter, 88 | child: Container( 89 | padding: _style?.padding ?? _kPadding, 90 | alignment: alignment, 91 | child: child, 92 | ), 93 | ); 94 | } 95 | return CustomPaint( 96 | painter: painter, 97 | child: Container( 98 | padding: _style?.padding ?? _kPadding, 99 | child: child, 100 | ), 101 | ); 102 | } 103 | } 104 | 105 | abstract class _BasePainter extends CustomPainter { 106 | /// 线的颜色 107 | final Color color; 108 | 109 | /// 线框宽 110 | final double strokeWidth; 111 | 112 | /// 圆角 113 | final BorderRadius radius; 114 | 115 | ///形状 116 | final BorderShape shape; 117 | 118 | /// 方向 119 | /// 120 | /// shape == line 时,表示方向 121 | final BorderLineDirection direction; 122 | 123 | /// 画笔 124 | late Paint _paint; 125 | 126 | _BasePainter({ 127 | required this.color, 128 | required this.strokeWidth, 129 | required this.radius, 130 | required this.shape, 131 | required this.direction, 132 | }) { 133 | _paint = Paint() 134 | ..color = color 135 | ..style = PaintingStyle.stroke 136 | ..strokeWidth = strokeWidth; 137 | } 138 | 139 | Path getPath(Size size) { 140 | double offset = strokeWidth / 2.0; 141 | Path _path = Path(); 142 | switch (shape) { 143 | // case BorderShape.line: 144 | // if (direction == BorderLineDirection.horizontal) { 145 | // _path.moveTo(0, size.height / 2); 146 | // _path.lineTo(size.width, size.height / 2); 147 | // } else { 148 | // _path.moveTo(size.width / 2, 0); 149 | // _path.lineTo(size.width / 2, size.height); 150 | // } 151 | // break; 152 | case BorderShape.rect: 153 | _path.addRect(Rect.fromLTWH( 154 | 0 + offset, 0 + offset, size.width - offset, size.height - offset)); 155 | break; 156 | case BorderShape.circle: 157 | _path.addOval(Rect.fromCircle( 158 | center: Offset(size.width / 2, size.height / 2), 159 | radius: (min(size.width, size.height) / 2) - offset, 160 | )); 161 | break; 162 | case BorderShape.rrect: 163 | _path.addRRect(RRect.fromRectAndCorners( 164 | Rect.fromLTWH(0 + offset, 0 + offset, size.width - offset, 165 | size.height - offset), 166 | topLeft: radius.topLeft, 167 | topRight: radius.topRight, 168 | bottomLeft: radius.bottomLeft, 169 | bottomRight: radius.bottomRight, 170 | )); 171 | break; 172 | case BorderShape.round: 173 | _path.addRRect(RRect.fromRectAndRadius( 174 | Rect.fromLTWH(0 + offset, 0 + offset, size.width - offset, 175 | size.height - offset), 176 | Radius.circular(max(size.width, size.height) / 2))); 177 | break; 178 | } 179 | return _path; 180 | } 181 | } 182 | 183 | class _DashedPainter extends _BasePainter { 184 | /// 线框虚线空白宽 185 | final double dashGap; 186 | 187 | /// 线框虚线宽 188 | final double dashWidth; 189 | 190 | _DashedPainter({ 191 | required Color color, 192 | required double strokeWidth, 193 | required this.dashGap, 194 | required this.dashWidth, 195 | required BorderRadius radius, 196 | required BorderShape shape, 197 | required BorderLineDirection direction, 198 | }) : super( 199 | color: color, 200 | strokeWidth: strokeWidth, 201 | radius: radius, 202 | shape: shape, 203 | direction: direction, 204 | ); 205 | 206 | @override 207 | void paint(Canvas canvas, Size size) { 208 | var path = getPath(size); 209 | var dashPath = 210 | _dashPath(source: path, dashWidth: dashWidth, dashGap: dashGap); 211 | canvas.drawPath(dashPath, _paint); 212 | } 213 | 214 | /// 参考 path_drawing 插件,稍作修改 215 | /// 216 | /// pub地址:https://pub.dev/packages/path_drawing 217 | Path _dashPath( 218 | {required Path source, 219 | required double dashWidth, 220 | required double dashGap}) { 221 | final Path dest = Path(); 222 | for (final PathMetric metric in source.computeMetrics()) { 223 | double distance = 0; 224 | bool draw = true; 225 | int index = 0; 226 | while (distance < metric.length) { 227 | final double len = index % 2 == 0 ? dashWidth : dashGap; 228 | if (draw) { 229 | dest.addPath( 230 | metric.extractPath(distance, distance + len), Offset.zero); 231 | } 232 | distance += len; 233 | draw = !draw; 234 | index++; 235 | } 236 | } 237 | return dest; 238 | } 239 | 240 | @override 241 | bool shouldRepaint(covariant _DashedPainter oldDelegate) { 242 | return oldDelegate.color != color || 243 | oldDelegate.dashWidth != dashWidth || 244 | oldDelegate.strokeWidth != strokeWidth || 245 | oldDelegate.dashGap != dashGap || 246 | oldDelegate.radius != radius || 247 | oldDelegate.shape != shape || 248 | oldDelegate.direction != direction; 249 | } 250 | } 251 | 252 | class _SolidPainter extends _BasePainter { 253 | _SolidPainter({ 254 | required Color color, 255 | required double strokeWidth, 256 | required BorderRadius radius, 257 | required BorderShape shape, 258 | required BorderLineDirection direction, 259 | }) : super( 260 | color: color, 261 | strokeWidth: strokeWidth, 262 | radius: radius, 263 | shape: shape, 264 | direction: direction, 265 | ); 266 | 267 | @override 268 | void paint(Canvas canvas, Size size) { 269 | var path = getPath(size); 270 | canvas.drawPath(path, _paint); 271 | } 272 | 273 | @override 274 | bool shouldRepaint(covariant _SolidPainter oldDelegate) { 275 | return oldDelegate.color != color || 276 | oldDelegate.strokeWidth != strokeWidth || 277 | oldDelegate.radius != radius || 278 | oldDelegate.shape != shape || 279 | oldDelegate.direction != direction; 280 | } 281 | } 282 | 283 | /// 线框类型 284 | enum BorderType { 285 | /// 实线 286 | solid, 287 | 288 | /// 虚线 289 | dashed 290 | } 291 | 292 | /// 线框形状 293 | enum BorderShape { 294 | /// 虚线 295 | circle, 296 | 297 | ///矩形 298 | rect, 299 | 300 | ///圆角矩形 301 | rrect, 302 | 303 | ///圆角 类似足球场形状 304 | round, 305 | } 306 | 307 | enum BorderLineDirection { 308 | /// 水平 309 | horizontal, 310 | 311 | /// 垂直 312 | vertical 313 | } 314 | -------------------------------------------------------------------------------- /lib/lib/src/widgets/button.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | 3 | import 'theme/theme.dart'; 4 | import 'package:flutter/material.dart'; 5 | 6 | class EButton extends StatelessWidget { 7 | final VoidCallback? onPressed; 8 | final Widget child; 9 | final ButtonStyle? style; 10 | final Color? loadingColor; 11 | 12 | /// radius 13 | final BorderRadius? radius; 14 | final bool loading; 15 | 16 | /// type 17 | final EButtonBorderStyle borderStyle; 18 | 19 | /// shape 20 | final BoxShape shape; 21 | final List? gradientColors; 22 | final AlignmentGeometry gradientBegin; 23 | final AlignmentGeometry gradientEnd; 24 | final List? gradientStops; 25 | 26 | const EButton({ 27 | Key? key, 28 | this.onPressed, 29 | required this.child, 30 | this.style, 31 | this.shape = BoxShape.rectangle, 32 | this.borderStyle = EButtonBorderStyle.fill, 33 | this.loading = false, 34 | this.loadingColor, 35 | this.radius, 36 | this.gradientColors, 37 | this.gradientBegin = Alignment.centerLeft, 38 | this.gradientEnd = Alignment.centerRight, 39 | this.gradientStops, 40 | }) : super(key: key); 41 | 42 | @override 43 | Widget build(BuildContext context) { 44 | var _child = child; 45 | if (loading) { 46 | _child = Row( 47 | mainAxisSize: MainAxisSize.min, 48 | children: [ 49 | _Indicator( 50 | radius: 8, 51 | color: loadingColor ?? 52 | EleTheme.of(context).backgroundColorWhite ?? 53 | Colors.white, 54 | ), 55 | const SizedBox(width: 8), 56 | _child 57 | ], 58 | ); 59 | } 60 | if (gradientColors != null) { 61 | _child = ClipRRect( 62 | borderRadius: radius ?? 63 | BorderRadius.circular(EleTheme.of(context).borderRadiusBase ?? 4.0), 64 | child: Container( 65 | decoration: BoxDecoration( 66 | gradient: LinearGradient( 67 | begin: gradientBegin, 68 | end: gradientEnd, 69 | colors: gradientColors!, 70 | stops: gradientStops, 71 | ), 72 | shape: shape, 73 | ), 74 | padding: style?.padding?.resolve({ 75 | MaterialState.hovered, 76 | MaterialState.pressed, 77 | MaterialState.focused, 78 | MaterialState.dragged, 79 | MaterialState.selected, 80 | MaterialState.scrolledUnder, 81 | MaterialState.disabled, 82 | MaterialState.error, 83 | }) ?? 84 | const EdgeInsets.symmetric(vertical: 4, horizontal: 12), 85 | child: _child, 86 | ), 87 | ); 88 | } 89 | 90 | return OutlinedButton( 91 | onPressed: loading ? null : onPressed, 92 | style: ButtonStyle( 93 | textStyle: style?.textStyle, 94 | foregroundColor: style?.foregroundColor ?? 95 | MaterialStateProperty.resolveWith((states) { 96 | if (borderStyle == EButtonBorderStyle.fill) { 97 | return EleTheme.of(context).backgroundColorWhite; 98 | } else { 99 | if (states.contains(MaterialState.focused) || 100 | states.contains(MaterialState.pressed) || 101 | states.contains(MaterialState.hovered)) { 102 | return EleTheme.of(context).primaryColor; 103 | } 104 | return EleTheme.of(context).regularTextColor; 105 | } 106 | }), 107 | backgroundColor: style?.backgroundColor ?? 108 | MaterialStateProperty.resolveWith((states) { 109 | if (borderStyle == EButtonBorderStyle.fill) { 110 | return EleTheme.of(context).primaryColor; 111 | } else if (borderStyle == EButtonBorderStyle.none) { 112 | return Colors.transparent; 113 | } 114 | return EleTheme.of(context).backgroundColorWhite; 115 | }), 116 | side: style?.side ?? 117 | MaterialStateProperty.resolveWith((states) { 118 | if (borderStyle == EButtonBorderStyle.stroke) { 119 | return BorderSide( 120 | color: EleTheme.of(context).borderColorBase ?? 121 | Colors.transparent); 122 | } 123 | if (borderStyle == EButtonBorderStyle.none) { 124 | return const BorderSide(color: Colors.transparent); 125 | } 126 | return null; 127 | }), 128 | overlayColor: style?.overlayColor ?? 129 | MaterialStateProperty.resolveWith((states) { 130 | if (borderStyle == EButtonBorderStyle.none) { 131 | return Colors.transparent; 132 | } 133 | }), 134 | padding: gradientColors == null 135 | ? style?.padding 136 | : MaterialStateProperty.all(EdgeInsets.zero), 137 | shadowColor: style?.shadowColor, 138 | elevation: style?.elevation, 139 | shape: style?.shape ?? 140 | getOutlinedBorder( 141 | shape, 142 | radius ?? 143 | BorderRadius.circular( 144 | EleTheme.of(context).borderRadiusBase ?? 4.0)), 145 | minimumSize: gradientColors == null 146 | ? style?.minimumSize 147 | : MaterialStateProperty.all(Size.zero), 148 | fixedSize: style?.fixedSize, 149 | maximumSize: style?.maximumSize, 150 | mouseCursor: style?.mouseCursor, 151 | visualDensity: style?.visualDensity, 152 | tapTargetSize: style?.tapTargetSize, 153 | animationDuration: style?.animationDuration, 154 | enableFeedback: style?.enableFeedback, 155 | alignment: style?.alignment, 156 | splashFactory: style?.splashFactory, 157 | ), 158 | child: _child, 159 | ); 160 | } 161 | 162 | MaterialStateProperty? getOutlinedBorder( 163 | BoxShape shape, BorderRadius borderRadius) { 164 | MaterialStateProperty? border; 165 | switch (shape) { 166 | case BoxShape.rectangle: 167 | border = MaterialStateProperty.all( 168 | RoundedRectangleBorder(borderRadius: borderRadius)); 169 | break; 170 | case BoxShape.circle: 171 | border = MaterialStateProperty.all(const CircleBorder()); 172 | break; 173 | } 174 | return border; 175 | } 176 | 177 | Color resolve(Color color, Color? overlayColor, Set states) { 178 | if (states.contains(MaterialState.hovered)) { 179 | return overlayColor ?? color.withOpacity(0.04); 180 | } 181 | if (states.contains(MaterialState.focused) || 182 | states.contains(MaterialState.pressed)) { 183 | return overlayColor ?? color.withOpacity(0.12); 184 | } 185 | return color; 186 | } 187 | } 188 | 189 | class _Indicator extends StatefulWidget { 190 | final double radius; 191 | final Color color; 192 | 193 | const _Indicator({Key? key, required this.radius, required this.color}) 194 | : super(key: key); 195 | 196 | @override 197 | __IndicatorState createState() => __IndicatorState(); 198 | } 199 | 200 | class __IndicatorState extends State<_Indicator> 201 | with SingleTickerProviderStateMixin { 202 | late AnimationController _controller; 203 | late Animation _animation; 204 | 205 | @override 206 | void initState() { 207 | super.initState(); 208 | _controller = AnimationController( 209 | vsync: this, duration: const Duration(milliseconds: 1200)) 210 | ..repeat(); 211 | _animation = Tween(begin: .0, end: 1.0).animate(_controller); 212 | } 213 | 214 | @override 215 | void dispose() { 216 | _controller.dispose(); 217 | super.dispose(); 218 | } 219 | 220 | @override 221 | Widget build(BuildContext context) { 222 | return RotationTransition( 223 | turns: _animation, 224 | child: SizedBox( 225 | height: widget.radius, 226 | width: widget.radius, 227 | child: CustomPaint( 228 | painter: 229 | _IndicatorPainter(radius: widget.radius, color: widget.color), 230 | ), 231 | ), 232 | ); 233 | } 234 | } 235 | 236 | class _IndicatorPainter extends CustomPainter { 237 | final double radius; 238 | final Color color; 239 | final int _count = 10; 240 | late Paint _paint; 241 | late RRect _rect; 242 | 243 | _IndicatorPainter({required this.radius, required this.color}) { 244 | _paint = Paint()..color = color; 245 | _rect = RRect.fromLTRBXY( 246 | -radius / 10.0, 247 | -radius / 3.0, 248 | radius / 10.0, 249 | -radius, 250 | radius / 10.0, 251 | radius / 10.0, 252 | ); 253 | } 254 | 255 | @override 256 | void paint(Canvas canvas, Size size) { 257 | canvas.save(); 258 | canvas.translate(size.width / 2.0, size.height / 2.0); 259 | for (int i = 0; i < _count; ++i) { 260 | canvas.drawRRect(_rect, _paint); 261 | canvas.rotate(2 * pi / _count); 262 | } 263 | canvas.restore(); 264 | } 265 | 266 | @override 267 | bool shouldRepaint(covariant _IndicatorPainter oldDelegate) { 268 | return oldDelegate.radius != radius || oldDelegate.color != color; 269 | } 270 | } 271 | 272 | enum EButtonBorderStyle { 273 | /// none 274 | none, 275 | 276 | /// stroke 277 | stroke, 278 | 279 | /// fill 280 | fill 281 | } 282 | -------------------------------------------------------------------------------- /sample/lib/ui/page/dialog_demo.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:element_ui/widgets.dart'; 3 | import 'package:flutter/cupertino.dart'; 4 | import 'package:flutter/material.dart'; 5 | 6 | class DialogDemo extends StatelessWidget { 7 | const DialogDemo({Key? key}) : super(key: key); 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | return Scaffold( 12 | appBar: AppBar(), 13 | body: Padding( 14 | padding: const EdgeInsets.all(8.0), 15 | child: Column( 16 | children: [ 17 | EButton( 18 | onPressed: () { 19 | // EDialog.showConfirmDialog(context); 20 | showDialog( 21 | context: context, 22 | builder: (context) { 23 | return EAlertDialog( 24 | title: Text('提示'), 25 | content: Text('确认删除吗'), 26 | actions: [ 27 | EButton( 28 | child: Text('取消'), 29 | onPressed: () { 30 | Navigator.of(context).pop(); 31 | }, 32 | ), 33 | EButton( 34 | child: Text('确认'), 35 | onPressed: () { 36 | Navigator.of(context).pop(); 37 | }, 38 | ), 39 | ], 40 | ); 41 | }); 42 | }, 43 | child: Text('基础用法'), 44 | ), 45 | EButton( 46 | onPressed: () { 47 | showDialog( 48 | context: context, 49 | builder: (context) { 50 | return EAlertDialog( 51 | title: Text('提示'), 52 | content: Text('确认删除吗'), 53 | actions: [ 54 | EButton( 55 | child: Text('取消'), 56 | onPressed: () { 57 | Navigator.of(context).pop(); 58 | }, 59 | ), 60 | EButton( 61 | child: Text('确认'), 62 | onPressed: () { 63 | Navigator.of(context).pop(); 64 | }, 65 | ), 66 | ], 67 | ); 68 | }); 69 | }, 70 | child: Text('基础用法'), 71 | ), 72 | EButton( 73 | onPressed: () { 74 | showDialog( 75 | context: context, 76 | builder: (context) { 77 | return EAlertDialog( 78 | title: Text('提示'), 79 | titleCenter: true, 80 | content: Text('确认删除吗'), 81 | contentCenter:true , 82 | actions: [ 83 | EButton( 84 | child: Text('取消'), 85 | onPressed: () { 86 | Navigator.of(context).pop(); 87 | }, 88 | ), 89 | EButton( 90 | child: Text('确认'), 91 | onPressed: () { 92 | Navigator.of(context).pop(); 93 | }, 94 | ), 95 | ], 96 | ); 97 | }); 98 | }, 99 | child: Text('标题、内容居中'), 100 | ), 101 | EButton( 102 | onPressed: () { 103 | showDialog( 104 | context: context, 105 | builder: (context) { 106 | return EAlertDialog( 107 | title: Text('提示'), 108 | content: Text(' 1、内容 \n 2、内容 \n 3、内容 \n 4、内容 \n 5、内容 \n 6、内容 \n 7、内容 \n 8、内容 \n 9、内容'), 109 | actions: [ 110 | EButton( 111 | child: Text('取消'), 112 | onPressed: () { 113 | Navigator.of(context).pop(); 114 | }, 115 | ), 116 | EButton( 117 | child: Text('确认'), 118 | onPressed: () { 119 | Navigator.of(context).pop(); 120 | }, 121 | ), 122 | ], 123 | scrollable: true, 124 | maxContentHeight: 150, 125 | ); 126 | }); 127 | }, 128 | child: Text('内容过多滚动'), 129 | ), 130 | EButton( 131 | onPressed: () { 132 | showDialog( 133 | context: context, 134 | builder: (context) { 135 | return EAlertDialog( 136 | title: Text('提示'), 137 | content: Text('1、内容'), 138 | actions: [ 139 | EButton( 140 | child: Text('取消'), 141 | onPressed: () { 142 | Navigator.of(context).pop(); 143 | }, 144 | ), 145 | EButton( 146 | child: Text('确认'), 147 | onPressed: () { 148 | Navigator.of(context).pop(); 149 | }, 150 | ), 151 | ], 152 | actionsAlignment: MainAxisAlignment.end, 153 | ); 154 | }); 155 | }, 156 | child: Text('按钮靠右'), 157 | ), 158 | EButton( 159 | onPressed: () { 160 | showDialog( 161 | context: context, 162 | builder: (context) { 163 | return EAlertDialog( 164 | title: Text('提示'), 165 | content: Text('1、内容'), 166 | actions: [ 167 | EButton( 168 | child: Container( 169 | child: Text('取消'), 170 | width: double.infinity, 171 | alignment: Alignment.center, 172 | ), 173 | borderStyle: EButtonBorderStyle.none, 174 | onPressed: () { 175 | Navigator.of(context).pop(); 176 | }, 177 | ), 178 | EButton( 179 | child: Container( 180 | child: Text('确认'), 181 | width: double.infinity, 182 | alignment: Alignment.center, 183 | ), 184 | radius: BorderRadius.zero, 185 | onPressed: () { 186 | Navigator.of(context).pop(); 187 | }, 188 | ), 189 | ], 190 | actionType: DialogActionType.cupertino, 191 | ); 192 | }); 193 | }, 194 | child: Text('按钮铺满'), 195 | ), 196 | EButton( 197 | onPressed: () { 198 | showDialog( 199 | context: context, 200 | builder: (context) { 201 | return EAlertDialog( 202 | title: Text('提示'), 203 | content: Text('1、内容'), 204 | actions: [ 205 | EButton( 206 | child: Container( 207 | child: Text('立即升级'), 208 | width: double.infinity, 209 | alignment: Alignment.center, 210 | ), 211 | borderStyle: EButtonBorderStyle.fill, 212 | radius: BorderRadius.circular(30), 213 | onPressed: () { 214 | Navigator.of(context).pop(); 215 | }, 216 | ), 217 | EButton( 218 | child: Container( 219 | child: Text('稍后再说'), 220 | width: double.infinity, 221 | alignment: Alignment.center, 222 | ), 223 | borderStyle: EButtonBorderStyle.stroke, 224 | radius: BorderRadius.circular(30), 225 | onPressed: () { 226 | Navigator.of(context).pop(); 227 | }, 228 | ), 229 | EButton( 230 | child: Container( 231 | child: Text('明天提醒'), 232 | width: double.infinity, 233 | alignment: Alignment.center, 234 | ), 235 | borderStyle: EButtonBorderStyle.stroke, 236 | radius: BorderRadius.circular(30), 237 | onPressed: () { 238 | Navigator.of(context).pop(); 239 | }, 240 | ), 241 | ], 242 | ); 243 | }); 244 | }, 245 | child: Text('多个按钮上下排列'), 246 | ), 247 | ], 248 | ), 249 | ), 250 | ); 251 | } 252 | } 253 | --------------------------------------------------------------------------------