Commit ad2c64b9 authored by 汪林玲's avatar 汪林玲

更新

parent 23c856ca
{
"dart.flutterSdkPath": "/Users/qiaomeng/flutter_2.5.1"
}
\ No newline at end of file
.DS_Store
.dart_tool/
.packages
.pub/
build/
.flutter-plugins
*.iml
pubspec.lock
.idea
\ No newline at end of file
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.
version:
revision: 7ffcd3d22d7bc1222d53d6d3bb83f59891aac2c2
channel: dev
# demo
A new Flutter project.
## Getting Started
For help getting started with Flutter, view our online
[documentation](https://flutter.io/).
*.iml
*.class
.gradle
/local.properties
/.idea/workspace.xml
/.idea/libraries
.DS_Store
/build
/captures
GeneratedPluginRegistrant.java
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
localPropertiesFile.withReader('UTF-8') { reader ->
localProperties.load(reader)
}
}
def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) {
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}
apply plugin: 'com.android.application'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
android {
compileSdkVersion 28
lintOptions {
disable 'InvalidPackage'
}
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.jpeng.demo"
minSdkVersion 16
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig signingConfigs.debug
}
}
}
flutter {
source '../..'
}
dependencies {
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.1'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
}
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.jpeng.example">
<!-- Flutter needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.jpeng.demo">
<!-- The INTERNET permission is required for development. Specifically,
flutter needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
<!-- io.flutter.app.FlutterApplication is an android.app.Application that
calls FlutterMain.startInitialization(this); in its onCreate method.
In most cases you can leave this as-is, but you if you want to provide
additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. -->
<application
android:name="io.flutter.app.FlutterApplication"
android:label="PullRefreshDemo"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- This keeps the window background of the activity showing
until Flutter renders its first frame. It can be removed if
there is no splash screen (such as the default splash screen
defined in @style/LaunchTheme). -->
<meta-data
android:name="io.flutter.app.android.SplashScreenUntilFirstFrame"
android:value="true" />
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
package com.jpeng.demo;
import android.os.Bundle;
import io.flutter.app.FlutterActivity;
import io.flutter.plugins.GeneratedPluginRegistrant;
public class MainActivity extends FlutterActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GeneratedPluginRegistrant.registerWith(this);
}
}
package com.jpeng.example
import io.flutter.embedding.android.FlutterActivity
class MainActivity: FlutterActivity() {
}
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@android:color/white" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
</layer-list>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
Flutter draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
Flutter draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
</resources>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.jpeng.example">
<!-- Flutter needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.1'
}
}
allprojects {
repositories {
google()
jcenter()
}
}
rootProject.buildDir = '../build'
subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
project.evaluationDependsOn(':app')
}
task clean(type: Delete) {
delete rootProject.buildDir
}
org.gradle.jvmargs=-Xmx1536M
android.enableR8=true
#Fri Jun 23 08:50:38 CEST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
#!/usr/bin/env bash
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windowz variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
include ':app'
def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
def plugins = new Properties()
def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
if (pluginsFile.exists()) {
pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
}
plugins.each { name, path ->
def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
include ":$name"
project(":$name").projectDir = pluginDirectory
}
.idea/
.vagrant/
.sconsign.dblite
.svn/
.DS_Store
*.swp
profile
DerivedData/
build/
GeneratedPluginRegistrant.h
GeneratedPluginRegistrant.m
.generated/
*.pbxuser
*.mode1v3
*.mode2v3
*.perspectivev3
!default.pbxuser
!default.mode1v3
!default.mode2v3
!default.perspectivev3
xcuserdata
*.moved-aside
*.pyc
*sync/
Icon?
.tags*
/Flutter/app.flx
/Flutter/app.zip
/Flutter/flutter_assets/
/Flutter/App.framework
/Flutter/Flutter.framework
/Flutter/Generated.xcconfig
/ServiceDefinitions.json
Pods/
cede5a498fe37fd7523b504da3df1a2b
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>App</string>
<key>CFBundleIdentifier</key>
<string>io.flutter.flutter.app</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>App</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>arm64</string>
</array>
<key>MinimumOSVersion</key>
<string>8.0</string>
</dict>
</plist>
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig"
#
# NOTE: This podspec is NOT to be published. It is only used as a local source!
#
Pod::Spec.new do |s|
s.name = 'Flutter'
s.version = '1.0.0'
s.summary = 'High-performance, high-fidelity mobile apps.'
s.description = <<-DESC
Flutter provides an easy and productive way to build and deploy high-performance mobile apps for Android and iOS.
DESC
s.homepage = 'https://flutter.io'
s.license = { :type => 'MIT' }
s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' }
s.source = { :git => 'https://github.com/flutter/engine', :tag => s.version.to_s }
s.ios.deployment_target = '8.0'
s.vendored_frameworks = 'Flutter.framework'
end
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.xcconfig"
#!/bin/sh
# This is a generated file; do not edit or check into version control.
export "FLUTTER_ROOT=C:\env\flutter1.22.4"
export "FLUTTER_APPLICATION_PATH=C:\_project_app\pull_to_refresh-1.6.3\example"
export "FLUTTER_TARGET=lib\main.dart"
export "FLUTTER_BUILD_DIR=build"
export "SYMROOT=${SOURCE_ROOT}/../build\ios"
export "OTHER_LDFLAGS=$(inherited) -framework Flutter"
export "FLUTTER_FRAMEWORK_DIR=C:\env\flutter1.22.4\bin\cache\artifacts\engine\ios"
export "FLUTTER_BUILD_NAME=1.0.0"
export "FLUTTER_BUILD_NUMBER=1"
export "DART_OBFUSCATION=false"
export "TRACK_WIDGET_CREATION=false"
export "TREE_SHAKE_ICONS=false"
export "PACKAGE_CONFIG=.packages"
# Uncomment this line to define a global platform for your project
# platform :ios, '9.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
def parse_KV_file(file, separator='=')
file_abs_path = File.expand_path(file)
if !File.exists? file_abs_path
return [];
end
pods_ary = []
skip_line_start_symbols = ["#", "/"]
File.foreach(file_abs_path) { |line|
next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ }
plugin = line.split(pattern=separator)
if plugin.length == 2
podname = plugin[0].strip()
path = plugin[1].strip()
podpath = File.expand_path("#{path}", file_abs_path)
pods_ary.push({:name => podname, :path => podpath});
else
puts "Invalid plugin specification: #{line}"
end
}
return pods_ary
end
target 'Runner' do
# Prepare symlinks folder. We use symlinks to avoid having Podfile.lock
# referring to absolute paths on developers' machines.
system('rm -rf Pods/.symlinks')
system('mkdir -p Pods/.symlinks/plugins')
# Flutter Pods
generated_xcode_build_settings = parse_KV_file('./Flutter/Generated.xcconfig')
if generated_xcode_build_settings.empty?
puts "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter packages get is executed first."
end
generated_xcode_build_settings.map { |p|
if p[:name] == 'FLUTTER_FRAMEWORK_DIR'
symlink = File.join('Pods', '.symlinks', 'flutter')
File.symlink(File.dirname(p[:path]), symlink)
pod 'Flutter', :path => File.join(symlink, File.basename(p[:path]))
end
}
# Plugin Pods
plugin_pods = parse_KV_file('../.flutter-plugins')
plugin_pods.map { |p|
symlink = File.join('Pods', '.symlinks', 'plugins', p[:name])
File.symlink(p[:path], symlink)
pod p[:name], :path => File.join(symlink, 'ios')
}
end
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['ENABLE_BITCODE'] = 'NO'
end
end
end
PODS:
- Flutter (1.0.0)
DEPENDENCIES:
- Flutter (from `Pods/.symlinks/flutter/ios`)
EXTERNAL SOURCES:
Flutter:
:path: Pods/.symlinks/flutter/ios
SPEC CHECKSUMS:
Flutter: 9d0fac939486c9aba2809b7982dfdbb47a7b0296
PODFILE CHECKSUM: 13dcf421f4da2e937a57e8ba760ed880beae536f
COCOAPODS: 1.5.0
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; };
3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; };
9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; };
9740EEB51CF90195004384FC /* Generated.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB31CF90195004384FC /* Generated.xcconfig */; };
978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; };
97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */,
9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = "<group>"; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
97C146EB1CF9000F007C117D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */,
3B80C3941E831B6300D905FE /* App.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
3B80C3931E831B6300D905FE /* App.framework */,
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
9740EEBA1CF902C7004384FC /* Flutter.framework */,
9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
9740EEB31CF90195004384FC /* Generated.xcconfig */,
);
name = Flutter;
sourceTree = "<group>";
};
97C146E51CF9000F007C117D = {
isa = PBXGroup;
children = (
9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */,
);
sourceTree = "<group>";
};
97C146EF1CF9000F007C117D /* Products */ = {
isa = PBXGroup;
children = (
97C146EE1CF9000F007C117D /* Runner.app */,
);
name = Products;
sourceTree = "<group>";
};
97C146F01CF9000F007C117D /* Runner */ = {
isa = PBXGroup;
children = (
7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */,
7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */,
97C146FA1CF9000F007C117D /* Main.storyboard */,
97C146FD1CF9000F007C117D /* Assets.xcassets */,
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
97C147021CF9000F007C117D /* Info.plist */,
97C146F11CF9000F007C117D /* Supporting Files */,
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
);
path = Runner;
sourceTree = "<group>";
};
97C146F11CF9000F007C117D /* Supporting Files */ = {
isa = PBXGroup;
children = (
97C146F21CF9000F007C117D /* main.m */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
97C146ED1CF9000F007C117D /* Runner */ = {
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
);
buildRules = (
);
dependencies = (
);
name = Runner;
productName = Runner;
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0910;
ORGANIZATIONNAME = "The Chromium Authors";
TargetAttributes = {
97C146ED1CF9000F007C117D = {
CreatedOnToolsVersion = 7.3.1;
DevelopmentTeam = Z598PJ2NUG;
ProvisioningStyle = Automatic;
};
};
};
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 97C146E51CF9000F007C117D;
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
97C146ED1CF9000F007C117D /* Runner */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
97C146EC1CF9000F007C117D /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
9740EEB51CF90195004384FC /* Generated.xcconfig in Resources */,
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */,
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Thin Binary";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin";
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Run Script";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
97C146EA1CF9000F007C117D /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */,
97C146F31CF9000F007C117D /* main.m in Sources */,
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
97C146FA1CF9000F007C117D /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C146FB1CF9000F007C117D /* Base */,
);
name = Main.storyboard;
sourceTree = "<group>";
};
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C147001CF9000F007C117D /* Base */,
);
name = LaunchScreen.storyboard;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
97C147031CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
97C147041CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
97C147061CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ARCHS = arm64;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = Z598PJ2NUG;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
INFOPLIST_FILE = Runner/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 11.2;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
PRODUCT_BUNDLE_IDENTIFIER = com.jpeng.demo1;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
VERSIONING_SYSTEM = "apple-generic";
};
name = Debug;
};
97C147071CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ARCHS = arm64;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = Z598PJ2NUG;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
INFOPLIST_FILE = Runner/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 11.2;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
PRODUCT_BUNDLE_IDENTIFIER = com.jpeng.demo1;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
VERSIONING_SYSTEM = "apple-generic";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147031CF9000F007C117D /* Debug */,
97C147041CF9000F007C117D /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147061CF9000F007C117D /* Debug */,
97C147071CF9000F007C117D /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 97C146E61CF9000F007C117D /* Project object */;
}
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
</Workspace>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreviewsEnabled</key>
<false/>
</dict>
</plist>
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0910"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
</Workspace>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>BuildSystemType</key>
<string>Original</string>
</dict>
</plist>
#import <UIKit/UIKit.h>
#import <Flutter/Flutter.h>
@interface AppDelegate : FlutterAppDelegate
@end
#include "AppDelegate.h"
#include "GeneratedPluginRegistrant.h"
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[GeneratedPluginRegistrant registerWithRegistry:self];
// Override point for customization after application launch.
return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
@end
import UIKit
import Flutter
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
{
"images" : [
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@3x.png",
"scale" : "3x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@3x.png",
"scale" : "3x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@3x.png",
"scale" : "3x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@2x.png",
"scale" : "2x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@3x.png",
"scale" : "3x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@1x.png",
"scale" : "1x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@1x.png",
"scale" : "1x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@1x.png",
"scale" : "1x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@2x.png",
"scale" : "2x"
},
{
"size" : "83.5x83.5",
"idiom" : "ipad",
"filename" : "Icon-App-83.5x83.5@2x.png",
"scale" : "2x"
},
{
"size" : "1024x1024",
"idiom" : "ios-marketing",
"filename" : "Icon-App-1024x1024@1x.png",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
{
"images" : [
{
"idiom" : "universal",
"filename" : "LaunchImage.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "LaunchImage@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "LaunchImage@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
# Launch Screen Assets
You can customize the launch screen with your own desired assets by replacing the image files in this directory.
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.
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="Ydg-fD-yQy"/>
<viewControllerLayoutGuide type="bottom" id="xbc-2k-c8Z"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4">
</imageView>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="1a2-6s-vTC"/>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="4X2-HB-R7a"/>
</constraints>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
<resources>
<image name="LaunchImage" width="168" height="185"/>
</resources>
</document>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
</dependencies>
<scenes>
<!--Flutter View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="FlutterViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
</scene>
</scenes>
</document>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleLocalizations</key>
<array>
<string>fr</string>
<string>zh_CN</string>
<string>en</string>
</array>
<key>CFBundleName</key>
<string>PullRefreshDemo</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>arm64</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
</dict>
</plist>
#import "GeneratedPluginRegistrant.h"
#import <UIKit/UIKit.h>
#import <Flutter/Flutter.h>
#import "AppDelegate.h"
int main(int argc, char * argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
import 'package:example/other/refresh_glowindicator.dart';
import 'package:example/ui/MainActivity.dart';
import 'package:example/ui/SecondActivity.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
import 'ui/indicator/base/IndicatorActivity.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return RefreshConfiguration(
footerTriggerDistance: 15,
dragSpeedRatio: 0.91,
headerBuilder: () => MaterialClassicHeader(),
footerBuilder: () => ClassicFooter(),
enableLoadingWhenNoData: false,
enableRefreshVibrate: false,
enableLoadMoreVibrate: false,
shouldFooterFollowWhenNotFull: (state) {
// If you want load more with noMoreData state ,may be you should return false
return false;
},
child: MaterialApp(
title: 'Pulltorefresh Demo',
debugShowCheckedModeBanner: false,
builder: (context, child) {
return ScrollConfiguration(
child: child,
behavior: RefreshScrollBehavior(),
);
},
theme: ThemeData(
// This is the theme of your application.
//s
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or press Run > Flutter Hot Reload in IntelliJ). Notice that the
// counter didn't reset back to zero; the application is not restarted.
primarySwatch: Colors.blue,
primaryColor: Colors.greenAccent),
localizationsDelegates: [
RefreshLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalCupertinoLocalizations.delegate
],
supportedLocales: [
const Locale('en'),
const Locale('zh'),
const Locale('ja'),
const Locale('uk'),
const Locale('it'),
const Locale('ru'),
const Locale('fr'),
const Locale('es'),
const Locale('nl'),
const Locale('sv'),
const Locale('pt'),
const Locale('ko'),
],
locale: const Locale('ko'),
localeResolutionCallback:
(Locale locale, Iterable<Locale> supportedLocales) {
//print("change language");
return locale;
},
home: MainActivity(title: 'Pulltorefresh'),
routes: {
"sec": (BuildContext context) {
return SecondActivity(
title: "SecondAct",
);
},
"indicator": (BuildContext context) {
return IndicatorActivity();
}
},
),
);
}
}
/*
* Author: Jpeng
* Email: peng8350@gmail.com
* Time: 2019-05-26 23:09
*/
import 'package:pull_to_refresh/pull_to_refresh.dart';
import 'package:flutter/material.dart'
hide RefreshIndicator, RefreshIndicatorState;
class RunningHeader extends RefreshIndicator {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return RunningHeaderState();
}
}
class RunningHeaderState extends RefreshIndicatorState<RunningHeader>
with TickerProviderStateMixin {
AnimationController _scaleAnimation;
AnimationController _offsetController;
Tween<Offset> offsetTween;
@override
void initState() {
// TODO: implement initState
_scaleAnimation = AnimationController(vsync: this);
_offsetController = AnimationController(
vsync: this, duration: Duration(milliseconds: 1000));
offsetTween = Tween(end: Offset(0.6, 0.0), begin: Offset(0.0, 0.0));
super.initState();
}
@override
void onOffsetChange(double offset) {
// TODO: implement onOffsetChange
if (!floating) {
_scaleAnimation.value = offset / 80.0;
}
super.onOffsetChange(offset);
}
@override
void resetValue() {
// TODO: implement handleModeChange
_scaleAnimation.value = 0.0;
_offsetController.value = 0.0;
}
@override
void dispose() {
// TODO: implement dispose
_scaleAnimation.dispose();
_offsetController.dispose();
super.dispose();
}
@override
Future<void> endRefresh() {
// TODO: implement endRefresh
return _offsetController.animateTo(1.0).whenComplete(() {});
}
@override
Widget buildContent(BuildContext context, RefreshStatus mode) {
// TODO: implement buildContent
return SlideTransition(
child: ScaleTransition(
child: (mode != RefreshStatus.idle || mode != RefreshStatus.canRefresh)
? Image.asset("images/custom_2.gif")
: Image.asset("images/custom_1.jpg"),
scale: _scaleAnimation,
),
position: offsetTween.animate(_offsetController),
);
}
}
import 'package:flutter/widgets.dart';
import 'package:flutter_spinkit/src/utils.dart';
class SpinKitFadingCircle extends StatefulWidget {
SpinKitFadingCircle({
Key key,
this.color,
this.size = 50.0,
this.itemBuilder,
this.animationController,
this.duration = const Duration(milliseconds: 1200),
}) : assert(
!(itemBuilder is IndexedWidgetBuilder && color is Color) &&
!(itemBuilder == null && color == null),
'You should specify either a itemBuilder or a color'),
assert(size != null),
super(key: key);
final Color color;
final double size;
final IndexedWidgetBuilder itemBuilder;
final AnimationController animationController;
final Duration duration;
@override
_SpinKitFadingCircleState createState() => _SpinKitFadingCircleState();
}
class _SpinKitFadingCircleState extends State<SpinKitFadingCircle>
with SingleTickerProviderStateMixin {
@override
void initState() {
super.initState();
// _controller = AnimationController(vsync: this, duration: widget.duration)
// ..repeat();
}
@override
void dispose() {
// _controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Center(
child: SizedBox.fromSize(
size: Size.square(widget.size),
child: Stack(
children: [
_circle(1, .0),
_circle(2, -1.1),
_circle(3, -1.0),
_circle(4, -0.9),
_circle(5, -0.8),
_circle(6, -0.7),
_circle(7, -0.6),
_circle(8, -0.5),
_circle(9, -0.4),
_circle(10, -0.3),
_circle(11, -0.2),
_circle(12, -0.1),
],
),
),
);
}
Widget _circle(int i, [double delay]) {
final _size = widget.size * 0.15, _position = widget.size * .5;
return Positioned.fill(
left: _position,
top: _position,
child: Transform(
transform: Matrix4.rotationZ(30.0 * (i - 1) * 0.0174533),
child: Align(
alignment: Alignment.center,
child: FadeTransition(
opacity: DelayTween(begin: 0.0, end: 1.0, delay: delay)
.animate(widget.animationController),
child: SizedBox.fromSize(
size: Size.square(_size),
child: _itemBuilder(i - 1),
),
),
),
),
);
}
Widget _itemBuilder(int index) {
return widget.itemBuilder != null
? widget.itemBuilder(context, index)
: DecoratedBox(
decoration: BoxDecoration(
color: widget.color,
shape: BoxShape.circle,
),
);
}
}
/*
* Author: Jpeng
* Email: peng8350@gmail.com
* Time: 2019-07-11 12:23
*/
import 'package:flutter/cupertino.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
import 'dart:math' as math;
/*
aim to implements expand all the free empty place when viewport is not full
,but this can not correction offset,due to _minScrollExtent,_maxScrollExtent private in RenderViewport
,no idea how to do. without doing this,chat list (top when not full && reverse = true) can not be done.
in my plugin similar issue:#127,# 118
in flutter similar issue:#12650,#33399,#17444
*/
class ExpandedViewport extends Viewport {
ExpandedViewport({
Key key,
AxisDirection axisDirection = AxisDirection.down,
AxisDirection crossAxisDirection,
double anchor = 0.0,
ScrollPosition offset,
Key center,
double cacheExtent,
List<Widget> slivers = const <Widget>[],
}) : super(
key: key,
slivers: slivers,
axisDirection: axisDirection,
crossAxisDirection: crossAxisDirection,
anchor: anchor,
offset: offset,
center: center,
cacheExtent: cacheExtent);
@override
RenderViewport createRenderObject(BuildContext context) {
// TODO: implement createRenderObject
return _RenderExpandedViewport(
axisDirection: axisDirection,
crossAxisDirection: crossAxisDirection ??
Viewport.getDefaultCrossAxisDirection(context, axisDirection),
anchor: anchor,
offset: offset,
cacheExtent: cacheExtent,
);
}
}
class _RenderExpandedViewport extends RenderViewport {
_RenderExpandedViewport({
AxisDirection axisDirection = AxisDirection.down,
@required AxisDirection crossAxisDirection,
@required ViewportOffset offset,
double anchor = 0.0,
List<RenderSliver> children,
RenderSliver center,
double cacheExtent,
}) : super(
axisDirection: axisDirection,
crossAxisDirection: crossAxisDirection,
offset: offset,
anchor: anchor,
children: children,
center: center,
cacheExtent: cacheExtent);
@override
void performLayout() {
// TODO: implement performLayout
super.performLayout();
RenderSliver expand;
RenderSliver p = firstChild;
double totalLayoutExtent = 0;
double frontExtent = 0.0;
while (p != null) {
totalLayoutExtent += p.geometry.scrollExtent;
if (p is _RenderExpanded) {
expand = p;
frontExtent = totalLayoutExtent;
}
p = childAfter(p);
}
if (expand != null && size.height > totalLayoutExtent) {
_attemptLayout(expand, size.height, size.width,
offset.pixels - frontExtent - (size.height - totalLayoutExtent));
}
}
// _minScrollExtent private in super,no setter method
double _attemptLayout(RenderSliver expandPosition, double mainAxisExtent,
double crossAxisExtent, double correctedOffset) {
assert(!mainAxisExtent.isNaN);
assert(mainAxisExtent >= 0.0);
assert(crossAxisExtent.isFinite);
assert(crossAxisExtent >= 0.0);
assert(correctedOffset.isFinite);
// centerOffset is the offset from the leading edge of the RenderViewport
// to the zero scroll offset (the line between the forward slivers and the
// reverse slivers).
final double centerOffset = mainAxisExtent * anchor - correctedOffset;
final double reverseDirectionRemainingPaintExtent =
centerOffset.clamp(0.0, mainAxisExtent);
final double forwardDirectionRemainingPaintExtent =
(mainAxisExtent - centerOffset).clamp(0.0, mainAxisExtent);
final double fullCacheExtent = mainAxisExtent + 2 * cacheExtent;
final double centerCacheOffset = centerOffset + cacheExtent;
final double forwardDirectionRemainingCacheExtent =
(fullCacheExtent - centerCacheOffset).clamp(0.0, fullCacheExtent);
final RenderSliver leadingNegativeChild = childBefore(center);
// positive scroll offsets
return layoutChildSequence(
child: expandPosition,
scrollOffset: math.max(0.0, -centerOffset),
overlap:
leadingNegativeChild == null ? math.min(0.0, -centerOffset) : 0.0,
layoutOffset: centerOffset >= mainAxisExtent
? centerOffset
: reverseDirectionRemainingPaintExtent,
remainingPaintExtent: forwardDirectionRemainingPaintExtent,
mainAxisExtent: mainAxisExtent,
crossAxisExtent: crossAxisExtent,
growthDirection: GrowthDirection.forward,
advance: childAfter,
remainingCacheExtent: forwardDirectionRemainingCacheExtent,
cacheOrigin: centerOffset.clamp(-cacheExtent, 0.0),
);
}
}
//tag
class SliverExpanded extends SingleChildRenderObjectWidget {
SliverExpanded() : super(child: Container());
@override
RenderSliver createRenderObject(BuildContext context) {
// TODO: implement createRenderObject
return _RenderExpanded();
}
}
class _RenderExpanded extends RenderSliver
with RenderObjectWithChildMixin<RenderBox> {
@override
void performLayout() {
// TODO: implement performLayout
geometry = SliverGeometry.zero;
}
}
/*
* Author: Jpeng
* Email: peng8350@gmail.com
* Time: 2019-09-08 14:44
*/
import 'package:flutter/material.dart';
// 在不自定义的默认情况下,当你拖到顶端不能再拖的时候会出现光晕,假如你只想在撞击顶部时看到光晕的情况
// 以下例子就是可以解决这种问题
// Android平台 自定义刷新光晕效果
class RefreshScrollBehavior extends ScrollBehavior {
@override
Widget buildViewportChrome(
BuildContext context, Widget child, AxisDirection axisDirection) {
// When modifying this function, consider modifying the implementation in
// _MaterialScrollBehavior as well.
switch (getPlatform(context)) {
case TargetPlatform.iOS:
return child;
case TargetPlatform.macOS:
case TargetPlatform.android:
return GlowingOverscrollIndicator(
child: child,
// this will disable top Bouncing OverScroll Indicator showing in Android
showLeading: true, //顶部水波纹是否展示
showTrailing: true, //底部水波纹是否展示
axisDirection: axisDirection,
notificationPredicate: (notification) {
if (notification.depth == 0) {
// 越界了拖动触发overScroll的话就没必要展示水波纹
if (notification.metrics.outOfRange) {
return false;
}
return true;
}
return false;
},
color: Theme.of(context).primaryColor,
);
case TargetPlatform.fuchsia:
case TargetPlatform.linux:
case TargetPlatform.windows:
}
return null;
}
}
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:math';
import 'package:flutter/rendering.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
import 'package:flutter/material.dart' hide RefreshIndicator;
// Examples can assume:
// class MyDataObject { }
/// The callback used by [ReorderableListView] to move an item to a new
/// position in a list.
///
/// Implementations should remove the corresponding list item at [oldIndex]
/// and reinsert it at [newIndex].
///
/// If [oldIndex] is before [newIndex], removing the item at [oldIndex] from the
/// list will reduce the list's length by one. Implementations used by
/// [ReorderableListView] will need to account for this when inserting before
/// [newIndex].
///
/// {@tool sample}
///
/// ```dart
/// final List<MyDataObject> backingList = <MyDataObject>[/* ... */];
///
/// void handleReorder(int oldIndex, int newIndex) {
/// if (oldIndex < newIndex) {
/// // removing the item at oldIndex will shorten the list by 1.
/// newIndex -= 1;
/// }
/// final MyDataObject element = backingList.removeAt(oldIndex);
/// backingList.insert(newIndex, element);
/// }
/// ```
/// {@end-tool}
typedef ReorderCallback = void Function(int oldIndex, int newIndex);
/// A list whose items the user can interactively reorder by dragging.
///
/// This class is appropriate for views with a small number of
/// children because constructing the [List] requires doing work for every
/// child that could possibly be displayed in the list view instead of just
/// those children that are actually visible.
///
/// All [children] must have a key.
class RefreshReorderableListView extends StatefulWidget {
final RefreshIndicator refreshHeader;
final LoadIndicator refreshFooter;
final bool enablePullUp;
final bool enablePullDown;
final Function onRefresh, onLoading;
final Function onOffsetChange;
final RefreshController refreshController;
/// Creates a reorderable list.
RefreshReorderableListView({
this.header,
@required this.children,
@required this.onReorder,
this.scrollDirection = Axis.vertical,
this.padding,
this.reverse = false,
@required this.refreshController,
this.refreshHeader,
this.refreshFooter,
this.enablePullDown: true,
this.enablePullUp: false,
this.onRefresh,
this.onLoading,
this.onOffsetChange,
}) : assert(scrollDirection != null),
assert(onReorder != null),
assert(children != null),
assert(
children.every((Widget w) => w.key != null),
'All children of this widget must have a key.',
);
/// A non-reorderable header widget to show before the list.
///
/// If null, no header will appear before the list.
final Widget header;
/// The widgets to display.
final List<Widget> children;
/// The [Axis] along which the list scrolls.
///
/// List [children] can only drag along this [Axis].
final Axis scrollDirection;
/// The amount of space by which to inset the [children].
final EdgeInsets padding;
/// Whether the scroll view scrolls in the reading direction.
///
/// For example, if the reading direction is left-to-right and
/// [scrollDirection] is [Axis.horizontal], then the scroll view scrolls from
/// left to right when [reverse] is false and from right to left when
/// [reverse] is true.
///
/// Similarly, if [scrollDirection] is [Axis.vertical], then the scroll view
/// scrolls from top to bottom when [reverse] is false and from bottom to top
/// when [reverse] is true.
///
/// Defaults to false.
final bool reverse;
/// Called when a list child is dropped into a new position to shuffle the
/// underlying list.
///
/// This [ReorderableListView] calls [onReorder] after a list child is dropped
/// into a new position.
final ReorderCallback onReorder;
@override
_ReorderableListViewState createState() => _ReorderableListViewState();
}
// This top-level state manages an Overlay that contains the list and
// also any Draggables it creates.
//
// _ReorderableListContent manages the list itself and reorder operations.
//
// The Overlay doesn't properly keep state by building new overlay entries,
// and so we cache a single OverlayEntry for use as the list layer.
// That overlay entry then builds a _ReorderableListContent which may
// insert Draggables into the Overlay above itself.
class _ReorderableListViewState extends State<RefreshReorderableListView> {
// We use an inner overlay so that the dragging list item doesn't draw outside of the list itself.
final GlobalKey _overlayKey =
GlobalKey(debugLabel: '$ReorderableListView overlay key');
// This entry contains the scrolling list itself.
OverlayEntry _listOverlayEntry;
@override
void initState() {
super.initState();
_listOverlayEntry = OverlayEntry(
opaque: true,
builder: (BuildContext context) {
return _ReorderableListContent(
header: widget.header,
children: widget.children,
scrollDirection: widget.scrollDirection,
onReorder: widget.onReorder,
padding: widget.padding,
reverse: widget.reverse,
refreshController: widget.refreshController,
enablePullDown: widget.enablePullDown,
enablePullUp: widget.enablePullUp,
refreshFooter: widget.refreshFooter,
refreshHeader: widget.refreshHeader,
onOffsetChange: widget.onOffsetChange,
onLoading: widget.onLoading,
onRefresh: widget.onRefresh,
);
},
);
}
@override
Widget build(BuildContext context) {
return Overlay(key: _overlayKey, initialEntries: <OverlayEntry>[
_listOverlayEntry,
]);
}
}
// This widget is responsible for the inside of the Overlay in the
// ReorderableListView.
class _ReorderableListContent extends StatefulWidget {
const _ReorderableListContent({
@required this.header,
@required this.children,
@required this.scrollDirection,
@required this.padding,
@required this.onReorder,
@required this.reverse,
@required this.refreshController,
this.refreshHeader,
this.refreshFooter,
this.enablePullDown: true,
this.enablePullUp: false,
this.onRefresh,
this.onLoading,
this.onOffsetChange,
});
final RefreshIndicator refreshHeader;
final LoadIndicator refreshFooter;
final bool enablePullUp;
final bool enablePullDown;
final Function onRefresh, onLoading;
final Function onOffsetChange;
final RefreshController refreshController;
final Widget header;
final List<Widget> children;
final Axis scrollDirection;
final EdgeInsets padding;
final ReorderCallback onReorder;
final bool reverse;
@override
_ReorderableListContentState createState() => _ReorderableListContentState();
}
class _ReorderableListContentState extends State<_ReorderableListContent>
with TickerProviderStateMixin<_ReorderableListContent> {
// The extent along the [widget.scrollDirection] axis to allow a child to
// drop into when the user reorders list children.
//
// This value is used when the extents haven't yet been calculated from
// the currently dragging widget, such as when it first builds.
static const double _defaultDropAreaExtent = 100.0;
// The additional margin to place around a computed drop area.
static const double _dropAreaMargin = 8.0;
// How long an animation to reorder an element in the list takes.
static const Duration _reorderAnimationDuration = Duration(milliseconds: 200);
// How long an animation to scroll to an off-screen element in the
// list takes.
static const Duration _scrollAnimationDuration = Duration(milliseconds: 200);
// Controls scrolls and measures scroll progress.
ScrollController _scrollController;
// This controls the entrance of the dragging widget into a new place.
AnimationController _entranceController;
// This controls the 'ghost' of the dragging widget, which is left behind
// where the widget used to be.
AnimationController _ghostController;
// The member of widget.children currently being dragged.
//
// Null if no drag is underway.
Key _dragging;
// The last computed size of the feedback widget being dragged.
Size _draggingFeedbackSize;
// The location that the dragging widget occupied before it started to drag.
int _dragStartIndex = 0;
// The index that the dragging widget most recently left.
// This is used to show an animation of the widget's position.
int _ghostIndex = 0;
// The index that the dragging widget currently occupies.
int _currentIndex = 0;
// The widget to move the dragging widget too after the current index.
int _nextIndex = 0;
// Whether or not we are currently scrolling this view to show a widget.
bool _scrolling = false;
double get _dropAreaExtent {
if (_draggingFeedbackSize == null) {
return _defaultDropAreaExtent;
}
double dropAreaWithoutMargin;
switch (widget.scrollDirection) {
case Axis.horizontal:
dropAreaWithoutMargin = _draggingFeedbackSize.width;
break;
case Axis.vertical:
default:
dropAreaWithoutMargin = _draggingFeedbackSize.height;
break;
}
return dropAreaWithoutMargin + _dropAreaMargin;
}
@override
void initState() {
super.initState();
_entranceController =
AnimationController(vsync: this, duration: _reorderAnimationDuration);
_ghostController =
AnimationController(vsync: this, duration: _reorderAnimationDuration);
_entranceController.addStatusListener(_onEntranceStatusChanged);
}
@override
void didChangeDependencies() {
_scrollController =
PrimaryScrollController.of(context) ?? ScrollController();
super.didChangeDependencies();
}
@override
void dispose() {
_entranceController.dispose();
_ghostController.dispose();
super.dispose();
}
// Animates the droppable space from _currentIndex to _nextIndex.
void _requestAnimationToNextIndex() {
if (_entranceController.isCompleted) {
_ghostIndex = _currentIndex;
if (_nextIndex == _currentIndex) {
return;
}
_currentIndex = _nextIndex;
_ghostController.reverse(from: 1.0);
_entranceController.forward(from: 0.0);
}
}
// Requests animation to the latest next index if it changes during an animation.
void _onEntranceStatusChanged(AnimationStatus status) {
if (status == AnimationStatus.completed) {
setState(() {
_requestAnimationToNextIndex();
});
}
}
// Scrolls to a target context if that context is not on the screen.
void _scrollTo(BuildContext context) {
if (_scrolling) return;
final RenderObject contextObject = context.findRenderObject();
final RenderAbstractViewport viewport =
RenderAbstractViewport.of(contextObject);
assert(viewport != null);
// If and only if the current scroll offset falls in-between the offsets
// necessary to reveal the selected context at the top or bottom of the
// screen, then it is already on-screen.
final double margin = _dropAreaExtent;
final double scrollOffset = _scrollController.offset;
final double topOffset = max(
_scrollController.position.minScrollExtent,
viewport.getOffsetToReveal(contextObject, 0.0).offset - margin,
);
final double bottomOffset = min(
_scrollController.position.maxScrollExtent,
viewport.getOffsetToReveal(contextObject, 1.0).offset + margin,
);
final bool onScreen =
scrollOffset <= topOffset && scrollOffset >= bottomOffset;
// If the context is off screen, then we request a scroll to make it visible.
if (!onScreen) {
_scrolling = true;
_scrollController.position
.animateTo(
scrollOffset < bottomOffset ? bottomOffset : topOffset,
duration: _scrollAnimationDuration,
curve: Curves.easeInOut,
)
.then((void value) {
setState(() {
_scrolling = false;
});
});
}
}
// Wraps children in Row or Column, so that the children flow in
// the widget's scrollDirection.
Widget _buildContainerForScrollDirection({List<Widget> children}) {
switch (widget.scrollDirection) {
case Axis.horizontal:
return Row(children: children);
case Axis.vertical:
default:
return Column(children: children);
}
}
// Wraps one of the widget's children in a DragTarget and Draggable.
// Handles up the logic for dragging and reordering items in the list.
Widget _wrap(Widget toWrap, int index, BoxConstraints constraints) {
assert(toWrap.key != null);
final GlobalObjectKey keyIndexGlobalKey = GlobalObjectKey(toWrap.key);
// We pass the toWrapWithGlobalKey into the Draggable so that when a list
// item gets dragged, the accessibility framework can preserve the selected
// state of the dragging item.
// Starts dragging toWrap.
void onDragStarted() {
setState(() {
_dragging = toWrap.key;
_dragStartIndex = index;
_ghostIndex = index;
_currentIndex = index;
_entranceController.value = 1.0;
_draggingFeedbackSize = keyIndexGlobalKey.currentContext.size;
});
}
// Places the value from startIndex one space before the element at endIndex.
void reorder(int startIndex, int endIndex) {
setState(() {
if (startIndex != endIndex) widget.onReorder(startIndex, endIndex);
// Animates leftover space in the drop area closed.
// TODO(djshuckerow): bring the animation in line with the Material
// specifications.
_ghostController.reverse(from: 0.1);
_entranceController.reverse(from: 0.1);
_dragging = null;
});
}
// Drops toWrap into the last position it was hovering over.
void onDragEnded() {
reorder(_dragStartIndex, _currentIndex);
}
Widget wrapWithSemantics() {
// First, determine which semantics actions apply.
final Map<CustomSemanticsAction, VoidCallback> semanticsActions =
<CustomSemanticsAction, VoidCallback>{};
// Create the appropriate semantics actions.
void moveToStart() => reorder(index, 0);
void moveToEnd() => reorder(index, widget.children.length);
void moveBefore() => reorder(index, index - 1);
// To move after, we go to index+2 because we are moving it to the space
// before index+2, which is after the space at index+1.
void moveAfter() => reorder(index, index + 2);
final MaterialLocalizations localizations =
MaterialLocalizations.of(context);
// If the item can move to before its current position in the list.
if (index > 0) {
semanticsActions[CustomSemanticsAction(
label: localizations.reorderItemToStart)] = moveToStart;
String reorderItemBefore = localizations.reorderItemUp;
if (widget.scrollDirection == Axis.horizontal) {
reorderItemBefore = Directionality.of(context) == TextDirection.ltr
? localizations.reorderItemLeft
: localizations.reorderItemRight;
}
semanticsActions[CustomSemanticsAction(label: reorderItemBefore)] =
moveBefore;
}
// If the item can move to after its current position in the list.
if (index < widget.children.length - 1) {
String reorderItemAfter = localizations.reorderItemDown;
if (widget.scrollDirection == Axis.horizontal) {
reorderItemAfter = Directionality.of(context) == TextDirection.ltr
? localizations.reorderItemRight
: localizations.reorderItemLeft;
}
semanticsActions[CustomSemanticsAction(label: reorderItemAfter)] =
moveAfter;
semanticsActions[
CustomSemanticsAction(label: localizations.reorderItemToEnd)] =
moveToEnd;
}
// We pass toWrap with a GlobalKey into the Draggable so that when a list
// item gets dragged, the accessibility framework can preserve the selected
// state of the dragging item.
//
// We also apply the relevant custom accessibility actions for moving the item
// up, down, to the start, and to the end of the list.
return KeyedSubtree(
key: keyIndexGlobalKey,
child: MergeSemantics(
child: Semantics(
customSemanticsActions: semanticsActions,
child: toWrap,
),
),
);
}
Widget buildDragTarget(BuildContext context, List<Key> acceptedCandidates,
List<dynamic> rejectedCandidates) {
final Widget toWrapWithSemantics = wrapWithSemantics();
// We build the draggable inside of a layout builder so that we can
// constrain the size of the feedback dragging widget.
Widget child = LongPressDraggable<Key>(
maxSimultaneousDrags: 1,
axis: widget.scrollDirection,
data: toWrap.key,
ignoringFeedbackSemantics: false,
feedback: Container(
alignment: Alignment.topLeft,
// These constraints will limit the cross axis of the drawn widget.
constraints: constraints,
child: Material(
elevation: 6.0,
child: toWrapWithSemantics,
),
),
child: _dragging == toWrap.key ? const SizedBox() : toWrapWithSemantics,
childWhenDragging: const SizedBox(),
dragAnchor: DragAnchor.child,
onDragStarted: onDragStarted,
// When the drag ends inside a DragTarget widget, the drag
// succeeds, and we reorder the widget into position appropriately.
onDragCompleted: onDragEnded,
// When the drag does not end inside a DragTarget widget, the
// drag fails, but we still reorder the widget to the last position it
// had been dragged to.
onDraggableCanceled: (Velocity velocity, Offset offset) {
onDragEnded();
},
);
// The target for dropping at the end of the list doesn't need to be
// draggable.
if (index >= widget.children.length) {
child = toWrap;
}
// Determine the size of the drop area to show under the dragging widget.
Widget spacing;
switch (widget.scrollDirection) {
case Axis.horizontal:
spacing = SizedBox(width: _dropAreaExtent);
break;
case Axis.vertical:
default:
spacing = SizedBox(height: _dropAreaExtent);
break;
}
// We open up a space under where the dragging widget currently is to
// show it can be dropped.
if (_currentIndex == index) {
return _buildContainerForScrollDirection(children: <Widget>[
SizeTransition(
sizeFactor: _entranceController,
axis: widget.scrollDirection,
child: spacing,
),
child,
]);
}
// We close up the space under where the dragging widget previously was
// with the ghostController animation.
if (_ghostIndex == index) {
return _buildContainerForScrollDirection(children: <Widget>[
SizeTransition(
sizeFactor: _ghostController,
axis: widget.scrollDirection,
child: spacing,
),
child,
]);
}
return child;
}
// We wrap the drag target in a Builder so that we can scroll to its specific context.
return Builder(builder: (BuildContext context) {
return DragTarget<Key>(
builder: buildDragTarget,
onWillAccept: (Key toAccept) {
setState(() {
_nextIndex = index;
_requestAnimationToNextIndex();
});
_scrollTo(context);
// If the target is not the original starting point, then we will accept the drop.
return _dragging == toAccept && toAccept != toWrap.key;
},
onAccept: (Key accepted) {},
onLeave: (_) {},
);
});
}
@override
Widget build(BuildContext context) {
// We use the layout builder to constrain the cross-axis size of dragging child widgets.
return LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
final List<Widget> wrappedChildren = <Widget>[];
if (widget.header != null) {
wrappedChildren.add(widget.header);
}
for (int i = 0; i < widget.children.length; i += 1) {
wrappedChildren.add(_wrap(widget.children[i], i, constraints));
}
const Key endWidgetKey = Key('DraggableList - End Widget');
Widget finalDropArea;
switch (widget.scrollDirection) {
case Axis.horizontal:
finalDropArea = SizedBox(
key: endWidgetKey,
width: _defaultDropAreaExtent,
height: constraints.maxHeight,
);
break;
case Axis.vertical:
default:
finalDropArea = SizedBox(
key: endWidgetKey,
height: _defaultDropAreaExtent,
width: constraints.maxWidth,
);
break;
}
if (widget.reverse) {
wrappedChildren.insert(
0,
_wrap(finalDropArea, widget.children.length, constraints),
);
} else {
wrappedChildren.add(
_wrap(finalDropArea, widget.children.length, constraints),
);
}
return SmartRefresher(
child: ListView(
scrollDirection: widget.scrollDirection,
children: [
_buildContainerForScrollDirection(children: wrappedChildren)
],
padding: widget.padding,
controller: _scrollController,
reverse: widget.reverse,
),
controller: widget.refreshController,
enablePullDown: widget.enablePullDown,
enablePullUp: widget.enablePullUp,
footer: widget.refreshFooter,
header: widget.refreshHeader,
onOffsetChange: widget.onOffsetChange,
onLoading: widget.onLoading,
onRefresh: widget.onRefresh,
);
});
}
}
/*
* Author: Jpeng
* Email: peng8350@gmail.com
* Time: 2019-07-08 10:51
*/
import 'package:flutter/material.dart' as prefix0;
import 'package:pull_to_refresh/pull_to_refresh.dart';
import 'package:flutter/material.dart'
hide RefreshIndicator, RefreshIndicatorState;
import 'package:shimmer/shimmer.dart';
/*
use to implements indicaotr
https://github.com/hnvn/flutter_shimmer
how to use?
in ui/example/customindicator/shimmer_indicaotr.dart,
it will show you how to use
*/
class ShimmerHeader extends RefreshIndicator {
final Color baseColor, highlightColor;
final Widget text;
final Duration period;
final ShimmerDirection direction;
final Function outerBuilder;
ShimmerHeader(
{@required this.text,
this.baseColor = Colors.grey,
this.highlightColor = Colors.white,
this.outerBuilder,
double height: 80.0,
this.period = const Duration(milliseconds: 1000),
this.direction = ShimmerDirection.ltr})
: super(height: height, refreshStyle: RefreshStyle.Behind);
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return _ShimmerHeaderState();
}
}
class _ShimmerHeaderState extends RefreshIndicatorState<ShimmerHeader>
with TickerProviderStateMixin {
AnimationController _scaleController;
AnimationController _fadeController;
@override
void initState() {
// TODO: implement initState
_scaleController = AnimationController(vsync: this);
_fadeController = AnimationController(vsync: this);
super.initState();
}
@override
void onOffsetChange(double offset) {
// TODO: implement onOffsetChange
if (!floating) {
_scaleController.value = offset / configuration.headerTriggerDistance;
_fadeController.value = offset / configuration.footerTriggerDistance;
}
}
@override
Widget buildContent(BuildContext context, RefreshStatus mode) {
// TODO: implement buildContent
final Widget body = ScaleTransition(
scale: _scaleController,
child: FadeTransition(
opacity: _fadeController,
child: mode == RefreshStatus.refreshing
? Shimmer.fromColors(
period: widget.period,
direction: widget.direction,
baseColor: widget.baseColor,
highlightColor: widget.highlightColor,
child: Center(
child: widget.text,
),
)
: Center(
child: widget.text,
),
),
);
return widget.outerBuilder != null
? widget.outerBuilder(body)
: Container(
alignment: prefix0.Alignment.center,
child: body,
decoration: prefix0.BoxDecoration(color: Colors.black12),
);
}
}
class ShimmerFooter extends LoadIndicator {
final Color baseColor, highlightColor;
final Widget text, failed, noMore;
final Duration period;
final ShimmerDirection direction;
final Function outerBuilder;
ShimmerFooter(
{@required this.text,
this.baseColor = Colors.grey,
this.highlightColor = Colors.white,
this.outerBuilder,
double height: 80.0,
this.failed,
this.noMore,
this.period = const Duration(milliseconds: 1000),
this.direction = ShimmerDirection.ltr,
LoadStyle loadStyle: LoadStyle.ShowAlways})
: super(height: height, loadStyle: loadStyle);
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return _ShimmerFooterState();
}
}
class _ShimmerFooterState extends LoadIndicatorState<ShimmerFooter> {
@override
Widget buildContent(BuildContext context, LoadStatus mode) {
// TODO: implement buildContent
final Widget body = mode == LoadStatus.failed
? widget.failed
: mode == LoadStatus.noMore
? widget.noMore
: mode == LoadStatus.idle
? Center(child: widget.text)
: Shimmer.fromColors(
period: widget.period,
direction: widget.direction,
baseColor: widget.baseColor,
highlightColor: widget.highlightColor,
child: Center(
child: widget.text,
),
);
return widget.outerBuilder != null
? widget.outerBuilder(body)
: Container(
height: widget.height,
child: body,
decoration: prefix0.BoxDecoration(color: Colors.black12),
);
}
}
/*
* Author: Jpeng
* Email: peng8350@gmail.com
* Time: 2019/5/7 下午12:22
*/
import 'package:flutter/material.dart';
class Item extends StatefulWidget {
final String title;
Item({this.title});
@override
_ItemState createState() => _ItemState();
}
class _ItemState extends State<Item> {
@override
Widget build(BuildContext context) {
return Container(
child: Card(
margin: EdgeInsets.only(left: 10.0, right: 10.0, top: 5.0, bottom: 5.0),
child: Center(
child: Text(widget.title),
),
),
height: 100.0,
);
}
@override
void dispose() {
// TODO: implement dispose
super.dispose();
}
}
/*
* Author: Jpeng
* Email: peng8350@gmail.com
* Time: 2019/5/3 下午6:13
*/
import 'package:flutter/material.dart';
import 'package:residemenu/residemenu.dart';
import 'example/ExamplePage.dart';
import 'test/TestPage.dart';
import 'indicator/IndicatorPage.dart';
class MainActivity extends StatefulWidget {
final String title;
MainActivity({this.title});
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return _MainActivityState();
}
}
class _MainActivityState extends State<MainActivity>
with TickerProviderStateMixin {
List<Widget> views;
MenuController _menuController;
TabController _tabController;
int _tabIndex = 1;
PageController _pageController;
Widget buildItem(String msg, Widget icon, Function voidCallBack) {
return Material(
color: Colors.transparent,
child: InkWell(
child: ResideMenuItem(
title: msg,
icon: icon,
right: const Icon(Icons.arrow_forward, color: Colors.grey),
),
onTap: voidCallBack,
),
);
}
@override
void initState() {
// TODO: implement initState
super.initState();
_tabController = TabController(length: 6, vsync: this);
_menuController =
MenuController(vsync: this, direction: ScrollDirection.LEFT);
_pageController = PageController(initialPage: 1);
views = [
IndicatorPage(title: "指示器界面"),
ExamplePage(),
TestPage(title: "测试界面"),
];
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return ResideMenu.scaffold(
controller: _menuController,
enable3dRotate: true,
child: Scaffold(
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text(_tabIndex == 0
? "指示器界面"
: _tabIndex == 1
? "例子界面"
: _tabIndex == 2
? "测试界面"
: _tabIndex == 3
? "样例界面"
: "App界面"),
leading: GestureDetector(
child: Icon(Icons.menu),
onTap: () {
_menuController.openMenu(true);
},
),
backgroundColor: Colors.greenAccent,
bottom: _tabIndex == 3
? TabBar(
isScrollable: true,
tabs: [
Tab(child: Text("超大数据量性能测试")),
Tab(child: Text("SliverAppbar+Sliverheader")),
Tab(child: Text("嵌套滚动视图")),
Tab(child: Text("动态变化指示器+Navigator")),
Tab(child: Text("主动刷新")),
Tab(child: Text("四个方向不同风格测试绘制")),
],
controller: _tabController,
)
: null,
),
body: PageView(
controller: _pageController,
children: views,
physics: NeverScrollableScrollPhysics(),
),
),
decoration: BoxDecoration(color: Colors.purple),
leftScaffold: MenuScaffold(
header: ConstrainedBox(
constraints: BoxConstraints(maxHeight: 80.0, maxWidth: 80.0),
child: CircleAvatar(
backgroundImage: NetworkImage(
'https://avatars1.githubusercontent.com/u/19425362?s=400&u=1a30f9fdf71cc9a51e20729b2fa1410c710d0f2f&v=4'),
radius: 40.0,
),
),
children: <Widget>[
buildItem("各种指示器", Icon(Icons.apps, size: 18, color: Colors.grey),
() {
setState(() {
_tabIndex = 0;
});
_pageController.jumpToPage(0);
_menuController.closeMenu();
}),
buildItem(
"例子", Icon(Icons.insert_emoticon, size: 18, color: Colors.grey),
() {
setState(() {
_tabIndex = 1;
});
_pageController.jumpToPage(1);
_menuController.closeMenu();
}),
buildItem("测试",
Icon(Icons.airplanemode_active, size: 18, color: Colors.grey),
() {
setState(() {
_tabIndex = 2;
});
_menuController.closeMenu();
_pageController.jumpToPage(2);
}),
],
),
);
}
}
/*
* Author: Jpeng
* Email: peng8350@gmail.com
* Time: 2019/3/29 下午4:27
*/
import 'package:flutter/material.dart';
class SecondActivity extends StatefulWidget {
SecondActivity({Key key, this.title}) : super(key: key);
// This widget is the home page of your application. It is stateful, meaning
// that it has a State object (defined below) that contains fields that affect
// how it looks.
// This class is the configuration for the state. It holds the values (in this
// case the title) provided by the parent (in this case the App widget) and
// used by the build method of the State. Fields in a Widget subclass are
// always marked "final".
final String title;
@override
_SecondActivityState createState() => new _SecondActivityState();
}
class _SecondActivityState extends State<SecondActivity> {
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text(widget.title),
leading: GestureDetector(
child: Container(
child: Row(
children: <Widget>[Icon(Icons.keyboard_arrow_left), Text("返回")],
),
),
onTap: () {
Navigator.of(context).pop();
}),
),
body: Text("测试跳转返回"),
);
}
}
/*
* Author: Jpeng
* Email: peng8350@gmail.com
* Time: 2019-06-24 17:21
*/
import 'package:example/ui/example/customindicator/footer_underscroll.dart';
import 'package:example/ui/example/customindicator/shimmer_indicator.dart';
import 'package:example/ui/example/useStage/force_full_one_page.dart';
import 'package:flutter/material.dart';
import 'otherwidget/refresh_staggered_and_sticky.dart';
import 'package:example/ui/example/useStage/empty_view.dart';
import 'customindicator/gif_indicator_example1.dart';
import 'package:example/ui/example/useStage/hidefooter_bycontent.dart';
import 'package:example/ui/example/otherwidget/refesh_expansiopn_panel_list_example.dart';
import 'package:example/ui/example/useStage/horizontal+reverse.dart';
import 'package:example/ui/example/useStage/Nested.dart';
import 'package:example/ui/example/otherwidget/refresh_animatedlist_example.dart';
import 'package:example/ui/example/customindicator/spinkit_header.dart';
import 'package:example/ui/example/useStage/basic.dart';
import 'package:example/ui/example/otherwidget/refresh_pageView_example.dart';
import 'package:example/ui/example/customindicator/link_header_example.dart';
import 'package:example/ui/example/useStage/twolevel_refresh.dart';
import 'useStage/qq_chat_list.dart';
import 'otherwidget/refresh_recordable_listview_example.dart';
import 'otherwidget/draggable_bottomsheet_loadmore.dart';
import 'useStage/tapbutton_refresh.dart';
class ExamplePage extends StatefulWidget {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return _ExamplePageState();
}
}
class ExampleItem extends StatefulWidget {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return _ExampleItemState();
}
final Function onClick;
final String title;
ExampleItem({this.title, this.onClick});
}
class _ExampleItemState extends State<ExampleItem> {
@override
Widget build(BuildContext context) {
// TODO: implement build
return InkWell(
onTap: widget.onClick,
child: Container(
height: 100.0,
child: Card(
child: Center(
child: Text(widget.title),
),
),
),
);
}
}
class _ExamplePageState extends State<ExamplePage>
with SingleTickerProviderStateMixin {
TabController _tabController;
@override
void initState() {
// TODO: implement initState
_tabController = TabController(initialIndex: 0, length: 3, vsync: this);
super.initState();
}
@override
Widget build(BuildContext context) {
// TODO: implement build
final List<ExampleItem> items1 = [
ExampleItem(
title: "基础用法",
onClick: () {
Navigator.of(context).push(MaterialPageRoute(builder: (context) {
return BasicExample();
}));
}),
ExampleItem(
title: "手动隐藏footer",
onClick: () {
Navigator.of(context).push(MaterialPageRoute(builder: (context) {
return Scaffold(
body: HideFooterManual(),
appBar: AppBar(),
);
}));
}),
ExampleItem(
title: "水平刷新",
onClick: () {
Navigator.of(context).push(MaterialPageRoute(builder: (context) {
return Scaffold(
body: HorizontalRefresh(),
appBar: AppBar(),
);
}));
}),
ExampleItem(
title: "点击按钮触发刷新",
onClick: () {
Navigator.of(context).push(MaterialPageRoute(builder: (context) {
return TapButtonRefreshExample();
}));
}),
ExampleItem(
title: "NestedScrollView下刷新",
onClick: () {
Navigator.of(context).push(MaterialPageRoute(builder: (context) {
return NestedRefresh();
}));
}),
ExampleItem(
title: "模仿qq聊天",
onClick: () {
Navigator.of(context).push(MaterialPageRoute(builder: (context) {
return QQChatList();
}));
}),
ExampleItem(
title: "空白视图+刷新",
onClick: () {
Navigator.of(context).push(MaterialPageRoute(builder: (context) {
return Scaffold(
body: RefreshWithEmptyView(),
appBar: AppBar(),
);
}));
}),
ExampleItem(
title: "淘宝二楼例子",
onClick: () {
Navigator.of(context).push(MaterialPageRoute(builder: (context) {
return TwoLevelExample();
}));
}),
ExampleItem(
title: "强制填满一屏",
onClick: () {
Navigator.of(context).push(MaterialPageRoute(builder: (context) {
return Scaffold(
body: ForceFullExample(),
appBar: AppBar(),
);
}));
}),
];
final List<ExampleItem> items2 = [
ExampleItem(
title: "animatedlist结合refresher",
onClick: () {
Navigator.of(context).push(MaterialPageRoute(builder: (context) {
return Scaffold(
body: AnimatedListExample(),
appBar: AppBar(),
);
}));
}),
ExampleItem(
title: "ExpansionPanelList配合使用",
onClick: () {
Navigator.of(context).push(MaterialPageRoute(builder: (context) {
return Scaffold(
appBar: AppBar(),
body: RefreshExpansionPanelList(),
);
}));
}),
ExampleItem(
title: "loadmore+draggablesheet",
onClick: () {
Navigator.of(context).push(MaterialPageRoute(builder: (context) {
return Scaffold(
appBar: AppBar(),
body: DraggableLoadingBottomSheet(),
);
}));
}),
ExampleItem(
title: "stickyHeader+StaggeredGridView",
onClick: () {
Navigator.of(context).push(MaterialPageRoute(builder: (context) {
return Scaffold(
appBar: AppBar(),
body: RefreshStaggeredAndSticky(),
);
}));
}),
ExampleItem(
title: "pageView共用SmartRefresher",
onClick: () {
Navigator.of(context).push(MaterialPageRoute(builder: (context) {
return Scaffold(
body: PageViewExample(),
appBar: AppBar(),
);
}));
}),
ExampleItem(
title: "RecordableListView",
onClick: () {
Navigator.of(context).push(MaterialPageRoute(builder: (context) {
return Scaffold(
body: ReorderableListDemo(),
appBar: AppBar(),
);
}));
}),
];
final List<ExampleItem> items3 = [
ExampleItem(
title: "简单自定义头部指示器",
onClick: () {
Navigator.of(context).push(MaterialPageRoute(builder: (context) {
return Scaffold(
body: CustomHeaderExample(),
appBar: AppBar(),
);
}));
}),
ExampleItem(
title: "LinkHeader例子",
onClick: () {
Navigator.of(context).push(MaterialPageRoute(builder: (context) {
return LinkHeaderExample();
}));
}),
ExampleItem(
title: "Shimmer指示器例子",
onClick: () {
Navigator.of(context).push(MaterialPageRoute(builder: (context) {
return Scaffold(
appBar: AppBar(),
body: ShimmerIndicatorExample(),
);
}));
}),
ExampleItem(
title: "Gif指示器例子1",
onClick: () {
Navigator.of(context).push(MaterialPageRoute(builder: (context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(),
body: GifIndicatorExample1(),
);
}));
}),
ExampleItem(
title: "footer使其于header同样表现",
onClick: () {
Navigator.of(context).push(MaterialPageRoute(builder: (context) {
return ConvertFooter();
}));
}),
];
return Column(
children: <Widget>[
Container(
child: TabBar(
controller: _tabController,
tabs: <Widget>[
Tab(
text: "使用场景",
),
Tab(
text: "配合特殊组件", //字符串
),
Tab(
text: "自定义指示器",
),
],
),
height: 50.0,
color: Colors.greenAccent,
),
Expanded(
child: TabBarView(
children: <Widget>[
ListView(children: items1),
ListView(children: items2),
ListView(children: items3)
],
controller: _tabController,
),
)
],
);
}
}
/*
* Author: Jpeng
* Email: peng8350@gmail.com
* Time: 2019-08-31 10:58
*/
// convert footer to header to use ,behaviour almost same with header
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_gifimage/flutter_gifimage.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
import '../../Item.dart';
class ConvertFooter extends StatefulWidget {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return _ConvertFooterState();
}
}
class _ConvertFooterState extends State<ConvertFooter> {
RefreshController _refreshController = RefreshController();
List<String> data = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"];
Widget buildCtn() {
return ListView.separated(
physics: ClampingScrollPhysics(),
padding: EdgeInsets.only(left: 5, right: 5),
itemBuilder: (c, i) => Item(
title: data[i],
),
separatorBuilder: (context, index) {
return Container(
height: 0.5,
color: Colors.greenAccent,
);
},
itemCount: data.length,
);
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
body: RefreshConfiguration.copyAncestor(
enableBallisticLoad: false,
footerTriggerDistance: -80,
maxUnderScrollExtent: 60,
context: context,
child: SmartRefresher(
enablePullUp: true,
footer: ClassicFooter(
loadStyle: LoadStyle.ShowWhenLoading,
),
child: buildCtn(),
onLoading: () async {
await Future.delayed(Duration(milliseconds: 1000));
for (int i = 0; i < 5; i++) data.add("1");
setState(() {});
_refreshController.loadFailed();
},
controller: _refreshController,
),
),
appBar: AppBar(),
);
}
}
/*
* Author: Jpeng
* Email: peng8350@gmail.com
* Time: 2019-07-26 18:22
*/
import 'package:flutter/widgets.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
import 'package:flutter_gifimage/flutter_gifimage.dart';
import 'package:flutter/material.dart'
hide RefreshIndicator, RefreshIndicatorState;
/*
I use my plugin to implements gif effect,this plugin can help you to controll gif easily,
see page to find about usage: (https://github.com/peng8350/flutter_gifimage)
*/
class GifHeader1 extends RefreshIndicator {
GifHeader1() : super(height: 80.0, refreshStyle: RefreshStyle.Follow);
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return GifHeader1State();
}
}
class GifHeader1State extends RefreshIndicatorState<GifHeader1>
with SingleTickerProviderStateMixin {
GifController _gifController;
@override
void initState() {
// TODO: implement initState
// init frame is 2
_gifController = GifController(
vsync: this,
value: 1,
);
super.initState();
}
@override
void onModeChange(RefreshStatus mode) {
// TODO: implement onModeChange
if (mode == RefreshStatus.refreshing) {
_gifController.repeat(
min: 0, max: 29, period: Duration(milliseconds: 500));
}
super.onModeChange(mode);
}
@override
Future<void> endRefresh() {
// TODO: implement endRefresh
_gifController.value = 30;
return _gifController.animateTo(59, duration: Duration(milliseconds: 500));
}
@override
void resetValue() {
// TODO: implement resetValue
// reset not ok , the plugin need to update lowwer
_gifController.value = 0;
super.resetValue();
}
@override
Widget buildContent(BuildContext context, RefreshStatus mode) {
// TODO: implement buildContent
return GifImage(
image: AssetImage("images/gifindicator1.gif"),
controller: _gifController,
height: 80.0,
width: 537.0,
);
}
@override
void dispose() {
// TODO: implement dispose
_gifController.dispose();
super.dispose();
}
}
class GifFooter1 extends StatefulWidget {
GifFooter1() : super();
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return _GifFooter1State();
}
}
class _GifFooter1State extends State<GifFooter1>
with SingleTickerProviderStateMixin {
GifController _gifController;
@override
void initState() {
// TODO: implement initState
// init frame is 2
_gifController = GifController(
vsync: this,
value: 1,
);
super.initState();
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return CustomFooter(
height: 80,
builder: (context, mode) {
return GifImage(
image: AssetImage("images/gifindicator1.gif"),
controller: _gifController,
height: 80.0,
width: 537.0,
);
},
loadStyle: LoadStyle.ShowWhenLoading,
onModeChange: (mode) {
if (mode == LoadStatus.loading) {
_gifController.repeat(
min: 0, max: 29, period: Duration(milliseconds: 500));
}
},
endLoading: () async {
_gifController.value = 30;
return _gifController.animateTo(59,
duration: Duration(milliseconds: 500));
},
);
}
@override
void dispose() {
// TODO: implement dispose
_gifController.dispose();
super.dispose();
}
}
class GifIndicatorExample1 extends StatefulWidget {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return GifIndicatorExample1State();
}
}
class GifIndicatorExample1State extends State<GifIndicatorExample1> {
RefreshController _controller = RefreshController();
@override
Widget build(BuildContext context) {
// TODO: implement build
return RefreshConfiguration.copyAncestor(
context: context,
// two attrs enable footer implements the effect in header default
enableBallisticLoad: false,
footerTriggerDistance: -80,
child: SmartRefresher(
controller: _controller,
enablePullUp: true,
header: GifHeader1(),
footer: GifFooter1(),
onRefresh: () async {
await Future.delayed(Duration(milliseconds: 2000));
_controller.refreshCompleted();
},
onLoading: () async {
await Future.delayed(Duration(milliseconds: 2000));
_controller.loadFailed();
},
child: ListView.builder(
itemBuilder: (c, q) => Card(),
itemCount: 50,
itemExtent: 100.0,
),
),
);
}
}
/*
* Author: Jpeng
* Email: peng8350@gmail.com
* Time: 2019-06-26 13:28
*/
/*
use to place indicator to other places,such as WeChat friend circle refresh effect
int 1.4.7 version will add it
*/
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
import '../../Item.dart';
class LinkHeaderExample extends StatefulWidget {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return _LinkHeaderExampleState();
}
}
class _LinkHeaderExampleState extends State<LinkHeaderExample> {
RefreshController _refreshController = RefreshController();
final Key linkKey = GlobalKey();
List<String> data = ["1", "2", "3", "4", "5", "6", "7", "8", "9"];
final ScrollController _scrollController = ScrollController();
bool dismissAppbar = false;
@override
void initState() {
// TODO: implement initState
_scrollController.addListener(() {
final bool ifdismissAppbar = _scrollController.offset >= 136.0;
if (dismissAppbar != ifdismissAppbar) {
if (mounted) setState(() {});
}
dismissAppbar = ifdismissAppbar;
});
super.initState();
}
@override
void dispose() {
// TODO: implement dispose
_refreshController.dispose();
_scrollController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return RefreshConfiguration.copyAncestor(
context: context,
child: Scaffold(
body: Stack(
children: <Widget>[
Stack(
children: <Widget>[
Positioned(
top: -150.0,
bottom: 0.0,
left: 0.0,
right: 0.0,
child: SmartRefresher(
controller: _refreshController,
header: LinkHeader(linkKey: linkKey),
onRefresh: () async {
await Future.delayed(Duration(milliseconds: 3000));
_refreshController.refreshCompleted();
},
child: CustomScrollView(
controller: _scrollController,
slivers: <Widget>[
SliverToBoxAdapter(
child: Image.asset(
"images/qqbg.jpg",
fit: BoxFit.fill,
height: 300.0,
),
),
SliverFixedExtentList(
delegate: SliverChildBuilderDelegate(
(c, i) => Item(
title: data[i],
),
childCount: data.length),
itemExtent: 100.0,
)
],
),
),
)
],
),
Container(
height: 64.0,
child: AppBar(
backgroundColor:
dismissAppbar ? Colors.blueAccent : Colors.transparent,
elevation: dismissAppbar ? 1.0 : 0.0,
title: SimpleLinkBar(
key: linkKey,
),
),
)
],
),
),
maxOverScrollExtent: 100,
);
}
}
class SimpleLinkBar extends StatefulWidget {
SimpleLinkBar({Key key}) : super(key: key);
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return _SimpleLinkBarState();
}
}
class _SimpleLinkBarState extends State<SimpleLinkBar>
with RefreshProcessor, SingleTickerProviderStateMixin {
RefreshStatus _status = RefreshStatus.idle;
AnimationController _animationController;
@override
void dispose() {
// TODO: implement dispose
super.dispose();
}
@override
void initState() {
// TODO: implement initState
_animationController = AnimationController(vsync: this);
super.initState();
}
@override
Future endRefresh() {
// TODO: implement endRefresh
_animationController.animateTo(0.0, duration: Duration(milliseconds: 300));
return Future.value();
}
@override
void onOffsetChange(double offset) {
// TODO: implement onOffsetChange
if (_status != RefreshStatus.refreshing)
_animationController.value = offset / 80.0;
super.onOffsetChange(offset);
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return ScaleTransition(
child: CupertinoActivityIndicator(),
scale: _animationController,
);
}
@override
void onModeChange(RefreshStatus mode) {
// TODO: implement onModeChange
super.onModeChange(mode);
_status = mode;
setState(() {});
}
}
/*
* Author: Jpeng
* Email: peng8350@gmail.com
* Time: 2019-07-08 11:05
*/
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import '../../../other/shimmer_indicator.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
class ShimmerIndicatorExample extends StatefulWidget {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return _ShimmerIndicatorExampleState();
}
}
/*
@required Color baseColor,
@required Color highlightColor,
this.period = const Duration(milliseconds: 1500),
this.direction = ShimmerDirection.ltr,
*/
class _ShimmerIndicatorExampleState extends State<ShimmerIndicatorExample> {
RefreshController _refreshController = RefreshController();
List<String> data = [
"1",
"2",
"1",
"2",
"1",
"2",
"1",
"2",
"1",
"2",
"1",
"2"
];
@override
Widget build(BuildContext context) {
// TODO: implement build
return SmartRefresher(
header: ShimmerHeader(
text: Text(
"PullToRefresh",
style: TextStyle(color: Colors.grey, fontSize: 22),
),
),
footer: ShimmerFooter(
text: Text(
"PullToRefresh",
style: TextStyle(color: Colors.grey, fontSize: 22),
),
),
controller: _refreshController,
enablePullUp: true,
child: ListView.builder(
itemCount: data.length,
itemExtent: 100.0,
itemBuilder: (c, i) => Card(),
),
onRefresh: () async {
await Future.delayed(Duration(milliseconds: 2000));
_refreshController.refreshCompleted();
},
onLoading: () async {
await Future.delayed(Duration(milliseconds: 2000));
for (int i = 0; i < 10; i++) {
data.add("1");
}
setState(() {});
_refreshController.loadComplete();
});
}
}
/*
* Author: Jpeng
* Email: peng8350@gmail.com
* Time: 2019-06-25 14:21
*/
/*
here,I use SpinKit as a
*/
import 'package:flutter/material.dart';
import '../../../other/custom_spinkit.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
/*
this example show you how to custom your indicator with CustomHeader and CustomFooter,
now I use Spinkit as a example,Custom a Spinkit Indicator with Scale effect.
notice that SpinKit I have updated some functions,expose a AnimationController for controll
the animation when refreshing. see "other/custom_spinkit.dart"
*/
class CustomHeaderExample extends StatefulWidget {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return _CustomHeaderExampleState();
}
}
class _CustomHeaderExampleState extends State<CustomHeaderExample>
with TickerProviderStateMixin {
AnimationController _anicontroller, _scaleController;
AnimationController _footerController;
RefreshController _refreshController = RefreshController();
int count = 20;
@override
void initState() {
// TODO: implement initState
_anicontroller = AnimationController(
vsync: this, duration: Duration(milliseconds: 2000));
_scaleController =
AnimationController(value: 0.0, vsync: this, upperBound: 1.0);
_footerController = AnimationController(
vsync: this, duration: Duration(milliseconds: 2000));
_refreshController.headerMode.addListener(() {
if (_refreshController.headerStatus == RefreshStatus.idle) {
_scaleController.value = 0.0;
_anicontroller.reset();
} else if (_refreshController.headerStatus == RefreshStatus.refreshing) {
_anicontroller.repeat();
}
});
super.initState();
}
@override
void dispose() {
// TODO: implement dispose
_refreshController.dispose();
_scaleController.dispose();
_footerController.dispose();
_anicontroller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return Container(
child: SmartRefresher(
enablePullUp: true,
controller: _refreshController,
onRefresh: () async {
await Future.delayed(Duration(milliseconds: 1000));
_refreshController.refreshCompleted();
},
onLoading: () async {
await Future.delayed(Duration(milliseconds: 1000));
count += 4;
setState(() {});
_refreshController.loadComplete();
},
child: ListView.builder(
itemBuilder: (c, i) => Card(),
itemExtent: 100,
itemCount: count,
),
footer: CustomFooter(
onModeChange: (mode) {
if (mode == LoadStatus.loading) {
_scaleController.value = 0.0;
_footerController.repeat();
} else {
_footerController.reset();
}
},
builder: (context, mode) {
Widget child;
switch (mode) {
case LoadStatus.failed:
child = Text("failed,click retry");
break;
case LoadStatus.noMore:
child = Text("no more data");
break;
default:
child = SpinKitFadingCircle(
size: 30.0,
animationController: _footerController,
itemBuilder: (_, int index) {
return DecoratedBox(
decoration: BoxDecoration(
color: index.isEven ? Colors.red : Colors.green,
),
);
},
);
break;
}
return Container(
height: 60,
child: Center(
child: child,
),
);
},
),
header: CustomHeader(
refreshStyle: RefreshStyle.Behind,
onOffsetChange: (offset) {
if (_refreshController.headerMode.value != RefreshStatus.refreshing)
_scaleController.value = offset / 80.0;
},
builder: (c, m) {
return Container(
child: FadeTransition(
opacity: _scaleController,
child: ScaleTransition(
child: SpinKitFadingCircle(
size: 30.0,
animationController: _anicontroller,
itemBuilder: (_, int index) {
return DecoratedBox(
decoration: BoxDecoration(
color: index.isEven ? Colors.red : Colors.green,
),
);
},
),
scale: _scaleController,
),
),
alignment: Alignment.center,
);
},
),
),
);
}
}
/*
* Author: Jpeng
* Email: peng8350@gmail.com
* Time: 2019-07-03 17:24
*/
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
/*
notice that,If your combine with DraggableScrollSheet with SmartRefresher,
It not support enablePullDown,only support enablePullUp = true.
the second, the example has StatefulBuilder,just not setState(),it will never rebuild scrollSheet
*/
class DraggableLoadingBottomSheet extends StatefulWidget {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return _DraggableLoadingBottomSheetState();
}
}
class _DraggableLoadingBottomSheetState
extends State<DraggableLoadingBottomSheet> {
RefreshController _controller = RefreshController();
List<String> items = [];
@override
void initState() {
// TODO: implement initState
super.initState();
for (int i = 0; i < 15; i++) items.add("数据");
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: const Text('DraggableScrollableSheet'),
),
body: Container(
child: RaisedButton(
onPressed: () {
showModalBottomSheet(
backgroundColor: Colors.transparent,
context: context,
builder: (c) {
return DraggableScrollableSheet(
initialChildSize: 1.0,
maxChildSize: 1.0,
minChildSize: 0.5,
builder: (BuildContext context,
ScrollController scrollController) {
return Container(
color: Colors.blue[100],
child: StatefulBuilder(
builder: (BuildContext context2, setter) {
return SmartRefresher(
child: ListView.separated(
controller: scrollController,
separatorBuilder: (c, i) => Divider(),
itemBuilder: (_, e) => Container(
child:
Center(child: Text("菜单" + e.toString())),
height: 40.0,
),
physics: ClampingScrollPhysics(),
itemCount: items.length,
),
controller: _controller,
onLoading: () async {
await Future.delayed(
Duration(milliseconds: 1000));
_controller.loadComplete();
for (int i = 0; i < 15; i++) {
items.add("1");
}
setter(() {});
},
enablePullUp: true,
enablePullDown: false,
);
},
),
);
},
);
});
},
child: Text("点击打开滑动BottomSheet"),
),
),
);
}
}
/*
* Author: Jpeng
* Email: peng8350@gmail.com
* Time: 2019-07-01 20:48
*/
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
class RefreshExpansionPanelList extends StatefulWidget {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return RefreshExpansionPanelListState();
}
}
class RefreshExpansionPanelListState extends State<RefreshExpansionPanelList> {
List<Item> _data = generateItems(10);
RefreshController _controller = RefreshController();
@override
Widget build(BuildContext context) {
return SmartRefresher(
controller: _controller,
child: ListView(
shrinkWrap: true,
children: <Widget>[_buildPanel()],
),
enablePullUp: true,
);
}
Widget _buildPanel() {
return ExpansionPanelList(
expansionCallback: (int index, bool isExpanded) {
if (mounted)
setState(() {
_data[index].isExpanded = !isExpanded;
});
},
children: _data.map<ExpansionPanel>((Item item) {
return ExpansionPanel(
headerBuilder: (BuildContext context, bool isExpanded) {
return ListTile(
title: Text(item.headerValue),
);
},
body: ListTile(
title: Text(item.headerValue),
subtitle: Text('To delete this panel, tap the trash can icon'),
trailing: Icon(Icons.delete),
onTap: () {
if (mounted)
setState(() {
_data.removeWhere((currentItem) => item == currentItem);
});
}),
isExpanded: item.isExpanded,
);
}).toList(),
);
}
}
List<Item> generateItems(int numberOfItems) {
return List.generate(numberOfItems, (int index) {
return Item(
headerValue: 'Panel $index',
expandedValue: 'This is item number $index',
);
});
}
// stores ExpansionPanel state information
class Item {
Item({
this.expandedValue,
this.headerValue,
this.isExpanded = false,
});
String expandedValue;
String headerValue;
bool isExpanded;
}
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
class AnimatedListExample extends StatefulWidget {
@override
_AnimatedListExampleState createState() => new _AnimatedListExampleState();
}
class _AnimatedListExampleState extends State<AnimatedListExample> {
final GlobalKey<SliverAnimatedListState> _listKey =
new GlobalKey<SliverAnimatedListState>();
ListModel<int> _list;
int _selectedItem;
int _nextItem; // The next item inserted when the user presses the '+' button.
@override
void initState() {
super.initState();
_list = new ListModel<int>(
listKey: _listKey,
initialItems: <int>[0, 1, 2],
removedItemBuilder: _buildRemovedItem,
);
_nextItem = 3;
}
// Used to build list items that haven't been removed.
Widget _buildItem(
BuildContext context, int index, Animation<double> animation) {
return new CardItem(
animation: animation,
item: _list[index],
selected: _selectedItem == _list[index],
onTap: () {
if (mounted)
setState(() {
_selectedItem = _selectedItem == _list[index] ? null : _list[index];
});
},
);
}
// Used to build an item after it has been removed from the list. This method is
// needed because a removed item remains visible until its animation has
// completed (even though it's gone as far this ListModel is concerned).
// The widget will be used by the [SliverAnimatedListState.removeItem] method's
// [SliverAnimatedListRemovedItemBuilder] parameter.
Widget _buildRemovedItem(
int item, BuildContext context, Animation<double> animation) {
return new CardItem(
animation: animation,
item: item,
selected: false,
// No gesture detector here: we don't want removed items to be interactive.
);
}
// Insert the "next item" into the list model.
void _insert() {
for (int i = 0; i < 5; i++) {
final int index =
_selectedItem == null ? _list.length : _list.indexOf(_selectedItem);
_list.insert(index, _nextItem++);
}
}
// Remove the selected item from the list model.
void _remove() {
if (_selectedItem != null) {
_list.removeAt(_list.indexOf(_selectedItem));
if (mounted)
setState(() {
_selectedItem = null;
});
}
}
RefreshController _refreshController = RefreshController();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: new AppBar(
title: const Text('SliverAnimatedList'),
actions: <Widget>[
new IconButton(
icon: const Icon(Icons.add_circle),
onPressed: _insert,
tooltip: 'insert a new item',
),
new IconButton(
icon: const Icon(Icons.remove_circle),
onPressed: _remove,
tooltip: 'remove the selected item',
),
],
),
body: SmartRefresher(
child: CustomScrollView(
slivers: <Widget>[
SliverAnimatedList(
key: _listKey,
initialItemCount: _list.length,
itemBuilder: _buildItem,
)
],
),
onRefresh: () async {
await Future.delayed(Duration(milliseconds: 500));
_list.insert(0, 0);
_refreshController.refreshFailed();
},
onLoading: () async {
await Future.delayed(Duration(milliseconds: 500));
_list.insert(_list.length, _list.length);
_refreshController.loadComplete();
},
enablePullUp: true,
controller: _refreshController,
),
);
}
}
/// Keeps a Dart List in sync with an SliverAnimatedList.
///
/// The [insert] and [removeAt] methods apply to both the internal list and the
/// animated list that belongs to [listKey].
///
/// This class only exposes as much of the Dart List API as is needed by the
/// sample app. More list methods are easily added, however methods that mutate the
/// list must make the same changes to the animated list in terms of
/// [SliverAnimatedListState.insertItem] and [SliverAnimatedList.removeItem].
class ListModel<E> {
ListModel({
@required this.listKey,
@required this.removedItemBuilder,
Iterable<E> initialItems,
}) : assert(listKey != null),
assert(removedItemBuilder != null),
_items = new List<E>.from(initialItems ?? <E>[]);
final GlobalKey<SliverAnimatedListState> listKey;
final dynamic removedItemBuilder;
final List<E> _items;
SliverAnimatedListState get _sliverAnimatedList => listKey.currentState;
void insert(int index, E item) {
_items.insert(index, item);
_sliverAnimatedList.insertItem(index);
}
E removeAt(int index) {
final E removedItem = _items.removeAt(index);
if (removedItem != null) {
_sliverAnimatedList.removeItem(index,
(BuildContext context, Animation<double> animation) {
return removedItemBuilder(removedItem, context, animation);
});
}
return removedItem;
}
int get length => _items.length;
E operator [](int index) => _items[index];
int indexOf(E item) => _items.indexOf(item);
}
/// Displays its integer item as 'item N' on a Card whose color is based on
/// the item's value. The text is displayed in bright green if selected is true.
/// This widget's height is based on the animation parameter, it varies
/// from 0 to 128 as the animation varies from 0.0 to 1.0.
class CardItem extends StatelessWidget {
const CardItem(
{Key key,
@required this.animation,
this.onTap,
@required this.item,
this.selected: false})
: assert(animation != null),
assert(item != null && item >= 0),
assert(selected != null),
super(key: key);
final Animation<double> animation;
final VoidCallback onTap;
final int item;
final bool selected;
@override
Widget build(BuildContext context) {
TextStyle textStyle = Theme.of(context).textTheme.bodyText1;
if (selected)
textStyle = textStyle.copyWith(color: Colors.lightGreenAccent[400]);
return new Padding(
padding: const EdgeInsets.all(2.0),
child: new SizeTransition(
axis: Axis.vertical,
sizeFactor: animation,
child: new GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: onTap,
child: new SizedBox(
height: 128.0,
child: new Card(
color: Colors.primaries[item % Colors.primaries.length],
child: new Center(
child: new Text('Item $item', style: textStyle),
),
),
),
),
),
);
}
}
/*
* Author: Jpeng
* Email: peng8350@gmail.com
* Time: 2019-06-24 17:14
*/
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
/*
this example will show you how to use vertical PageView as child in SmartRefresher(vertical refresh)
*/
class PageViewExample extends StatefulWidget {
PageViewExample({Key key}) : super(key: key);
@override
PageViewExampleState createState() => PageViewExampleState();
}
class PageViewExampleState extends State<PageViewExample>
with TickerProviderStateMixin {
RefreshController _refreshController;
int _lastReportedPage = 0;
List<Widget> data = [];
final PageController _pageController = PageController();
void enterRefresh() {
_refreshController.requestLoading();
}
@override
void initState() {
// TODO: implement initState
_refreshController = RefreshController(initialRefresh: true);
super.initState();
}
@override
void dispose() {
// TODO: implement dispose
_refreshController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return NotificationListener(
onNotification: (ScrollNotification notification) {
if (notification.depth == 0 &&
notification is ScrollUpdateNotification) {
final PageMetrics metrics = notification.metrics as PageMetrics;
final int currentPage = metrics.page.round();
if (currentPage != _lastReportedPage) {
_lastReportedPage = currentPage;
// this will callback onPageChange()
print("onPageChange + $currentPage");
}
}
return false;
},
child: SmartRefresher(
enablePullUp: true,
enablePullDown: true,
footer: ClassicFooter(
loadStyle: LoadStyle.ShowWhenLoading,
),
controller: _refreshController,
header: MaterialClassicHeader(),
onRefresh: () async {
print("onRefresh");
await Future.delayed(const Duration(milliseconds: 4000));
if (mounted) setState(() {});
_refreshController.refreshFailed();
},
child: CustomScrollView(
physics: PageScrollPhysics(),
controller: _pageController,
slivers: <Widget>[
SliverFillViewport(
delegate: SliverChildListDelegate([
Center(child: Text("第一页")),
Center(child: Text("第二页")),
Center(child: Text("第三页")),
Center(child: Text("第四页"))
]))
],
),
onLoading: () {
print("onload");
Future.delayed(const Duration(milliseconds: 2000)).then((val) {
_refreshController.loadComplete();
});
},
),
);
}
}
/*
* Author: Jpeng
* Email: peng8350@gmail.com
* Time: 2019-07-01 22:44
*/
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:example/other/refresh_recordable_listview.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
enum _ReorderableListType {
/// A list tile that contains a [CircleAvatar].
horizontalAvatar,
/// A list tile that contains a [CircleAvatar].
verticalAvatar,
/// A list tile that contains three lines of text and a checkbox.
threeLine,
}
class ReorderableListDemo extends StatefulWidget {
const ReorderableListDemo({Key key}) : super(key: key);
static const String routeName = '/material/reorderable-list';
@override
_ListDemoState createState() => _ListDemoState();
}
class _ListItem {
_ListItem(this.value, this.checkState);
final String value;
bool checkState;
}
class _ListDemoState extends State<ReorderableListDemo> {
static final GlobalKey<ScaffoldState> scaffoldKey =
GlobalKey<ScaffoldState>();
PersistentBottomSheetController<void> _bottomSheet;
RefreshController _refreshController = RefreshController();
_ReorderableListType _itemType = _ReorderableListType.threeLine;
bool _reverse = false;
bool _reverseSort = false;
final List<_ListItem> _items = <String>[
'A',
'B',
'C',
'D',
'E',
'F',
'G',
'H',
'I',
'J',
'K',
'L',
'M',
'N',
].map<_ListItem>((String item) => _ListItem(item, false)).toList();
void changeItemType(_ReorderableListType type) {
if (mounted)
setState(() {
_itemType = type;
});
// Rebuild the bottom sheet to reflect the selected list view.
if (mounted)
_bottomSheet?.setState(() {
// Trigger a rebuild.
});
// Close the bottom sheet to give the user a clear view of the list.
_bottomSheet?.close();
}
void changeReverse(bool newValue) {
if (mounted)
setState(() {
_reverse = newValue;
});
// Rebuild the bottom sheet to reflect the selected list view.
if (mounted)
_bottomSheet?.setState(() {
// Trigger a rebuild.
});
// Close the bottom sheet to give the user a clear view of the list.
_bottomSheet?.close();
}
void _showConfigurationSheet() {
if (mounted)
setState(() {
_bottomSheet = scaffoldKey.currentState
.showBottomSheet<void>((BuildContext bottomSheetContext) {
return DecoratedBox(
decoration: const BoxDecoration(
border: Border(top: BorderSide(color: Colors.black26)),
),
child: ListView(
shrinkWrap: true,
primary: false,
children: <Widget>[
CheckboxListTile(
dense: true,
title: const Text('Reverse'),
value: _reverse,
onChanged: changeReverse,
),
RadioListTile<_ReorderableListType>(
dense: true,
title: const Text('Horizontal Avatars'),
value: _ReorderableListType.horizontalAvatar,
groupValue: _itemType,
onChanged: changeItemType,
),
RadioListTile<_ReorderableListType>(
dense: true,
title: const Text('Vertical Avatars'),
value: _ReorderableListType.verticalAvatar,
groupValue: _itemType,
onChanged: changeItemType,
),
RadioListTile<_ReorderableListType>(
dense: true,
title: const Text('Three-line'),
value: _ReorderableListType.threeLine,
groupValue: _itemType,
onChanged: changeItemType,
),
],
),
);
});
// Garbage collect the bottom sheet when it closes.
_bottomSheet.closed.whenComplete(() {
if (mounted) {
setState(() {
_bottomSheet = null;
});
}
});
});
}
Widget buildListTile(_ListItem item) {
const Widget secondary = Text(
'Even more additional list item information appears on line three.',
);
Widget listTile;
switch (_itemType) {
case _ReorderableListType.threeLine:
listTile = CheckboxListTile(
key: Key(item.value),
isThreeLine: true,
value: item.checkState ?? false,
onChanged: (bool newValue) {
if (mounted)
setState(() {
item.checkState = newValue;
});
},
title: Text('This item represents ${item.value}.'),
subtitle: secondary,
secondary: const Icon(Icons.drag_handle),
);
break;
case _ReorderableListType.horizontalAvatar:
case _ReorderableListType.verticalAvatar:
listTile = Container(
key: Key(item.value),
height: 100.0,
width: 100.0,
child: CircleAvatar(
child: Text(item.value),
backgroundColor: Colors.green,
),
);
break;
}
return listTile;
}
void _onReorder(int oldIndex, int newIndex) {
if (mounted)
setState(() {
if (newIndex > oldIndex) {
newIndex -= 1;
}
final _ListItem item = _items.removeAt(oldIndex);
_items.insert(newIndex, item);
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
key: scaffoldKey,
appBar: AppBar(
title: const Text('Reorderable list'),
actions: <Widget>[
IconButton(
icon: const Icon(Icons.sort_by_alpha),
tooltip: 'Sort',
onPressed: () {
if (mounted)
setState(() {
_reverseSort = !_reverseSort;
_items.sort((_ListItem a, _ListItem b) => _reverseSort
? b.value.compareTo(a.value)
: a.value.compareTo(b.value));
});
},
),
IconButton(
icon: Icon(
Theme.of(context).platform == TargetPlatform.iOS
? Icons.more_horiz
: Icons.more_vert,
),
tooltip: 'Show menu',
onPressed: _bottomSheet == null ? _showConfigurationSheet : null,
),
],
),
body: Scrollbar(
child: RefreshReorderableListView(
header: _itemType != _ReorderableListType.threeLine
? Padding(
padding: const EdgeInsets.all(8.0),
child: Text('Header of the list',
style: Theme.of(context).textTheme.headline1))
: null,
onReorder: _onReorder,
reverse: _reverse,
scrollDirection: _itemType == _ReorderableListType.horizontalAvatar
? Axis.horizontal
: Axis.vertical,
padding: const EdgeInsets.symmetric(vertical: 8.0),
children: _items.map<Widget>(buildListTile).toList(),
refreshController: _refreshController,
),
),
);
}
}
/*
* Author: Jpeng
* Email: peng8350@gmail.com
* Time: 2019-07-23 21:09
*/
import 'package:flutter/material.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'package:flutter_sticky_header/flutter_sticky_header.dart';
/*
use refresh with StaggeredGridView or StickyHeader
the two plugins from letsar
author page : https://github.com/letsar
*/
class RefreshStaggeredAndSticky extends StatefulWidget {
RefreshStaggeredAndSticky({Key key}) : super(key: key);
@override
RefreshStaggeredAndStickyState createState() =>
RefreshStaggeredAndStickyState();
}
class RefreshStaggeredAndStickyState extends State<RefreshStaggeredAndSticky>
with TickerProviderStateMixin {
RefreshController _refreshController;
List<Widget> data = [];
int length = 10;
void _getDatas() {
data.add(Row(
children: <Widget>[
FlatButton(
onPressed: () {
_refreshController.requestRefresh();
},
child: Text("请求刷新")),
FlatButton(
onPressed: () {
_refreshController.requestLoading();
},
child: Text("请求加载数据"))
],
));
for (int i = 0; i < 13; i++) {
data.add(GestureDetector(
child: Container(
color: Color.fromARGB(255, 250, 250, 250),
child: Card(
margin:
EdgeInsets.only(left: 10.0, right: 10.0, top: 5.0, bottom: 5.0),
child: Center(
child: Text('Data $i'),
),
),
),
onTap: () {
_refreshController.requestRefresh();
},
));
}
}
void enterRefresh() {
_refreshController.requestLoading();
}
@override
void initState() {
// TODO: implement initState
_getDatas();
_refreshController = RefreshController(initialRefresh: true);
super.initState();
}
@override
void dispose() {
// TODO: implement dispose
_refreshController.dispose();
super.dispose();
}
List<bool> expand = [false, false, false, false, false, false, false, false];
@override
Widget build(BuildContext context) {
List<Widget> slivers = [];
for (int i = 0; i < expand.length; i++) {
slivers.add(SliverStickyHeader(
header: GestureDetector(
child: new Container(
height: 60.0,
color: Colors.lightBlue,
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: new Text(
'Header #$i',
style: const TextStyle(color: Colors.white),
),
),
onTap: () {
expand[i] = !expand[i];
setState(() {});
},
),
sliver: expand[i]
? new SliverList(
delegate: new SliverChildBuilderDelegate(
(context, i) => new ListTile(
leading: new CircleAvatar(
child: new Text('0'),
),
title: new Text('List tile #$i'),
),
childCount: 4,
),
)
: null,
));
}
slivers.add(SliverStaggeredGrid.countBuilder(
crossAxisCount: 4,
itemCount: length,
itemBuilder: (BuildContext context, int index) => new Container(
color: Colors.green,
child: new Center(
child: new CircleAvatar(
backgroundColor: Colors.white,
child: new Text('$index'),
),
)),
staggeredTileBuilder: (int index) =>
new StaggeredTile.count(2, index.isEven ? 2 : 1),
mainAxisSpacing: 4.0,
crossAxisSpacing: 4.0,
));
return LayoutBuilder(
builder: (i, c) {
return SmartRefresher(
enablePullUp: true,
enablePullDown: true,
controller: _refreshController,
header: MaterialClassicHeader(),
onRefresh: () async {
print("onRefresh");
await Future.delayed(const Duration(milliseconds: 4000));
if (mounted) setState(() {});
_refreshController.refreshFailed();
},
child: CustomScrollView(
slivers: slivers,
),
onLoading: () {
print("onload");
Future.delayed(const Duration(milliseconds: 2000)).then((val) {
length += 10;
if (mounted) setState(() {});
_refreshController.loadComplete();
});
},
);
},
);
}
}
import 'dart:async';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart' hide RefreshIndicator;
/*
NestedScrollView+SmartRefresher,implements such effect ,refreshing under the SliverAppbar,
see the issue #98.
But NestedScrollView cannot compatible with overScroll,so it may have a bug when Dragging down then dragging up quickly.
this bug I have no idea how to fix this,only waiting for flutter fix this bug.
*/
class NestedRefresh extends StatefulWidget {
NestedRefresh({Key key}) : super(key: key);
@override
NestedRefreshState createState() => NestedRefreshState();
}
class NestedRefreshState extends State<NestedRefresh>
with SingleTickerProviderStateMixin {
// RefreshMode refreshing = RefreshMode.idle;
// LoadMode loading = LoadMode.idle;
RefreshController _refreshController;
List<Widget> data = [];
void _getDatas() {
for (int i = 0; i < 4; i++) {
data.add(Container(
color: Colors.greenAccent,
margin: EdgeInsets.only(left: 10.0, right: 10.0, top: 5.0, bottom: 5.0),
child: Center(
child: Text('Data $i'),
),
));
}
}
void enterRefresh() {
_refreshController.requestRefresh();
}
@override
void initState() {
// TODO: implement initState
_getDatas();
_refreshController = RefreshController(initialRefresh: true);
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: DefaultTabController(
length: 4,
child: NestedScrollView(
headerSliverBuilder: (c, s) => [
SliverAppBar(
expandedHeight: 206.0,
pinned: true,
floating: true,
flexibleSpace: FlexibleSpaceBar(
centerTitle: true,
background: Image.network(
"https://images.unsplash.com/photo-1541701494587-cb58502866ab?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=0c21b1ac3066ae4d354a3b2e0064c8be&auto=format&fit=crop&w=500&q=60",
fit: BoxFit.cover,
)),
bottom: TabBar(
tabs: <Widget>[
Tab(
child: Text("tab1"),
),
Tab(
child: Text("tab2"),
),
Tab(
child: Text("tab3"),
),
Tab(
child: Text("tab4"),
)
],
),
),
],
body: TabBarView(
children: <Widget>[
RefreshListView(),
RefreshListView(),
RefreshListView(),
RefreshListView()
],
)),
),
);
}
}
class RefreshListView extends StatefulWidget {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return _RefreshListViewState();
}
}
class _RefreshListViewState extends State<RefreshListView> {
List<String> items = ["1", "2", "3", "4", "5", "6", "7", "8"];
RefreshController _refreshController =
RefreshController(initialRefresh: true);
void _onRefresh() async {
// monitor network fetch
await Future.delayed(Duration(milliseconds: 1000));
// if failed,use refreshFailed()
_refreshController.refreshCompleted();
}
void _onLoading() async {
// monitor network fetch
await Future.delayed(Duration(milliseconds: 250));
// if failed,use loadFailed(),if no data return,use LoadNodata()
items.add((items.length + 1).toString());
if (mounted) setState(() {});
_refreshController.loadComplete();
}
@override
Widget build(BuildContext context) {
return SmartRefresher(
enablePullDown: true,
enablePullUp: true,
header: WaterDropHeader(),
footer: CustomFooter(
builder: (BuildContext context, LoadStatus mode) {
Widget body;
if (mode == LoadStatus.idle) {
body = Text("pull up load");
} else if (mode == LoadStatus.loading) {
body = CupertinoActivityIndicator();
} else if (mode == LoadStatus.failed) {
body = Text("Load Failed!Click retry!");
} else if (mode == LoadStatus.canLoading) {
body = Text("Release to Load more");
} else {
body = Text("No more Data");
}
return Container(
height: 55.0,
child: Center(child: body),
);
},
),
controller: _refreshController,
onRefresh: _onRefresh,
onLoading: _onLoading,
child: ListView.builder(
physics: BouncingScrollPhysics(),
itemBuilder: (c, i) => Card(child: Center(child: Text(items[i]))),
itemExtent: 100.0,
itemCount: items.length,
),
);
}
// don't forget to dispose refreshController
@override
void dispose() {
// TODO: implement dispose
_refreshController.dispose();
super.dispose();
}
}
/*
* Author: Jpeng
* Email: peng8350@gmail.com
* Time: 2019-06-26 11:36
*/
/*
the basic usage
*/
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_swiper/flutter_swiper.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
import '../../Item.dart';
/*
the most common usage,
child wrap ListView,GridView,CustomView,Widget,
RefreshConfiguration is a global setting,just like theme,All refreshers under the RefreshConfiguration subtree will refer to its properties,
in this example,I gave RefreshConfiguration a property headerBuilder,The default header indicator for the four refreshers is it.
If you use almost the same page indicator, using Refresh Configuration can greatly reduce the complexity of your work.
*/
class BasicExample extends StatefulWidget {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return _BasicExampleState();
}
}
class _BasicExampleState extends State<BasicExample>
with SingleTickerProviderStateMixin {
// int pageIndex = 0;
List<String> data1 = [], data2 = [], data3 = [];
TabController _tabController;
@override
void initState() {
// TODO: implement initState
_tabController = TabController(length: 6, vsync: this);
_tabController.addListener(() {});
for (int i = 0; i < 10; i++) {
data1.add("Item $i");
}
for (int i = 0; i < 10; i++) {
data2.add("Item $i");
}
for (int i = 0; i < 10; i++) {
data3.add("Item $i");
}
super.initState();
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return RefreshConfiguration.copyAncestor(
enableLoadingWhenFailed: true,
context: context,
child: Scaffold(
appBar: AppBar(
bottom: TabBar(
isScrollable: true,
controller: _tabController,
tabs: <Widget>[
Tab(
text: "ListView",
),
Tab(
text: "GridView",
),
Tab(
text: "非滚动组件",
),
Tab(
text: "SliverAppBar+list",
),
Tab(
text: "GridView+ListView",
),
Tab(
text: "水平组件+listView",
),
],
),
),
body: TabBarView(
physics: NeverScrollableScrollPhysics(),
controller: _tabController,
children: <Widget>[
Scrollbar(
child: OnlyListView(),
),
Scrollbar(
child: OnlyGridView(),
),
Scrollbar(
child: NoScrollable(),
),
Scrollbar(
child: SliverAppBarWithList(),
),
Scrollbar(
child: GridAndList(),
),
Scrollbar(
child: SwiperAndList(),
)
],
),
),
headerBuilder: () => WaterDropMaterialHeader(
backgroundColor: Theme.of(context).primaryColor,
),
footerTriggerDistance: 30.0,
);
}
}
//only ListView
class OnlyListView extends StatefulWidget {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return _OnlyListViewState();
}
}
class _OnlyListViewState extends State<OnlyListView> {
RefreshController _refreshController =
RefreshController(initialRefresh: false);
List<String> data = ["1", "2", "3", "4", "5", "6", "7", "8", "9"];
GlobalKey _contentKey = GlobalKey();
GlobalKey _refresherKey = GlobalKey();
Widget buildCtn() {
return ListView.separated(
key: _contentKey,
reverse: true,
padding: EdgeInsets.only(left: 5, right: 5),
itemBuilder: (c, i) => Item(
title: data[i],
),
separatorBuilder: (context, index) {
return Container(
height: 0.5,
color: Colors.greenAccent,
);
},
itemCount: data.length,
);
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return SmartRefresher(
key: _refresherKey,
controller: _refreshController,
enablePullUp: true,
child: buildCtn(),
physics: BouncingScrollPhysics(),
footer: ClassicFooter(
loadStyle: LoadStyle.ShowWhenLoading,
completeDuration: Duration(milliseconds: 500),
),
onRefresh: () async {
//monitor fetch data from network
await Future.delayed(Duration(milliseconds: 1000));
for (int i = 0; i < 10; i++) {
data.add("Item $i");
}
if (mounted) setState(() {});
_refreshController.refreshCompleted();
/*
if(failed){
_refreshController.refreshFailed();
}
*/
},
onLoading: () async {
//monitor fetch data from network
await Future.delayed(Duration(milliseconds: 180));
// for (int i = 0; i < 10; i++) {
// data.add("Item $i");
// }
if (mounted) setState(() {});
_refreshController.loadFailed();
},
);
}
}
//only GridView
class OnlyGridView extends StatefulWidget {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return _OnlyGridViewState();
}
}
class _OnlyGridViewState extends State<OnlyGridView> {
RefreshController _refreshController =
RefreshController(initialRefresh: false);
List<String> data = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"];
Widget buildCtn() {
return GridView.builder(
physics: ClampingScrollPhysics(),
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
itemBuilder: (c, i) => Item(
title: data[i],
),
itemCount: data.length,
);
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return SmartRefresher(
controller: _refreshController,
enablePullUp: true,
child: buildCtn(),
header: ClassicHeader(),
onRefresh: () async {
//monitor fetch data from network
await Future.delayed(Duration(milliseconds: 1000));
if (data.length == 0) {
for (int i = 0; i < 10; i++) {
data.add("Item $i");
}
}
if (mounted) setState(() {});
_refreshController.refreshCompleted();
/*
if(failed){
_refreshController.refreshFailed();
}
*/
},
onLoading: () async {
//monitor fetch data from network
await Future.delayed(Duration(milliseconds: 1000));
for (int i = 0; i < 10; i++) {
data.add("Item $i");
}
// pageIndex++;
if (mounted) setState(() {});
_refreshController.loadComplete();
},
);
}
}
// No vertical Scrollable (like SingleChildScrollView)
// if child is not extends CustomScrollView,this will add it to SliverToBoxAdapter
// mostly for emptyView
class NoScrollable extends StatefulWidget {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return _NoScrollableState();
}
}
class _NoScrollableState extends State<NoScrollable> {
RefreshController _refreshController =
RefreshController(initialRefresh: false);
List<String> data = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"];
Widget buildCtn() {
return Container(
height: 1000.0,
child: Column(
children: <Widget>[
Container(
color: Colors.redAccent,
height: 200.0,
),
Text("标题"),
Container(
color: Colors.redAccent,
height: 200.0,
),
Text("标题"),
Container(
color: Colors.redAccent,
height: 200.0,
),
Text("标题"),
Container(
color: Colors.redAccent,
height: 200.0,
),
Text("标题"),
],
));
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return SmartRefresher(
controller: _refreshController,
enablePullUp: true,
child: buildCtn(),
header: WaterDropHeader(),
onRefresh: () async {
//monitor fetch data from network
await Future.delayed(Duration(milliseconds: 1000));
if (data.length == 0) {
for (int i = 0; i < 10; i++) {
data.add("Item $i");
}
}
if (mounted) setState(() {});
_refreshController.refreshCompleted();
/*
if(failed){
_refreshController.refreshFailed();
}
*/
},
onLoading: () async {
//monitor fetch data from network
await Future.delayed(Duration(milliseconds: 1000));
for (int i = 0; i < 10; i++) {
data.add("Item $i");
}
// pageIndex++;
if (mounted) setState(() {});
_refreshController.loadComplete();
},
);
}
}
//SliverAppBar + ListView
class SliverAppBarWithList extends StatefulWidget {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return _SliverAppBarWithListState();
}
}
class _SliverAppBarWithListState extends State<SliverAppBarWithList> {
RefreshController _refreshController =
RefreshController(initialRefresh: false);
List<String> data = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"];
Widget buildCtn() {
return CustomScrollView(
slivers: <Widget>[
SliverToBoxAdapter(),
SliverAppBar(
title: Text("SliverAppBar"),
expandedHeight: 100.0,
),
SliverList(
delegate: SliverChildBuilderDelegate(
(c, i) => Item(title: data[i]),
childCount: data.length,
),
)
],
);
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return SmartRefresher(
controller: _refreshController,
enablePullUp: true,
child: buildCtn(),
header: WaterDropHeader(),
onRefresh: () async {
//monitor fetch data from network
await Future.delayed(Duration(milliseconds: 1000));
if (data.length == 0) {
for (int i = 0; i < 10; i++) {
data.add("Item $i");
}
}
if (mounted) setState(() {});
_refreshController.refreshCompleted();
/*
if(failed){
_refreshController.refreshFailed();
}
*/
},
onLoading: () async {
//monitor fetch data from network
await Future.delayed(Duration(milliseconds: 1000));
for (int i = 0; i < 10; i++) {
data.add("Item $i");
}
// pageIndex++;
if (mounted) setState(() {});
_refreshController.loadComplete();
},
);
}
}
// GridView + ListView
class GridAndList extends StatefulWidget {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return _GridAndListState();
}
}
class _GridAndListState extends State<GridAndList> {
RefreshController _refreshController =
RefreshController(initialRefresh: false);
List<String> data = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"];
Widget buildCtn() {
return CustomScrollView(
slivers: <Widget>[
SliverGrid(
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3),
delegate: SliverChildBuilderDelegate(
(c, i) => Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[Icon(Icons.storage), Text("菜单标题")],
),
childCount: 6,
),
),
SliverList(
delegate: SliverChildBuilderDelegate(
(c, i) => Item(title: data[i]),
childCount: data.length,
),
)
],
);
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return SmartRefresher(
controller: _refreshController,
enablePullUp: true,
child: buildCtn(),
header: WaterDropHeader(),
onRefresh: () async {
//monitor fetch data from network
await Future.delayed(Duration(milliseconds: 1000));
if (data.length == 0) {
for (int i = 0; i < 10; i++) {
data.add("Item $i");
}
}
if (mounted) setState(() {});
_refreshController.refreshCompleted();
/*
if(failed){
_refreshController.refreshFailed();
}
*/
},
onLoading: () async {
//monitor fetch data from network
await Future.delayed(Duration(milliseconds: 1000));
for (int i = 0; i < 10; i++) {
data.add("Item $i");
}
// pageIndex++;
if (mounted) setState(() {});
_refreshController.loadComplete();
},
);
}
}
// 水平组件(例子:轮播图)+List
class SwiperAndList extends StatefulWidget {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return _SwiperAndListState();
}
}
class _SwiperAndListState extends State<SwiperAndList> {
RefreshController _refreshController =
RefreshController(initialRefresh: false);
List<String> data = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"];
Widget buildCtn() {
return CustomScrollView(
slivers: <Widget>[
SliverToBoxAdapter(
child: Swiper(
layout: SwiperLayout.CUSTOM,
customLayoutOption:
new CustomLayoutOption(startIndex: -1, stateCount: 3)
.addRotate([-45.0 / 180, 0.0, 45.0 / 180]).addTranslate([
new Offset(-370.0, -40.0),
new Offset(0.0, 0.0),
new Offset(370.0, -40.0)
]),
itemWidth: double.infinity,
itemHeight: 200,
itemBuilder: (context, index) {
return Container(
height: 200,
child: new Image.asset(
"images/empty.png",
fit: BoxFit.cover,
),
);
},
itemCount: 10),
),
SliverList(
delegate: SliverChildBuilderDelegate(
(c, i) => Item(title: data[i]),
childCount: data.length,
),
)
],
);
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return SmartRefresher(
controller: _refreshController,
enablePullUp: true,
child: buildCtn(),
header: WaterDropHeader(),
onRefresh: () async {
//monitor fetch data from network
await Future.delayed(Duration(milliseconds: 1000));
if (data.length == 0) {
for (int i = 0; i < 10; i++) {
data.add("Item $i");
}
}
if (mounted) setState(() {});
_refreshController.refreshCompleted();
/*
if(failed){
_refreshController.refreshFailed();
}
*/
},
onLoading: () async {
//monitor fetch data from network
await Future.delayed(Duration(milliseconds: 1000));
for (int i = 0; i < 10; i++) {
data.add("Item $i");
}
// pageIndex++;
if (mounted) setState(() {});
_refreshController.loadComplete();
},
);
}
}
/*
* Author: Jpeng
* Email: peng8350@gmail.com
* Time: 2019-06-24 17:13
*/
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
/*
when listView have no data,sometime we should return a view that indicate empty state
there are two ways to do ,see follow
*/
class RefreshWithEmptyView extends StatefulWidget {
RefreshWithEmptyView();
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return _RefreshWithEmptyViewState();
}
}
class _RefreshWithEmptyViewState extends State<RefreshWithEmptyView> {
List<String> data = [];
RefreshController _refreshController =
RefreshController(initialRefresh: false);
Widget buildEmpty() {
// there are two ways
// this way is more converient,but it doesn't reference ListView some attribute
// If you don't need some attribute like physics,cacheExtent,just default
// you can return emptyWidget directly,else return ListView
// from 1.5.2,you needn't compute the height by LayoutBuilder,If your boxConstaints is double.infite,
// SmartRefresher can convert the height to the viewport mainExtent
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Image.asset(
"images/empty1.png",
fit: BoxFit.cover,
),
Text("没数据,请下拉刷新")
],
);
/* second way
return ListView(
children: [
Image.asset(
"images/empty.png",
fit: BoxFit.cover,
)
],
physics: BouncingScrollPhysics(),
cacheExtent: 100.0,
);
*/
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return SmartRefresher(
controller: _refreshController,
enablePullUp: data.length != 0,
enablePullDown: true,
onRefresh: () async {
await Future.delayed(const Duration(milliseconds: 2000));
if (mounted)
setState(() {
data.add("new");
});
_refreshController.refreshCompleted();
},
child: data.length == 0
? buildEmpty()
: ListView.builder(
itemBuilder: (c, i) => Text(data[i]),
itemCount: data.length,
itemExtent: 100.0,
),
);
}
}
/*
* Author: Jpeng
* Email: peng8350@gmail.com
* Time: 2019-10-17 20:30
*/
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter/widgets.dart' as prefix0;
import 'package:pull_to_refresh/pull_to_refresh.dart';
/// This example aim to fix the viewport not enough one page,there must be exist some problems that you don't hope that.
/// relevant issue:#183,#166*
// A Sliver for Expanding empty space
class SliverFillEmptySpace extends SingleChildRenderObjectWidget {
/// Creates a sliver that contains a single box widget.
SliverFillEmptySpace({
Key key,
}) : super(key: key, child: Container());
@override
RenderSliverFillEmptySpace createRenderObject(BuildContext context) =>
RenderSliverFillEmptySpace();
}
class RenderSliverFillEmptySpace extends RenderSliverSingleBoxAdapter {
/// Creates a [RenderSliver] that wraps a [RenderBox].
RenderSliverFillEmptySpace({
RenderBox child,
}) : super(child: child);
@override
void performLayout() {
double emptySpaceExtent =
constraints.viewportMainAxisExtent - constraints.precedingScrollExtent;
if (emptySpaceExtent > 0) {
child.layout(constraints.asBoxConstraints(maxExtent: emptySpaceExtent),
parentUsesSize: true);
double childExtent = emptySpaceExtent;
final double paintedChildSize =
calculatePaintOffset(constraints, from: 0.0, to: childExtent);
final double cacheExtent =
calculateCacheOffset(constraints, from: 0.0, to: childExtent);
geometry = SliverGeometry(
scrollExtent: childExtent,
paintExtent: paintedChildSize,
cacheExtent: cacheExtent,
maxPaintExtent: childExtent,
);
setChildParentData(child, constraints, geometry);
} else {
geometry = SliverGeometry.zero;
}
}
}
class FillEmptyCustomScrollView extends prefix0.CustomScrollView {
final bool enableFillEmpty;
const FillEmptyCustomScrollView({
Key key,
this.enableFillEmpty,
Axis scrollDirection = Axis.vertical,
bool reverse = false,
ScrollController controller,
bool primary,
ScrollPhysics physics,
bool shrinkWrap = false,
Key center,
double anchor = 0.0,
double cacheExtent,
this.slivers = const <Widget>[],
int semanticChildCount,
DragStartBehavior dragStartBehavior = DragStartBehavior.start,
}) : super(
key: key,
scrollDirection: scrollDirection,
reverse: reverse,
controller: controller,
primary: primary,
physics: physics,
shrinkWrap: shrinkWrap,
center: center,
anchor: anchor,
cacheExtent: cacheExtent,
semanticChildCount: semanticChildCount,
dragStartBehavior: dragStartBehavior,
);
/// The slivers to place inside the viewport.
final List<Widget> slivers;
@override
List<Widget> buildSlivers(BuildContext context) {
if (enableFillEmpty) slivers.add(SliverFillEmptySpace());
return slivers;
}
}
class ForceFullExample extends StatelessWidget {
RefreshController _refreshController = RefreshController();
@override
Widget build(BuildContext context) {
// TODO: implement build
return SmartRefresher(
controller: _refreshController,
enablePullUp: true,
onRefresh: () async {
await Future.delayed(const Duration(milliseconds: 500));
_refreshController.refreshCompleted();
},
onLoading: () async {
await Future.delayed(const Duration(milliseconds: 500));
_refreshController.loadComplete();
},
footer: ClassicFooter(
loadStyle: LoadStyle.ShowWhenLoading,
),
child: FillEmptyCustomScrollView(
enableFillEmpty:
_refreshController.footerMode.value != LoadStatus.noMore,
slivers: <Widget>[
SliverToBoxAdapter(
child: Text(
"有很多时候,不满一屏时,会出现很多问题,比如底部指示器加载触发只能隐藏回去,而不能在底部卡着显示,等加载完毕再隐藏回去,解决这个问题,我们可以通过把Viewport剩余空间给填充满,来达到底部能看到的效果。"),
)
],
),
);
}
}
/*
* Author: Jpeng
* Email: peng8350@gmail.com
* Time: 2019-06-24 17:13
*/
/*
this example will show you how to hide Footer by the sizeOfContent,
SmartRefresher has an ability to automatically hide indicators when less than one page,e
when your slivers have some complex sliver,which will cause error hiding,so You need to hide it yourself.
though many widgets provided by flutter doesn't have this situation
first step: give RefreshConfiguration's hideFooterWhenNotFull = false
second step: use LayoutBuilder get the Widget height
third step: Use your judgment to decide whether to hide footer, enablePullUp = false
*/
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
class HideFooterManual extends StatefulWidget {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return HideFooterManualState();
}
}
class HideFooterManualState extends State<HideFooterManual> {
RefreshController _controller = RefreshController();
List<String> strs = ["1", "2"];
@override
Widget build(BuildContext context) {
// TODO: implement build
return RefreshConfiguration.copyAncestor(
context: context,
child: LayoutBuilder(
builder: (b, c) {
double refresherHeight = c.biggest.height -
50.0; // 50.0 is Container's height before SmartRefresher
return Column(
children: <Widget>[
Container(
height: 50.0,
),
Expanded(
child: SmartRefresher(
controller: _controller,
enablePullUp: refresherHeight < 100.0 * strs.length,
//100.0 is itemExtent in SliverList
onLoading: () {
strs.add("new");
if (mounted) setState(() {});
_controller.loadComplete();
},
onRefresh: () {
strs.add("new");
if (mounted) setState(() {});
_controller.refreshCompleted();
},
child: CustomScrollView(
slivers: <Widget>[
SliverFixedExtentList(
delegate: SliverChildBuilderDelegate(
(c, i) => Text(strs[i]),
childCount: strs.length),
itemExtent: 100.0,
)
],
),
),
)
],
);
},
),
hideFooterWhenNotFull: false,
);
}
}
/*
* Author: Jpeng
* Email: peng8350@gmail.com
* Time: 2019-06-24 17:23
*/
import 'dart:async';
import 'dart:convert' show json;
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import '../../Item.dart';
import 'package:http/http.dart' as HTTP;
import 'package:pull_to_refresh/pull_to_refresh.dart';
/*
this example will show you how to implements horizontal refresh or reverse,
the main point is in child scrollDirection attr
*/
class HorizontalRefresh extends StatefulWidget {
@override
_HorizontalRefreshState createState() => _HorizontalRefreshState();
}
class _HorizontalRefreshState extends State<HorizontalRefresh>
with TickerProviderStateMixin {
RefreshController _controller1 = RefreshController();
RefreshController _controller2 = RefreshController();
int indexPage = 0;
List<String> data = [];
void _fetch() {
HTTP
.get(
'https://gank.io/api/v2/data/category/Girl/type/Girl/page/$indexPage/count/10')
.then((HTTP.Response response) {
Map map = json.decode(response.body);
return map["data"];
}).then((array) {
for (var item in array) {
data.add(item["url"]);
}
if (mounted) setState(() {});
_controller1.loadComplete();
indexPage++;
}).catchError((_) {
print("error");
_controller1.loadComplete();
});
}
void _onRefresh() {
Future.delayed(const Duration(milliseconds: 2009)).then((val) {
_controller1.refreshCompleted();
// refresher.sendStatus(RefreshStatus.completed);
});
}
void _onLoading() {
Future.delayed(const Duration(milliseconds: 2009)).then((val) {
_fetch();
});
}
Widget buildImage(context, index) {
return GestureDetector(
child: Item1(
url: data[index],
),
onTap: () {
_controller1.requestRefresh();
},
);
}
@override
void initState() {
// TODO: implement initState
super.initState();
_controller1 = RefreshController();
_fetch();
}
@override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Container(
child: SmartRefresher(
enablePullDown: true,
enablePullUp: true,
controller: _controller1,
onRefresh: _onRefresh,
footer: ClassicFooter(
iconPos: IconPosition.top,
outerBuilder: (child) {
return Container(
width: 80.0,
child: Center(
child: child,
),
);
},
),
header: ClassicHeader(
iconPos: IconPosition.top,
outerBuilder: (child) {
return Container(
width: 80.0,
child: Center(
child: child,
),
);
},
),
onLoading: _onLoading,
child: ListView.builder(
itemCount: data.length,
scrollDirection: Axis.horizontal,
physics: ClampingScrollPhysics(),
itemBuilder: buildImage,
),
),
height: 200.0,
),
Expanded(
child: Container(
child: SmartRefresher(
enablePullDown: true,
enablePullUp: true,
controller: _controller2,
onRefresh: () async {
_controller2.refreshCompleted();
},
footer: ClassicFooter(
iconPos: IconPosition.top,
outerBuilder: (child) {
return Container(
width: 80.0,
child: Center(
child: child,
),
);
},
),
header: WaterDropMaterialHeader(),
onLoading: () async {
await Future.delayed(const Duration(milliseconds: 1000));
if (mounted) setState(() {});
_controller2.loadComplete();
},
child: ListView.builder(
reverse: true,
itemCount: data.length,
physics: ClampingScrollPhysics(),
itemBuilder: (c, i) => Item(
title: "data $i",
),
),
),
height: 200.0,
),
)
],
);
}
@override
// TODO: implement wantKeepAlive
bool get wantKeepAlive => false;
}
class Item1 extends StatefulWidget {
final String url;
Item1({this.url});
@override
_ItemState createState() => _ItemState();
}
class _ItemState extends State<Item1> {
@override
Widget build(BuildContext context) {
if (widget.url == null) return Container();
return FadeInImage(
placeholder: AssetImage("images/empty.png"),
image: NetworkImage(
widget.url,
),
);
}
@override
void dispose() {
// TODO: implement dispose
super.dispose();
}
}
/*
* Author: Jpeng
* Email: peng8350@gmail.com
* Time: 2019-07-11 17:55
*/
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
import '../../../other/expanded_viewport.dart';
/*
实现聊天列表+加载更多功能,类似于qq那种加载效果
聊天列表最大的难点就是在列表不满一屏时,要把它往上压。目前来说,flutter没有提供这类sliver能把剩余空间(上和下)给占有,类似于Expanded,
SliverFillRemaing并没有起作用。
ExpandedViewport是我自定义Viewport,用来解决当不满一屏时reverseListView要居于顶部的问题(只适用于少数情况),原理就是第一次
布局先探测一下他们的布局情况,第二次布局假如不满一屏,就在SliverExpanded后面的所有slivers调整主轴偏距。
*/
class QQChatList extends StatefulWidget {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return _QQChatListState();
}
}
const String myUrl =
"https://avatars1.githubusercontent.com/u/19425362?s=400&u=1a30f9fdf71cc9a51e20729b2fa1410c710d0f2f&v=4";
class _QQChatListState extends State<QQChatList> {
RefreshController _refreshController = RefreshController();
ScrollController _scrollController = ScrollController();
TextEditingController _textController = TextEditingController();
List<_MessageItem> data = [
_MessageItem(
content: "你好...................asdasdasdasdasdasdasdasdasda",
isMe: true,
author: "我",
url: myUrl,
),
_MessageItem(
content:
"eem.....................................................................",
isMe: false,
author: "对方",
url:
"https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=1718395925,3485808025&fm=27&gp=0.jpg",
),
_MessageItem(
content: "吃饭了没有?????????????",
isMe: false,
author: "对方",
url:
"https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=1718395925,3485808025&fm=27&gp=0.jpg",
)
];
@override
void initState() {
// TODO: implement initState
super.initState();
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return CupertinoApp(
home: RefreshConfiguration.copyAncestor(
context: context,
shouldFooterFollowWhenNotFull: (mode) {
return true;
},
child: CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
middle: Text("XXXXX"),
leading: GestureDetector(
child: Icon(
Icons.arrow_back_ios,
color: Colors.grey,
size: 20,
),
onTap: () {
Navigator.of(context).pop();
},
),
trailing: Icon(
Icons.group,
color: Colors.grey,
size: 24,
),
),
child: SafeArea(
child: Column(
children: <Widget>[
Expanded(
child: SmartRefresher(
enablePullDown: false,
onLoading: () async {
await Future.delayed(Duration(milliseconds: 1000));
data.add(_MessageItem(
content: "Xxxxxxxxxxxxxx",
isMe: true,
author: "我",
url: myUrl,
));
data.add(_MessageItem(
content: "...........",
isMe: false,
author: "对方",
url:
"https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=1718395925,3485808025&fm=27&gp=0.jpg",
));
data.add(_MessageItem(
content: "吃饭了没有?????????????",
isMe: false,
author: "对方",
url:
"https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=1718395925,3485808025&fm=27&gp=0.jpg"));
setState(() {});
_refreshController.loadComplete();
},
footer: CustomFooter(
loadStyle: LoadStyle.ShowAlways,
builder: (context, mode) {
if (mode == LoadStatus.loading) {
return Container(
height: 60.0,
child: Container(
height: 20.0,
width: 20.0,
child: CupertinoActivityIndicator(),
),
);
} else
return Container();
},
),
enablePullUp: true,
child: Scrollable(
controller: _scrollController,
axisDirection: AxisDirection.up,
viewportBuilder: (context, offset) {
return ExpandedViewport(
offset: offset,
axisDirection: AxisDirection.up,
slivers: <Widget>[
SliverExpanded(),
SliverList(
delegate: SliverChildBuilderDelegate(
(c, i) => data[i],
childCount: data.length),
)
],
);
},
),
controller: _refreshController,
),
),
Container(
color: Colors.white,
height: 56.0,
child: Row(
children: <Widget>[
Expanded(
child: Container(
child: CupertinoTextField(
controller: _textController,
placeholder: "输入你想发送的信息",
onSubmitted: (s) {
data.insert(
0,
_MessageItem(
content: s,
author: "我",
url: myUrl,
isMe: true,
));
setState(() {});
_scrollController.jumpTo(0.0);
_textController.clear();
},
),
margin: EdgeInsets.all(10.0),
),
),
RaisedButton(
child: Text("发送"),
color: Colors.blueAccent,
onPressed: () {
_scrollController.jumpTo(0.0);
data.insert(
0,
_MessageItem(
content: _textController.text,
author: "我",
url: myUrl,
isMe: true,
));
setState(() {});
_textController.clear();
},
)
],
),
)
],
),
),
),
),
);
}
}
class _MessageItem extends StatelessWidget {
final String content;
final String author;
final bool isMe;
final String url;
_MessageItem({this.content, this.author, this.isMe, this.url});
@override
Widget build(BuildContext context) {
// TODO: implement build
return Container(
margin: EdgeInsets.only(top: 10.0),
child: Wrap(
textDirection: isMe ? TextDirection.rtl : TextDirection.ltr,
children: <Widget>[
CircleAvatar(
backgroundImage: NetworkImage(url),
radius: 20.0,
),
Container(width: 15.0),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
height: 25.0,
width: 222.0,
alignment: isMe ? Alignment.topRight : Alignment.topLeft,
child: Text(
author,
style: TextStyle(color: Colors.grey, fontSize: 16),
),
),
Container(
constraints: BoxConstraints(
minWidth: 100.0,
minHeight: 100.0,
maxWidth: 222.0,
),
alignment: isMe ? Alignment.topRight : Alignment.topLeft,
decoration: BoxDecoration(
color: Colors.grey[200],
borderRadius: BorderRadius.circular(10),
),
child: Text(
content,
style: TextStyle(color: Colors.black),
),
padding: EdgeInsets.all(10.0),
)
],
)
],
),
);
}
}
/*
* Author: Jpeng
* Email: peng8350@gmail.com
* Time: 2020-06-21 13:43
*/
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
/*
achieve requirement
tap button to trigger refresh insteal of pull down refresh
*/
class TapButtonRefreshExample extends StatefulWidget {
TapButtonRefreshExample();
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return _TapButtonRefreshExampleState();
}
}
class _TapButtonRefreshExampleState extends State<TapButtonRefreshExample> {
List<String> data = [];
RefreshController _refreshController =
RefreshController(initialRefresh: false);
bool _enablePullDown = false;
Widget buildEmpty() {
// there are two ways
// this way is more converient,but it doesn't reference ListView some attribute
// If you don't need some attribute like physics,cacheExtent,just default
// you can return emptyWidget directly,else return ListView
// from 1.5.2,you needn't compute the height by LayoutBuilder,If your boxConstaints is double.infite,
// SmartRefresher can convert the height to the viewport mainExtent
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Image.asset(
"images/empty1.png",
fit: BoxFit.cover,
),
Text("没数据,请点击按钮刷新")
],
);
/* second way
return ListView(
children: [
Image.asset(
"images/empty.png",
fit: BoxFit.cover,
)
],
physics: BouncingScrollPhysics(),
cacheExtent: 100.0,
);
*/
}
@override
void initState() {
// TODO: implement initState
super.initState();
_refreshController.headerMode.addListener(() {
if (_refreshController.headerMode.value == RefreshStatus.idle) {
Future.delayed(const Duration(milliseconds: 20)).then((value) {
_enablePullDown = false;
setState(() {});
});
}
});
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
body: SmartRefresher(
controller: _refreshController,
enablePullUp: data.length != 0,
enablePullDown: _enablePullDown,
header: ClassicHeader(),
onRefresh: () async {
await Future.delayed(const Duration(milliseconds: 2000));
if (mounted)
setState(() {
data.add("new");
data.add("new");
data.add("new");
data.add("new");
data.add("new");
data.add("new");
});
_refreshController.refreshCompleted();
},
child: data.length == 0
? buildEmpty()
: ListView.builder(
itemBuilder: (c, i) => Text(data[i]),
itemCount: data.length,
itemExtent: 100.0,
),
),
appBar: AppBar(
title: Text("点击按钮刷新"),
actions: [
GestureDetector(
onTap: () {
_enablePullDown = true;
setState(() {});
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
_refreshController.requestRefresh();
});
},
child: Icon(Icons.refresh),
)
],
),
);
}
}
/*
* Author: Jpeng
* Email: peng8350@gmail.com
* Time: 2019-06-26 16:28
*/
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'
hide RefreshIndicator, RefreshIndicatorState;
import 'package:flutter/widgets.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
/*
there two example implements two level,
the first is common,when twoRefreshing,header will follow the list to scrollDown,when closing,still follow
list move up,
the second example use Navigator and keep offset when twoLevel trigger,
header can use ClassicalHeader to implments twoLevel,it provide outerBuilder(1.4.7)
important point:
1. open enableTwiceRefresh bool ,default is false
2. _refreshController.twiceRefreshComplete() can closing the two level
*/
class TwoLevelExample extends StatefulWidget {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return _TwoLevelExampleState();
}
}
class _TwoLevelExampleState extends State<TwoLevelExample> {
RefreshController _refreshController1 = RefreshController();
RefreshController _refreshController2 = RefreshController();
int _tabIndex = 0;
@override
void initState() {
// TODO: implement initState
_refreshController1.headerMode.addListener(() {
setState(() {});
});
WidgetsBinding.instance.addPostFrameCallback((_) {
_refreshController1.position.jumpTo(0);
setState(() {});
});
super.initState();
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return RefreshConfiguration.copyAncestor(
context: context,
enableScrollWhenTwoLevel: true,
maxOverScrollExtent: 120,
child: Scaffold(
bottomNavigationBar: !_refreshController1.isTwoLevel
? BottomNavigationBar(
currentIndex: _tabIndex,
onTap: (index) {
_tabIndex = index;
if (mounted) setState(() {});
},
items: [
BottomNavigationBarItem(
icon: Icon(Icons.add), title: Text("二级刷新例子1")),
BottomNavigationBarItem(
icon: Icon(Icons.border_clear), title: Text("二级刷新例子2"))
],
)
: null,
body: Stack(
children: <Widget>[
Offstage(
offstage: _tabIndex != 0,
child: LayoutBuilder(
builder: (_, c) {
return SmartRefresher(
header: TwoLevelHeader(
textStyle: TextStyle(color: Colors.white),
displayAlignment: TwoLevelDisplayAlignment.fromTop,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("images/secondfloor.jpg"),
fit: BoxFit.cover,
// 很重要的属性,这会影响你打开二楼和关闭二楼的动画效果
alignment: Alignment.topCenter),
),
twoLevelWidget: TwoLevelWidget(),
),
child: CustomScrollView(
physics: ClampingScrollPhysics(),
slivers: <Widget>[
SliverToBoxAdapter(
child: Container(
child: Scaffold(
appBar: AppBar(),
body: Column(
children: <Widget>[
RaisedButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text("点击这里返回上一页!"),
),
RaisedButton(
onPressed: () {
_refreshController1.requestTwoLevel();
},
child: Text("点击这里打开二楼!"),
)
],
),
),
height: 500.0,
),
)
],
),
controller: _refreshController1,
enableTwoLevel: true,
enablePullDown: true,
enablePullUp: true,
onLoading: () async {
await Future.delayed(Duration(milliseconds: 2000));
_refreshController1.loadComplete();
},
onRefresh: () async {
await Future.delayed(Duration(milliseconds: 2000));
_refreshController1.refreshCompleted();
},
onTwoLevel: () {},
);
},
),
),
Offstage(
offstage: _tabIndex != 1,
child: SmartRefresher(
header: ClassicHeader(),
child: CustomScrollView(
physics: ClampingScrollPhysics(),
slivers: <Widget>[
SliverToBoxAdapter(
child: Container(
child: RaisedButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text("点击这里返回上一页!"),
),
color: Colors.red,
height: 680.0,
),
)
],
),
controller: _refreshController2,
enableTwoLevel: true,
onRefresh: () async {
await Future.delayed(Duration(milliseconds: 2000));
_refreshController2.refreshCompleted();
},
onTwoLevel: () {
print("Asd");
_refreshController2.position.hold(() {});
Navigator.of(context)
.push(MaterialPageRoute(
builder: (c) => Scaffold(
appBar: AppBar(),
body: Text("二楼刷新"),
)))
.whenComplete(() {
_refreshController2.twoLevelComplete(
duration: Duration(microseconds: 1));
});
},
),
)
],
),
),
);
}
}
class TwoLevelWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("images/secondfloor.jpg"),
// 很重要的属性,这会影响你打开二楼和关闭二楼的动画效果,关联到TwoLevelHeader,如果背景一致的情况,请设置相同
alignment: Alignment.topCenter,
fit: BoxFit.cover),
),
child: Stack(
children: <Widget>[
Center(
child: Wrap(
children: <Widget>[
RaisedButton(
color: Colors.greenAccent,
onPressed: () {},
child: Text("登陆"),
),
],
),
),
Container(
height: 60.0,
child: GestureDetector(
child: Icon(
Icons.arrow_back_ios,
color: Colors.white,
),
onTap: () {
SmartRefresher.of(context).controller.twoLevelComplete();
},
),
alignment: Alignment.bottomLeft,
),
],
),
);
}
}
/*
* Author: Jpeng
* Email: peng8350@gmail.com
* Time: 2019/5/5 下午6:07
*/
import 'package:flutter/material.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
import 'base/IndicatorActivity.dart';
class IndicatorPage extends StatefulWidget {
IndicatorPage({Key key, this.title}) : super(key: key);
// This widget is the home page of your application. It is stateful, meaning
// that it has a State object (defined below) that contains fields that affect
// how it looks.
// This class is the configuration for the state. It holds the values (in this
// case the title) provided by the parent (in this case the App widget) and
// used by the build method of the State. Fields in a Widget subclass are
// always marked "final".
final String title;
@override
_IndicatorPageState createState() => new _IndicatorPageState();
}
class _IndicatorPageState extends State<IndicatorPage> {
List<Widget> items;
@override
Widget build(BuildContext context) {
return GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2, childAspectRatio: 0.5),
itemCount: items.length,
itemBuilder: (BuildContext context, int index) => items[index],
);
}
@override
void initState() {
// TODO: implement initState
super.initState();
}
@override
void didChangeDependencies() {
// TODO: implement didChangeDependencies
items = [
IndicatorItem(
title: "经典指示器(跟随)",
onClick: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (BuildContext context) => IndicatorActivity(
title: "经典指示器(跟随)",
header: ClassicHeader(refreshStyle: RefreshStyle.Follow),
)));
},
imgRes: "images/classical_follow.gif"),
IndicatorItem(
title: "经典指示器(不跟随)",
onClick: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (BuildContext context) => IndicatorActivity(
title: "经典指示器(不跟随)",
header:
ClassicHeader(refreshStyle: RefreshStyle.UnFollow),
)));
},
imgRes: "images/classical_unfollow.gif"),
IndicatorItem(
title: "QQ头部指示器",
onClick: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (BuildContext context) => IndicatorActivity(
reverse: false,
title: "QQ头部指示器",
header: WaterDropHeader())));
},
imgRes: "images/warterdrop.gif"),
IndicatorItem(
title: "经典Material指示器",
onClick: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (BuildContext context) => IndicatorActivity(
title: "官方Material指示器",
header: MaterialClassicHeader(
distance: 40,
))));
},
imgRes: "images/material_classic.gif"),
IndicatorItem(
title: "bezier+circle",
onClick: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (BuildContext context) => IndicatorActivity(
reverse: false,
title: "bezier+circle",
header: BezierCircleHeader(
dismissType: BezierDismissType.ScaleToCenter,
))));
},
imgRes: "images/bezier.gif"),
IndicatorItem(
title: "水滴坠落Material指示器",
onClick: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (BuildContext context) => IndicatorActivity(
reverse: false,
title: "水滴坠落Material指示器",
header: WaterDropMaterialHeader(color: Colors.red))));
},
imgRes: "images/material_waterdrop.gif"),
IndicatorItem(
title: "底部指示器(经常显示)",
onClick: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (BuildContext context) => IndicatorActivity(
title: "底部指示器(经常显示)",
footer: ClassicFooter(
height: 80.0,
loadStyle: LoadStyle.ShowAlways,
),
)));
},
imgRes: "images/loadstyle1.gif"),
IndicatorItem(
title: "底部指示器(经常隐藏)",
onClick: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (BuildContext context) =>
RefreshConfiguration.copyAncestor(
context: context,
child: IndicatorActivity(
reverse: false,
title: "底部指示器(经常隐藏)",
footer: ClassicFooter(
loadStyle: LoadStyle.HideAlways,
)),
footerTriggerDistance: -30.0,
enableLoadingWhenFailed: true,
maxUnderScrollExtent: 100.0,
)));
},
imgRes: "images/loadstyle2.gif"),
IndicatorItem(
title: "底部指示器(只有加载中才显示)",
onClick: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (BuildContext context) =>
RefreshConfiguration.copyAncestor(
context: context,
child: RefreshConfiguration.copyAncestor(
context: context,
child: IndicatorActivity(
reverse: false,
title: "底部指示器(只有加载中才显示)",
footer: ClassicFooter(
loadStyle: LoadStyle.ShowWhenLoading,
)),
enableLoadingWhenFailed: true,
maxUnderScrollExtent: 100.0,
footerTriggerDistance: -45.0,
),
enableLoadingWhenFailed: true,
footerTriggerDistance: -60.0,
)));
},
imgRes: "images/loadstyle3.gif"),
];
super.didChangeDependencies();
}
}
class IndicatorItem extends StatefulWidget {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return _IndicatorItemState();
}
final Function onClick;
final String imgRes;
final String title;
IndicatorItem({this.title, this.imgRes, this.onClick});
}
class _IndicatorItemState extends State<IndicatorItem> {
@override
Widget build(BuildContext context) {
// TODO: implement build
return InkWell(
onTap: widget.onClick,
child: Card(
child: Column(
children: <Widget>[
Center(
child: Image.asset(
widget.imgRes,
fit: BoxFit.cover,
width: 180.0,
),
),
Center(
child: Text(widget.title),
)
],
),
),
);
}
}
/*
* Author: Jpeng
* Email: peng8350@gmail.com
* Time: 2019/5/5 下午6:10
*/
import 'package:flutter/material.dart'
hide RefreshIndicator, RefreshIndicatorState;
import 'package:pull_to_refresh/pull_to_refresh.dart';
import '../../Item.dart';
class IndicatorActivity extends StatefulWidget {
final String title;
final Widget header;
final Widget footer;
final bool enableOverScroll;
final bool reverse;
IndicatorActivity(
{this.title,
this.header,
this.reverse: false,
this.footer,
this.enableOverScroll: true});
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return _IndicatorActivityState();
}
}
class _IndicatorActivityState extends State<IndicatorActivity> {
List<Widget> items = [];
RefreshController _refreshController;
void _init() {
for (int i = 0; i < 15; i++) {
items.add(Item(
title: "Data$i",
));
}
}
ScrollController _scrollController;
@override
void initState() {
// TODO: implement initState
_scrollController = new ScrollController();
_refreshController = RefreshController();
Future.delayed(Duration(milliseconds: 3000)).then((_) {
// _jumpTo(0.0);
});
_init();
super.initState();
}
@override
void dispose() {
// TODO: implement dispose
_refreshController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text(widget.title),
),
body: Builder(
builder: (c) {
return SmartRefresher(
child: ListView.builder(
itemBuilder: (c, i) => items[i],
itemExtent: 100.0,
controller: _scrollController,
reverse: widget.reverse,
itemCount: items.length,
),
onRefresh: _onRefresh,
onLoading: () {
_onLoading(c);
},
header: widget.header,
footer: widget.footer,
enablePullDown: true,
enablePullUp: true,
controller: _refreshController);
},
),
);
}
_onRefresh() {
print("onRefresh");
Future.delayed(Duration(milliseconds: 1000)).then((_) {
items.add(Item(title: "Data"));
if (mounted) setState(() {});
_refreshController.refreshCompleted();
});
}
_onLoading(BuildContext context) {
print("onLoading");
Future.delayed(Duration(milliseconds: 1000)).then((_) {
_refreshController.loadComplete();
});
}
}
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart' hide RefreshIndicator;
class Test1 extends StatefulWidget {
Test1({Key key}) : super(key: key);
@override
Test1State createState() => Test1State();
}
class Test1State extends State<Test1> {
// RefreshMode refreshing = RefreshMode.idle;
// LoadMode loading = LoadMode.idle;
RefreshController _refreshController;
ScrollController _scrollController;
List<Widget> data = [];
void _getDatas() {
for (int i = 0; i < 4; i++) {
data.add(Container(
color: Colors.greenAccent,
margin: EdgeInsets.only(left: 10.0, right: 10.0, top: 5.0, bottom: 5.0),
child: Center(
child: Text('Data $i'),
),
));
}
}
void scrollTop() {
_scrollController.animateTo(0.0,
duration: const Duration(milliseconds: 200), curve: Curves.linear);
}
void enterRefresh() {
_refreshController.requestRefresh();
}
void _onOffsetCallback(bool isUp, double offset) {}
@override
void initState() {
// TODO: implement initState
_getDatas();
_scrollController = ScrollController(keepScrollOffset: true);
_refreshController = RefreshController();
SchedulerBinding.instance.addPostFrameCallback((_) {
// _refreshController.requestRefresh(true);
});
super.initState();
}
// Widget _footerCreate(BuildContext context,int mode){
// return new ClassicIndicator(mode: mode);
// }
@override
Widget build(BuildContext context) {
return NestedScrollView(
key: PageStorageKey("q"),
controller: _scrollController,
headerSliverBuilder: (c, s) => [
SliverAppBar(
backgroundColor: Colors.greenAccent,
expandedHeight: 200.0,
pinned: true,
flexibleSpace: FlexibleSpaceBar(
centerTitle: true,
background: Image.network(
"https://images.unsplash.com/photo-1541701494587-cb58502866ab?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=0c21b1ac3066ae4d354a3b2e0064c8be&auto=format&fit=crop&w=500&q=60",
fit: BoxFit.cover,
)),
),
],
body: Container(
child: SmartRefresher(
controller: _refreshController,
enablePullDown: true,
header: WaterDropHeader(),
enablePullUp: true,
onRefresh: () {
Future.delayed(const Duration(milliseconds: 2009)).then((val) {
data.add(Card(
margin: EdgeInsets.only(
left: 10.0, right: 10.0, top: 5.0, bottom: 5.0),
child: Center(
child: Text('Data '),
),
));
if (mounted)
setState(() {
_refreshController.refreshCompleted();
});
});
},
onLoading: () {
Future.delayed(const Duration(milliseconds: 2009)).then((val) {
if (mounted)
setState(() {
data.add(Card(
margin: EdgeInsets.only(
left: 10.0, right: 10.0, top: 5.0, bottom: 5.0),
child: Center(
child: Text('Data '),
),
));
_refreshController.loadComplete();
});
});
},
onOffsetChange: _onOffsetCallback,
child: ListView.builder(
itemExtent: 100.0,
itemCount: data.length,
itemBuilder: (context, index) => Item(),
)),
));
}
}
class Item extends StatefulWidget {
@override
_ItemState createState() => _ItemState();
}
class _ItemState extends State<Item> {
@override
Widget build(BuildContext context) {
return Card(
color: Colors.red,
margin: EdgeInsets.only(left: 10.0, right: 10.0, top: 5.0, bottom: 5.0),
child: Center(
child: Text('Data'),
),
);
}
@override
void dispose() {
// TODO: implement dispose
super.dispose();
}
}
import 'dart:async';
import 'dart:convert' show json;
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as HTTP;
import 'package:pull_to_refresh/pull_to_refresh.dart';
class Test2 extends StatefulWidget {
@override
_Test2State createState() => _Test2State();
}
class _Test2State extends State<Test2> with TickerProviderStateMixin {
RefreshController _controller;
int indexPage = 0;
List<String> data = [];
void _fetch() {
HTTP
.get(
'https://gank.io/api/v2/data/category/Girl/type/Girl/page/$indexPage/count/10')
.then((HTTP.Response response) {
Map map = json.decode(response.body);
return map["data"];
}).then((array) {
for (var item in array) {
data.add(item["url"]);
}
if (mounted) setState(() {});
_controller.loadFailed();
indexPage++;
}).catchError((_) {
print("error");
_controller.loadComplete();
});
}
void _onRefresh() {
Future.delayed(const Duration(milliseconds: 2009)).then((val) {
_controller.refreshCompleted();
// refresher.sendStatus(RefreshStatus.completed);
});
}
void _onLoading() {
Future.delayed(const Duration(milliseconds: 2009)).then((val) {
_fetch();
});
}
Widget buildImage(context, index) {
return GestureDetector(
child: Item(
url: data[index],
),
onTap: () {
print("tap");
// _controller.requestRefresh().then((_){
// print("request complete");
// });
_controller.requestRefresh(needMove: false)?.then((_) {
print("request complete");
});
},
);
}
void _onOffsetCallback(bool isUp, double offset) {
// if you want change some widgets state ,you should rewrite the callback
if (isUp) {
} else {}
}
@override
void initState() {
// TODO: implement initState
super.initState();
_controller = RefreshController(initialLoadStatus: LoadStatus.failed);
_fetch();
}
@override
void didChangeDependencies() {
// TODO: implement didChangeDependencies
super.didChangeDependencies();
}
@override
Widget build(BuildContext context) {
return SmartRefresher(
enablePullDown: true,
enablePullUp: true,
controller: _controller,
onRefresh: _onRefresh,
header: MaterialClassicHeader(),
onLoading: _onLoading,
onOffsetChange: _onOffsetCallback,
child: GridView.builder(
primary: false,
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
itemCount: data.length,
itemBuilder: buildImage,
),
);
}
}
class Item extends StatefulWidget {
final String url;
Item({this.url});
@override
_ItemState createState() => _ItemState();
}
class _ItemState extends State<Item> {
@override
Widget build(BuildContext context) {
if (widget.url == null) return Container();
return Container(
child: FadeInImage(
placeholder: AssetImage("images/empty.png"),
image: NetworkImage(
widget.url,
),
),
);
}
@override
void dispose() {
// TODO: implement dispose
super.dispose();
}
}
import 'dart:async';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
class Test3 extends StatefulWidget {
Test3({Key key}) : super(key: key);
@override
Test3State createState() => Test3State();
}
class Test3State extends State<Test3> with TickerProviderStateMixin {
// RefreshMode refreshing = RefreshMode.idle;
// LoadMode loading = LoadMode.idle;
ValueNotifier<double> topOffsetLis = ValueNotifier(0.0);
ValueNotifier<double> bottomOffsetLis = ValueNotifier(0.0);
RefreshController _refreshController;
List<Widget> data = [];
void _getDatas() {
data.add(Row(
children: <Widget>[
FlatButton(
onPressed: () {
_refreshController.requestRefresh();
},
child: Text("请求刷新")),
FlatButton(
onPressed: () {
_refreshController.requestLoading();
},
child: Text("请求加载数据"))
],
));
for (int i = 0; i < 1; i++) {
data.add(GestureDetector(
child: Container(
color: Color.fromARGB(255, 250, 250, 250),
child: Card(
margin:
EdgeInsets.only(left: 10.0, right: 10.0, top: 5.0, bottom: 5.0),
child: Center(
child: Text('Data $i'),
),
),
),
onTap: () {
_refreshController.requestRefresh();
},
));
}
}
void enterRefresh() {
_refreshController.requestLoading();
}
@override
void initState() {
// TODO: implement initState
// for test #68 true-> false ->true
// Future.delayed(Duration(milliseconds: 3000), () {
// _enablePullDown = false;
// _enablePullUp = false;
// if (mounted) setState(() {});
// });
// Future.delayed(Duration(milliseconds: 6000), () {
// _enablePullDown = true;
// _enablePullUp = true;
// if (mounted) setState(() {});
// });
// // for test #68 false-> true ->false
// Future.delayed(Duration(milliseconds: 3000),(){
// _enablePullDown = false;
// _enablePullUp = true;
// if(mounted)
// setState(() {
//
// });
// });
// Future.delayed(Duration(milliseconds: 6000),(){
// _enablePullDown = true;
// _enablePullUp = false;
// if(mounted)
// setState(() {
//
// });
// });
// Future.delayed(Duration(milliseconds: 3000),(){
// _enablePullDown = true;
// _enablePullUp = false;
// if(mounted)
// setState(() {
//
// });
// });
// Future.delayed(Duration(milliseconds: 6000),(){
// _enablePullDown = false;
// _enablePullUp = true;
// if(mounted)
// setState(() {
//
// });
// });
_getDatas();
_refreshController = RefreshController(
initialRefresh: false, initialLoadStatus: LoadStatus.noMore);
super.initState();
}
@override
void dispose() {
// TODO: implement dispose
super.dispose();
}
@override
void didChangeDependencies() {
// TODO: implement didChangeDependencies
super.didChangeDependencies();
}
@override
Widget build(BuildContext context) {
return RefreshConfiguration.copyAncestor(
context: context,
footerTriggerDistance: -80,
maxUnderScrollExtent: 60,
enableLoadingWhenNoData: true,
child: SmartRefresher(
enablePullUp: true,
enablePullDown: true,
controller: _refreshController,
footer: ClassicFooter(
height: 60,
loadStyle: LoadStyle.ShowWhenLoading,
),
header: TwoLevelHeader(
twoLevelWidget: Center(
child: Container(
color: Colors.green,
width: double.infinity,
child: Text("twoLevel"),
height: 60,
),
),
),
onRefresh: () async {
print("onRefresh");
await Future.delayed(const Duration(milliseconds: 3000));
data.add(Container(
child: Card(),
height: 100.0,
));
if (mounted) setState(() {});
_refreshController.refreshCompleted();
// Future.delayed(const Duration(milliseconds: 2009)).then((val) {
// data.add(Card());
//
// });
},
child: CustomScrollView(
slivers: <Widget>[
SliverFillViewport(
delegate: SliverChildListDelegate(
[Text("第一页"), Text("第一页"), Text("第一页"), Text("第一页")]))
],
physics: PageScrollPhysics(),
),
onLoading: () async {
await Future.delayed(const Duration(milliseconds: 1000));
print("onLoading");
_refreshController.loadNoData();
},
),
dragSpeedRatio: 0.9,
);
}
}
class CirclePainter extends CustomClipper<Path> {
final double offset;
final bool up;
CirclePainter({this.offset, this.up});
@override
Path getClip(Size size) {
// TODO: implement getClip
final path = Path();
if (!up) path.moveTo(0.0, size.height);
path.cubicTo(
0.0,
up ? 0.0 : size.height,
size.width / 2,
up ? offset * 2.3 : size.height - offset * 2.3,
size.width,
up ? 0.0 : size.height);
path.close();
return path;
}
@override
bool shouldReclip(CustomClipper oldClipper) {
// TODO: implement shouldReclip
return oldClipper != this;
}
}
import 'dart:async';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
class Test4 extends StatefulWidget {
Test4({Key key}) : super(key: key);
@override
Test4State createState() => Test4State();
}
class Test4State extends State<Test4> with TickerProviderStateMixin {
// RefreshMode refreshing = RefreshMode.idle;
// LoadMode loading = LoadMode.idle;
ValueNotifier<double> topOffsetLis = ValueNotifier(0.0);
ValueNotifier<double> bottomOffsetLis = ValueNotifier(0.0);
RefreshController _refreshController;
List<Widget> data = [];
void _getDatas() {
data.add(Row(
children: <Widget>[
FlatButton(
onPressed: () {
_refreshController.requestRefresh();
},
child: Text("请求刷新")),
FlatButton(
onPressed: () {
_refreshController.requestLoading();
},
child: Text("请求加载数据"))
],
));
for (int i = 0; i < 22; i++) {
data.add(GestureDetector(
child: Container(
color: Color.fromARGB(255, 250, 250, 250),
child: Card(
margin:
EdgeInsets.only(left: 10.0, right: 10.0, top: 5.0, bottom: 5.0),
child: Center(
child: Text('Data $i'),
),
),
),
onTap: () {
_refreshController.requestRefresh();
},
));
}
}
void enterRefresh() {
_refreshController.requestLoading();
}
@override
void initState() {
// TODO: implement initState
// for test #68 true-> false ->true
// Future.delayed(Duration(milliseconds: 3000), () {
// _enablePullDown = false;
// _enablePullUp = false;
// if (mounted) setState(() {});
// });
// Future.delayed(Duration(milliseconds: 6000), () {
// _enablePullDown = true;
// _enablePullUp = true;
// if (mounted) setState(() {});
// });
// // for test #68 false-> true ->false
// Future.delayed(Duration(milliseconds: 3000),(){
// _enablePullDown = false;
// _enablePullUp = true;
// if(mounted)
// setState(() {
//
// });
// });
// Future.delayed(Duration(milliseconds: 6000),(){
// _enablePullDown = true;
// _enablePullUp = false;
// if(mounted)
// setState(() {
//
// });
// });
// Future.delayed(Duration(milliseconds: 3000),(){
// _enablePullDown = true;
// _enablePullUp = false;
// if(mounted)
// setState(() {
//
// });
// });
// Future.delayed(Duration(milliseconds: 6000),(){
// _enablePullDown = false;
// _enablePullUp = true;
// if(mounted)
// setState(() {
//
// });
// });
// final NetworkImage provider = AssetImage("images/animate.gif");
// provider.obtainKey(ImageConfiguration()).then((k) async{
// final ByteData data = await k.bundle.load(k.name);
// ui.Codec codec= await PaintingBinding.instance.instantiateImageCodec(data.buffer.asUint8List());
// ui.FrameInfo info;
// for(int i = 0 ;i<54;i++){
// info = await codec.getNextFrame();
// }
// print(codec.frameCount);
// return ;
// });
_getDatas();
_refreshController = RefreshController(initialRefresh: false);
super.initState();
}
@override
void dispose() {
// TODO: implement dispose
super.dispose();
}
@override
Widget build(BuildContext context) {
// // Check that a second resolve of the same image is synchronous.
// final ImageStream stream = provider.resolve(provider.);
// bool isSync;
// stream.addListener(ImageStreamListener((ImageInfo image, bool sync) { isSync = sync; }));
return RefreshConfiguration.copyAncestor(
context: context,
child: SmartRefresher.builder(
enablePullUp: true,
enablePullDown: true,
builder: (context, physics) {
return CustomScrollView(physics: physics, slivers: [
MaterialClassicHeader(),
SliverAppBar(),
SliverToBoxAdapter(
child: Column(
children: <Widget>[
Container(
height: 3000,
color: Colors.red,
),
Center(
child: Row(
children: <Widget>[
RaisedButton(
child: Text("主动刷新(移动)"),
onPressed: () {
_refreshController.requestRefresh();
},
),
RaisedButton(
child: Text("主动加载"),
onPressed: () {
_refreshController.requestLoading();
},
),
],
),
),
Container(
height: 3000,
color: Colors.red,
),
],
),
),
ClassicFooter(),
]);
},
onRefresh: () async {
print("onRefresh");
await Future.delayed(Duration(milliseconds: 1300));
_refreshController.refreshCompleted();
},
onLoading: () async {
await Future.delayed(Duration(milliseconds: 1300));
_refreshController.loadComplete();
},
controller: _refreshController,
),
hideFooterWhenNotFull: false,
);
}
@override
// TODO: implement wantKeepAlive
bool get wantKeepAlive => false;
}
class CirclePainter extends CustomClipper<Path> {
final double offset;
final bool up;
CirclePainter({this.offset, this.up});
@override
Path getClip(Size size) {
// TODO: implement getClip
final path = Path();
if (!up) path.moveTo(0.0, size.height);
path.cubicTo(
0.0,
up ? 0.0 : size.height,
size.width / 2,
up ? offset * 2.3 : size.height - offset * 2.3,
size.width,
up ? 0.0 : size.height);
path.close();
return path;
}
@override
bool shouldReclip(CustomClipper oldClipper) {
// TODO: implement shouldReclip
return oldClipper != this;
}
}
class RefreshListView extends StatefulWidget {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return _RefreshListViewState();
}
final ScrollPhysics physics;
final List<Widget> slivers;
RefreshListView({this.slivers, this.physics});
}
class _RefreshListViewState extends State<RefreshListView> {
bool show = true;
@override
Widget build(BuildContext context) {
// TODO: implement build
return show
? CustomScrollView(
slivers: widget.slivers,
physics: AlwaysScrollableScrollPhysics(),
)
: CupertinoActivityIndicator();
}
}
import 'Test1.dart';
import 'Test2.dart';
import 'Test3.dart';
import 'Test4.dart';
import 'package:flutter/material.dart';
class TestPage extends StatefulWidget {
TestPage({Key key, this.title}) : super(key: key);
// This widget is the home page of your application. It is stateful, meaning
// that it has a State object (defined below) that contains fields that affect
// how it looks.
// This class is the configuration for the state. It holds the values (in this
// case the title) provided by the parent (in this case the App widget) and
// used by the build method of the State. Fields in a Widget subclass are
// always marked "final".
final String title;
@override
_TestPageState createState() => new _TestPageState();
}
class _TestPageState extends State<TestPage>
with SingleTickerProviderStateMixin {
int tabIndex = 0;
PageController _pageController;
List<Widget> views;
GlobalKey<Test3State> example3Key = GlobalKey();
GlobalKey<Test1State> example1Key = GlobalKey();
@override
Widget build(BuildContext context) {
// This method is rerun every time setState is called, for instance as done
// by the _incrementCounter method above.
//
// The Flutter framework has been optimized to make rerunning build methods
// fast, so that you can just rebuild anything that needs updating rather
// than having to individually change instances of widgets.
// return new Scaffold(
//
// appBar: new AppBar(
// // Here we take the value from the MyHomePage object that was created by
// // the App.build method, and use it to set our appbar title.
// bottom: new TabBar(controller: _tabController,tabs: <Widget>[ new Tab(icon: new Icon(Icons.nature),) , new Tab(icon: new Icon(Icons.directions_bike),),
// new Tab(icon: new Icon(Icons.directions_boat),),
// new Tab(icon: new Icon(Icons.directions_bus),),],),
// title: new Text(widget.title),
// actions: <Widget>[(tabIndex==2||tabIndex==0)?new MaterialButton(onPressed: (){
// tabIndex==2? example3Key.currentState.enterRefresh():example1Key.currentState.scrollTop();
// },child: new Text(tabIndex==2?'refresh3':"滚回顶部",style: new TextStyle(color:Colors.white),)):new Container()],
// ),
// body: new TabBarView(children: views,controller:_tabController ,),
// );
return Column(
children: <Widget>[
Expanded(
child: PageView(
controller: _pageController,
physics: NeverScrollableScrollPhysics(),
children: views,
onPageChanged: (index) {
tabIndex = index;
if (mounted) setState(() {});
},
),
),
BottomNavigationBar(
items: [
BottomNavigationBarItem(
icon: Icon(Icons.home,
color: tabIndex == 0 ? Colors.blue : Colors.grey),
title: Text('Example1',
style: TextStyle(
color: tabIndex == 0 ? Colors.blue : Colors.grey))),
BottomNavigationBarItem(
icon: Icon(Icons.cloud,
color: tabIndex == 1 ? Colors.blue : Colors.grey),
title: Text('Example2',
style: TextStyle(
color: tabIndex == 1 ? Colors.blue : Colors.grey))),
BottomNavigationBarItem(
icon: Icon(Icons.call,
color: tabIndex == 2 ? Colors.blue : Colors.grey),
title: Text('Example3',
style: TextStyle(
color: tabIndex == 2 ? Colors.blue : Colors.grey))),
BottomNavigationBarItem(
icon: Icon(Icons.transform,
color: tabIndex == 3 ? Colors.blue : Colors.grey),
title: Text('Example4',
style: TextStyle(
color: tabIndex == 3 ? Colors.blue : Colors.grey))),
],
onTap: (index) {
_pageController.jumpToPage(index);
},
currentIndex: tabIndex,
fixedColor: Colors.grey,
type: BottomNavigationBarType.fixed,
)
],
);
}
@override
void initState() {
// TODO: implement initState
_pageController = PageController();
views = [
Test1(key: example1Key),
Test2(),
Test3(key: example3Key),
Test4()
];
super.initState();
}
}
name: example
description: A new Flutter project.
dependencies:
flutter:
sdk: flutter
pull_to_refresh:
path: ../
http: 0.12.0
flutter_staggered_grid_view: ^0.3.0
flutter_spinkit: 2.1.0
residemenu: 1.3.7
fish_redux: ^0.2.2
shimmer: 1.0.0
flutter_sticky_header: ^0.4.0
flutter_gifimage: ^1.0.0
flutter_swiper : ^1.1.6
dev_dependencies:
flutter_test:
sdk: flutter
flutter_localizations:
sdk: flutter
# For information on the generic Dart part of this file, see the
# following page: https://www.dartlang.org/tools/pub/pubspec
# The following section is specific to Flutter.
flutter:
assets:
- images/animate.gif
- images/empty.png
- images/empty1.png
- images/secondfloor.jpg
- images/classical_follow.gif
- images/classical_unfollow.gif
- images/bezier.gif
- images/warterdrop.gif
- images/material_classic.gif
- images/material_waterdrop.gif
- images/qqbg.jpg
- images/custom_1.jpg
- images/gifindicator1.gif
- images/msg_text_right_bg.9.png
- images/custom_2.gif
- images/loadstyle1.gif
- images/loadstyle2.gif
- images/loadstyle3.gif
- images/refreshstyle1.gif
- images/refreshstyle2.gif
- images/refreshstyle3.gif
- images/refreshstyle4.gif
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true
# To add assets to your application, add an assets section, like this:
# assets:
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.io/assets-and-images/#resolution-aware.
# For details regarding adding assets from package dependencies, see
# https://flutter.io/assets-and-images/#from-packages
# To add custom fonts to your application, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a
# "family" key with the font family name, and a "fonts" key with a
# list giving the asset and other descriptors for the font. For
# example:
# fonts:
# - family: Schyler
# fonts:
# - asset: fonts/Schyler-Regular.ttf
# - asset: fonts/Schyler-Italic.ttf
# style: italic
# - family: Trajan Pro
# fonts:
# - asset: fonts/TrajanPro.ttf
# - asset: fonts/TrajanPro_Bold.ttf
# weight: 700
#
# For details regarding fonts from package dependencies,
# see https://flutter.io/custom-fonts/#from-packages
......@@ -52,7 +52,6 @@ class BezierHeader extends RefreshIndicator {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return _BezierHeaderState();
}
}
......@@ -63,7 +62,6 @@ class _BezierHeaderState extends RefreshIndicatorState<BezierHeader>
@override
void initState() {
// TODO: implement initState
_beizerBounceCtl = AnimationController(
vsync: this, lowerBound: -10, upperBound: 50, value: 0);
_bezierDismissCtl = AnimationController(vsync: this);
......@@ -72,7 +70,6 @@ class _BezierHeaderState extends RefreshIndicatorState<BezierHeader>
@override
void onOffsetChange(double offset) {
// TODO: implement onOffsetChange
if (widget.onOffsetChange != null) {
widget.onOffsetChange(offset);
}
......@@ -82,7 +79,6 @@ class _BezierHeaderState extends RefreshIndicatorState<BezierHeader>
@override
void onModeChange(RefreshStatus mode) {
// TODO: implement onModeChange
if (widget.onModeChange != null) {
widget.onModeChange(mode);
}
......@@ -91,7 +87,6 @@ class _BezierHeaderState extends RefreshIndicatorState<BezierHeader>
@override
void dispose() {
// TODO: implement dispose
_bezierDismissCtl.dispose();
_beizerBounceCtl.dispose();
super.dispose();
......@@ -99,7 +94,6 @@ class _BezierHeaderState extends RefreshIndicatorState<BezierHeader>
@override
Future<void> readyToRefresh() {
// TODO: implement readyToRefresh
final Simulation simulation = SpringSimulation(
SpringDescription(
mass: 3.4,
......@@ -118,7 +112,6 @@ class _BezierHeaderState extends RefreshIndicatorState<BezierHeader>
@override
Future<void> endRefresh() async {
// TODO: implement endRefresh
if (widget.endRefresh != null) {
await widget.endRefresh();
}
......@@ -128,7 +121,6 @@ class _BezierHeaderState extends RefreshIndicatorState<BezierHeader>
@override
void resetValue() {
// TODO: implement resetValue
_bezierDismissCtl.reset();
_beizerBounceCtl.value = 0;
if (widget.onResetValue != null) {
......@@ -139,8 +131,6 @@ class _BezierHeaderState extends RefreshIndicatorState<BezierHeader>
@override
Widget buildContent(BuildContext context, RefreshStatus mode) {
// TODO: implement buildContent
return AnimatedBuilder(
builder: (_, __) {
return Stack(
......@@ -209,7 +199,6 @@ class _BezierDismissPainter extends CustomClipper<Path> {
@override
getClip(Size size) {
// TODO: implement getClip
Path path = Path();
if (dismissType == BezierDismissType.None || value == 0) {
path.moveTo(0, 0);
......@@ -247,7 +236,6 @@ class _BezierDismissPainter extends CustomClipper<Path> {
@override
bool shouldReclip(_BezierDismissPainter oldClipper) {
// TODO: implement shouldReclip
return dismissType != oldClipper.dismissType || value != oldClipper.value;
}
}
......@@ -261,7 +249,6 @@ class _BezierPainter extends CustomClipper<Path> {
@override
getClip(Size size) {
// TODO: implement getClip
Path path = Path();
path.lineTo(0, startOffsetY);
path.quadraticBezierTo(
......@@ -275,7 +262,6 @@ class _BezierPainter extends CustomClipper<Path> {
@override
bool shouldReclip(_BezierPainter oldClipper) {
// TODO: implement shouldReclip
return value != oldClipper.value;
}
}
......@@ -317,7 +303,6 @@ class BezierCircleHeader extends StatefulWidget {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return _BezierCircleHeaderState();
}
}
......@@ -333,7 +318,6 @@ class _BezierCircleHeaderState extends State<BezierCircleHeader>
@override
void initState() {
// TODO: implement initState
_dismissCtrl = AnimationController(vsync: this);
_childMoveCtl = AnimationController(vsync: this);
_radialCtrl =
......@@ -347,7 +331,6 @@ class _BezierCircleHeaderState extends State<BezierCircleHeader>
@override
void dispose() {
// TODO: implement dispose
_dismissCtrl.dispose();
_childMoveCtl.dispose();
_radialCtrl.dispose();
......@@ -356,7 +339,6 @@ class _BezierCircleHeaderState extends State<BezierCircleHeader>
@override
Widget build(BuildContext context) {
// TODO: implement build
return BezierHeader(
bezierColor: widget.bezierColor,
rectHeight: widget.rectHeight,
......@@ -447,7 +429,6 @@ class _RaidalPainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
// TODO: implement paint
Paint paint = Paint();
paint.color = circleColor;
paint.strokeWidth = 2;
......@@ -496,7 +477,6 @@ class _RaidalPainter extends CustomPainter {
@override
bool shouldRepaint(_RaidalPainter oldDelegate) {
// TODO: implement shouldRepaint
return value != oldDelegate.value;
}
}
......@@ -88,7 +88,6 @@ class ClassicHeader extends RefreshIndicator {
@override
State createState() {
// TODO: implement createState
return _ClassicHeaderState();
}
}
......@@ -146,13 +145,11 @@ class _ClassicHeaderState extends RefreshIndicatorState<ClassicHeader> {
@override
bool needReverseAll() {
// TODO: implement needReverseAll
return false;
}
@override
Widget buildContent(BuildContext context, RefreshStatus mode) {
// TODO: implement buildContent
Widget textWidget = _buildText(mode);
Widget iconWidget = _buildIcon(mode);
List<Widget> children = <Widget>[iconWidget, textWidget];
......@@ -243,8 +240,6 @@ class ClassicFooter extends LoadIndicator {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return _ClassicFooterState();
}
}
......@@ -289,13 +284,11 @@ class _ClassicFooterState extends LoadIndicatorState<ClassicFooter> {
@override
Future endLoading() {
// TODO: implement endLoading
return Future.delayed(widget.completeDuration);
}
@override
Widget buildContent(BuildContext context, LoadStatus mode) {
// TODO: implement buildChild
Widget textWidget = _buildText(mode);
Widget iconWidget = _buildIcon(mode);
List<Widget> children = <Widget>[iconWidget, textWidget];
......
......@@ -81,7 +81,6 @@ class CustomHeader extends RefreshIndicator {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return _CustomHeaderState();
}
}
......@@ -89,7 +88,6 @@ class CustomHeader extends RefreshIndicator {
class _CustomHeaderState extends RefreshIndicatorState<CustomHeader> {
@override
void onOffsetChange(double offset) {
// TODO: implement onOffsetChange
if (widget.onOffsetChange != null) {
widget.onOffsetChange(offset);
}
......@@ -98,7 +96,6 @@ class _CustomHeaderState extends RefreshIndicatorState<CustomHeader> {
@override
void onModeChange(RefreshStatus mode) {
// TODO: implement onModeChange
if (widget.onModeChange != null) {
widget.onModeChange(mode);
}
......@@ -107,7 +104,6 @@ class _CustomHeaderState extends RefreshIndicatorState<CustomHeader> {
@override
Future<void> readyToRefresh() {
// TODO: implement endRefresh
if (widget.readyToRefresh != null) {
return widget.readyToRefresh();
}
......@@ -116,7 +112,6 @@ class _CustomHeaderState extends RefreshIndicatorState<CustomHeader> {
@override
Future<void> endRefresh() {
// TODO: implement endRefresh
if (widget.endRefresh != null) {
return widget.endRefresh();
}
......@@ -125,7 +120,6 @@ class _CustomHeaderState extends RefreshIndicatorState<CustomHeader> {
@override
Widget buildContent(BuildContext context, RefreshStatus mode) {
// TODO: implement buildContent
return widget.builder(context, mode);
}
}
......@@ -159,7 +153,6 @@ class CustomFooter extends LoadIndicator {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return _CustomFooterState();
}
}
......@@ -167,7 +160,6 @@ class CustomFooter extends LoadIndicator {
class _CustomFooterState extends LoadIndicatorState<CustomFooter> {
@override
void onOffsetChange(double offset) {
// TODO: implement onOffsetChange
if (widget.onOffsetChange != null) {
widget.onOffsetChange(offset);
}
......@@ -176,7 +168,6 @@ class _CustomFooterState extends LoadIndicatorState<CustomFooter> {
@override
void onModeChange(LoadStatus mode) {
// TODO: implement onModeChange
if (widget.onModeChange != null) {
widget.onModeChange(mode);
}
......@@ -185,7 +176,6 @@ class _CustomFooterState extends LoadIndicatorState<CustomFooter> {
@override
Future readyToLoad() {
// TODO: implement readyToLoad
if (widget.readyLoading != null) {
return widget.readyLoading();
}
......@@ -194,7 +184,6 @@ class _CustomFooterState extends LoadIndicatorState<CustomFooter> {
@override
Future endLoading() {
// TODO: implement endLoading
if (widget.endLoading != null) {
return widget.endLoading();
}
......@@ -203,7 +192,6 @@ class _CustomFooterState extends LoadIndicatorState<CustomFooter> {
@override
Widget buildContent(BuildContext context, LoadStatus mode) {
// TODO: implement buildContent
return widget.builder(context, mode);
}
}
......@@ -25,7 +25,6 @@ class LinkHeader extends RefreshIndicator {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return _LinkHeaderState();
}
}
......@@ -33,49 +32,42 @@ class LinkHeader extends RefreshIndicator {
class _LinkHeaderState extends RefreshIndicatorState<LinkHeader> {
@override
void resetValue() {
// TODO: implement resetValue
((widget.linkKey as GlobalKey).currentState as RefreshProcessor)
.resetValue();
}
@override
Future<void> endRefresh() {
// TODO: implement endRefresh
return ((widget.linkKey as GlobalKey).currentState as RefreshProcessor)
.endRefresh();
}
@override
void onModeChange(RefreshStatus mode) {
// TODO: implement onModeChange
((widget.linkKey as GlobalKey).currentState as RefreshProcessor)
.onModeChange(mode);
}
@override
void onOffsetChange(double offset) {
// TODO: implement onOffsetChange
((widget.linkKey as GlobalKey).currentState as RefreshProcessor)
.onOffsetChange(offset);
}
@override
Future<void> readyToRefresh() {
// TODO: implement readyToRefresh
return ((widget.linkKey as GlobalKey).currentState as RefreshProcessor)
.readyToRefresh();
}
@override
Widget buildContent(BuildContext context, RefreshStatus mode) {
// TODO: implement buildContent
return Container();
}
}
/// enable footer link other footer place outside the viewport
class LinkFooter extends LoadIndicator {
/// the key that widget outside viewport indicator
final Key linkKey;
const LinkFooter(
......@@ -87,7 +79,6 @@ class LinkFooter extends LoadIndicator {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return _LinkFooterState();
}
}
......@@ -95,21 +86,18 @@ class LinkFooter extends LoadIndicator {
class _LinkFooterState extends LoadIndicatorState<LinkFooter> {
@override
void onModeChange(LoadStatus mode) {
// TODO: implement onModeChange
((widget.linkKey as GlobalKey).currentState as LoadingProcessor)
.onModeChange(mode);
}
@override
void onOffsetChange(double offset) {
// TODO: implement onOffsetChange
((widget.linkKey as GlobalKey).currentState as LoadingProcessor)
.onOffsetChange(offset);
}
@override
Widget buildContent(BuildContext context, LoadStatus mode) {
// TODO: implement buildContent
return Container();
}
}
......@@ -50,8 +50,6 @@ class MaterialClassicHeader extends RefreshIndicator {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return _MaterialClassicHeaderState();
}
}
......@@ -67,7 +65,6 @@ class _MaterialClassicHeaderState
@override
void initState() {
// TODO: implement initState
_valueAni = AnimationController(
vsync: this,
value: 0.0,
......@@ -94,7 +91,6 @@ class _MaterialClassicHeaderState
@override
Widget buildContent(BuildContext context, RefreshStatus mode) {
// TODO: implement buildContent
return _buildIndicator(widget.backgroundColor ?? Colors.white);
}
......@@ -121,7 +117,6 @@ class _MaterialClassicHeaderState
@override
void onOffsetChange(double offset) {
// TODO: implement onOffsetChange
if (!floating) {
_valueAni.value = offset / configuration.headerTriggerDistance;
_positionController.value = offset / configuration.headerTriggerDistance;
......@@ -130,7 +125,6 @@ class _MaterialClassicHeaderState
@override
void onModeChange(RefreshStatus mode) {
// TODO: implement onModeChange
if (mode == RefreshStatus.refreshing) {
_positionController.value = widget.distance / widget.height;
_scaleFactor.value = 1;
......@@ -140,7 +134,6 @@ class _MaterialClassicHeaderState
@override
void resetValue() {
// TODO: implement resetValue
_scaleFactor.value = 1.0;
_positionController.value = 0.0;
_valueAni.value = 0.0;
......@@ -170,19 +163,16 @@ class _MaterialClassicHeaderState
@override
Future<void> readyToRefresh() {
// TODO: implement readyToRefresh
return _positionController.animateTo(widget.distance / widget.height);
}
@override
Future<void> endRefresh() {
// TODO: implement endRefresh
return _scaleFactor.animateTo(0.0);
}
@override
void dispose() {
// TODO: implement dispose
_valueAni.dispose();
_scaleFactor.dispose();
_positionController.dispose();
......@@ -212,7 +202,6 @@ class WaterDropMaterialHeader extends MaterialClassicHeader {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return _WaterDropMaterialHeaderState();
}
}
......@@ -223,7 +212,6 @@ class _WaterDropMaterialHeaderState extends _MaterialClassicHeaderState {
@override
void initState() {
// TODO: implement initState
super.initState();
_bezierController = AnimationController(
vsync: this,
......@@ -243,7 +231,6 @@ class _WaterDropMaterialHeaderState extends _MaterialClassicHeaderState {
@override
void didChangeDependencies() {
// TODO: implement didChangeDependencies
super.didChangeDependencies();
final ThemeData theme = Theme.of(context);
_valueColor = _positionController.drive(
......@@ -265,7 +252,6 @@ class _WaterDropMaterialHeaderState extends _MaterialClassicHeaderState {
@override
Future<void> readyToRefresh() {
// TODO: implement readyToRefresh
_bezierController.value = 1.01;
_showWater = true;
_bezierController.animateTo(1.5,
......@@ -280,28 +266,24 @@ class _WaterDropMaterialHeaderState extends _MaterialClassicHeaderState {
@override
Future<void> endRefresh() {
// TODO: implement endRefresh
_showWater = false;
return super.endRefresh();
}
@override
void resetValue() {
// TODO: implement resetValue
_bezierController.reset();
super.resetValue();
}
@override
void dispose() {
// TODO: implement dispose
_bezierController.dispose();
super.dispose();
}
@override
void onOffsetChange(double offset) {
// TODO: implement onOffsetChange
offset = offset > 80.0 ? 80.0 : offset;
if (!floating) {
......@@ -315,7 +297,6 @@ class _WaterDropMaterialHeaderState extends _MaterialClassicHeaderState {
@override
Widget buildContent(BuildContext context, RefreshStatus mode) {
// TODO: implement buildContent
return Container(
child: Stack(
children: <Widget>[
......@@ -362,7 +343,6 @@ class _WaterPainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
// TODO: implement paint
final Paint paint = Paint();
paint.color = color;
final Path path = Path();
......@@ -378,7 +358,6 @@ class _WaterPainter extends CustomPainter {
@override
bool shouldRepaint(_WaterPainter oldDelegate) {
// TODO: implement shouldRepaint
return this != oldDelegate || offset != oldDelegate.offset;
}
}
......@@ -393,7 +372,6 @@ class _BezierPainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
// TODO: implement paint
final double middleX = size.width / 2;
final Paint paint = Paint();
paint.color = color;
......@@ -424,7 +402,6 @@ class _BezierPainter extends CustomPainter {
@override
bool shouldRepaint(_BezierPainter oldDelegate) {
// TODO: implement shouldRepaint
return this != oldDelegate || oldDelegate.value != value;
}
}
......@@ -112,7 +112,6 @@ class TwoLevelHeader extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return ClassicHeader(
refreshStyle: displayAlignment == TwoLevelDisplayAlignment.fromBottom
? RefreshStyle.Follow
......
......@@ -51,7 +51,6 @@ class WaterDropHeader extends RefreshIndicator {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return _WaterDropHeaderState();
}
}
......@@ -63,7 +62,6 @@ class _WaterDropHeaderState extends RefreshIndicatorState<WaterDropHeader>
@override
void onOffsetChange(double offset) {
// TODO: implement onOffsetChange
final double realOffset =
offset - 44.0; //55.0 mean circleHeight(24) + originH (20) in Painter
// when readyTorefresh
......@@ -73,14 +71,12 @@ class _WaterDropHeaderState extends RefreshIndicatorState<WaterDropHeader>
@override
Future<void> readyToRefresh() {
// TODO: implement readyToRefresh
_dismissCtl.animateTo(0.0);
return _animationController.animateTo(0.0);
}
@override
void initState() {
// TODO: implement initState
_dismissCtl = AnimationController(
vsync: this, duration: Duration(milliseconds: 400), value: 1.0);
_animationController = AnimationController(
......@@ -93,13 +89,11 @@ class _WaterDropHeaderState extends RefreshIndicatorState<WaterDropHeader>
@override
bool needReverseAll() {
// TODO: implement needReverseAll
return false;
}
@override
Widget buildContent(BuildContext context, RefreshStatus mode) {
// TODO: implement buildContent
Widget child;
if (mode == RefreshStatus.refreshing) {
child = widget.refresh ??
......@@ -196,14 +190,12 @@ class _WaterDropHeaderState extends RefreshIndicatorState<WaterDropHeader>
@override
void resetValue() {
// TODO: implement resetValue
_animationController.reset();
_dismissCtl.value = 1.0;
}
@override
void dispose() {
// TODO: implement dispose
_dismissCtl.dispose();
_animationController.dispose();
super.dispose();
......@@ -270,7 +262,6 @@ class _QqPainter extends CustomPainter {
@override
bool shouldRepaint(CustomPainter oldDelegate) {
// TODO: implement shouldRepaint
return oldDelegate != this;
}
}
......@@ -77,7 +77,6 @@ abstract class LoadIndicator extends StatefulWidget {
///
/// @override
/// void initState() {
/// // TODO: implement initState
/// _scaleAnimation = AnimationController(vsync: this);
/// _offsetController = AnimationController(
/// vsync: this, duration: Duration(milliseconds: 1000));
......@@ -87,7 +86,6 @@ abstract class LoadIndicator extends StatefulWidget {
///
/// @override
/// void onOffsetChange(double offset) {
/// // TODO: implement onOffsetChange
/// if (!floating) {
/// _scaleAnimation.value = offset / 80.0;
/// }
......@@ -96,14 +94,12 @@ abstract class LoadIndicator extends StatefulWidget {
///
/// @override
/// void resetValue() {
/// // TODO: implement handleModeChange
/// _scaleAnimation.value = 0.0;
/// _offsetController.value = 0.0;
/// }
///
/// @override
/// void dispose() {
/// // TODO: implement dispose
/// _scaleAnimation.dispose();
/// _offsetController.dispose();
/// super.dispose();
......@@ -111,13 +107,11 @@ abstract class LoadIndicator extends StatefulWidget {
///
/// @override
/// Future<void> endRefresh() {
/// // TODO: implement endRefresh
/// return _offsetController.animateTo(1.0).whenComplete(() {});
/// }
///
/// @override
/// Widget buildContent(BuildContext context, RefreshStatus mode) {
/// // TODO: implement buildContent
/// return SlideTransition(
/// child: ScaleTransition(
/// child: (mode != RefreshStatus.idle || mode != RefreshStatus.canRefresh)
......@@ -150,7 +144,6 @@ abstract class RefreshIndicatorState<T extends RefreshIndicator>
@override
void _handleOffsetChange() {
// TODO: implement _handleOffsetChange
super._handleOffsetChange();
final double overscrollPast = _calculateScrollOffset();
onOffsetChange(overscrollPast);
......@@ -376,7 +369,6 @@ abstract class LoadIndicatorState<T extends LoadIndicator> extends State<T>
@override
Future endLoading() {
// TODO: implement endLoading
return Future.delayed(Duration(milliseconds: 0));
}
......@@ -524,21 +516,18 @@ abstract class LoadIndicatorState<T extends LoadIndicator> extends State<T>
@override
void didChangeDependencies() {
// TODO: implement didChangeDependencies
super.didChangeDependencies();
_lastMode = mode;
}
@override
void dispose() {
// TODO: implement dispose
_position?.isScrollingNotifier?.removeListener(_listenScrollEnd);
super.dispose();
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return SliverLoading(
hideWhenNotFull: configuration.hideFooterWhenNotFull,
floating: widget.loadStyle == LoadStyle.ShowAlways
......@@ -627,9 +616,7 @@ mixin IndicatorStateMixin<T extends StatefulWidget, V> on State<T> {
void _updateListener() {
configuration = RefreshConfiguration.of(context);
refresher = SmartRefresher.of(context);
ValueNotifier<V> newMode = V == RefreshStatus
? refresher.controller.headerMode
: refresher.controller.footerMode;
ValueNotifier<V> newMode = (V == RefreshStatus ? refresher.controller.headerMode : refresher.controller.footerMode) as ValueNotifier<V>;
final ScrollPosition newPosition = Scrollable.of(context).position;
if (newMode != _mode) {
_mode?.removeListener(_handleModeChange);
......@@ -646,7 +633,6 @@ mixin IndicatorStateMixin<T extends StatefulWidget, V> on State<T> {
@override
void initState() {
// TODO: implement initState
if (V == RefreshStatus) {
SmartRefresher.of(context)?.controller?.headerMode?.value =
RefreshStatus.idle;
......@@ -656,7 +642,6 @@ mixin IndicatorStateMixin<T extends StatefulWidget, V> on State<T> {
@override
void dispose() {
// TODO: implement dispose
//1.3.7: here need to careful after add asSliver builder
disposeListener();
super.dispose();
......@@ -664,14 +649,12 @@ mixin IndicatorStateMixin<T extends StatefulWidget, V> on State<T> {
@override
void didChangeDependencies() {
// TODO: implement didChangeDependencies
_updateListener();
super.didChangeDependencies();
}
@override
void didUpdateWidget(T oldWidget) {
// TODO: implement didUpdateWidget
// needn't to update _headerMode,because it's state will never change
// 1.3.7: here need to careful after add asSliver builder
_updateListener();
......
......@@ -86,7 +86,6 @@ class RefreshPhysics extends ScrollPhysics {
@override
bool shouldAcceptUserOffset(ScrollMetrics position) {
// TODO: implement shouldAcceptUserOffset
if (parent is NeverScrollableScrollPhysics) {
return false;
}
......@@ -98,7 +97,6 @@ class RefreshPhysics extends ScrollPhysics {
// will lead to whether the newPhysics should replace oldPhysics,If flutter can provide a method such as "shouldUpdate",
// It can work perfectly.
@override
// TODO: implement runtimeType
Type get runtimeType {
if (updateFlag == 0) {
return RefreshPhysics;
......@@ -109,7 +107,6 @@ class RefreshPhysics extends ScrollPhysics {
@override
double applyPhysicsToUserOffset(ScrollMetrics position, double offset) {
// TODO: implement applyPhysicsToUserOffset
viewportRender ??=
findViewport(controller.position?.context?.storageContext);
if (controller.headerMode.value == RefreshStatus.twoLeveling) {
......@@ -261,7 +258,6 @@ class RefreshPhysics extends ScrollPhysics {
@override
Simulation createBallisticSimulation(
ScrollMetrics position, double velocity) {
// TODO: implement createBallisticSimulation
viewportRender ??=
findViewport(controller.position?.context?.storageContext);
......@@ -287,9 +283,7 @@ class RefreshPhysics extends ScrollPhysics {
return BouncingScrollSimulation(
spring: springDescription ?? spring,
position: position.pixels,
// -1.0 avoid stop springing back ,and release gesture
velocity: velocity * 0.91,
// TODO(abarth): We should move this constant closer to the drag end.
leadingExtent: position.minScrollExtent,
trailingExtent: controller.headerMode.value == RefreshStatus.twoLeveling
? 0.0
......
......@@ -125,12 +125,10 @@ class RenderSliverRefresh extends RenderSliverSingleBoxAdapter {
@override
void performResize() {
// TODO: implement performResize
super.performResize();
}
@override
// TODO: implement centerOffsetAdjustment
double get centerOffsetAdjustment {
if (refreshStyle == RefreshStyle.Front) {
final RenderViewportBase renderViewport = parent;
......@@ -141,7 +139,6 @@ class RenderSliverRefresh extends RenderSliverSingleBoxAdapter {
@override
void layout(Constraints constraints, {bool parentUsesSize = false}) {
// TODO: implement layout
if (refreshStyle == RefreshStyle.Front) {
final RenderViewportBase renderViewport = parent;
super.layout(
......
......@@ -274,16 +274,15 @@ class SmartRefresher extends StatefulWidget {
super(key: key);
static SmartRefresher of(BuildContext context) {
return context?.ancestorWidgetOfExactType(SmartRefresher);
return context?.findAncestorWidgetOfExactType<SmartRefresher>();
}
static SmartRefresherState ofState(BuildContext context) {
return context?.ancestorStateOfType(TypeMatcher<SmartRefresherState>());
return context?.findAncestorStateOfType<SmartRefresherState>();
}
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return SmartRefresherState();
}
}
......@@ -489,7 +488,6 @@ class SmartRefresherState extends State<SmartRefresher> {
@override
void didUpdateWidget(SmartRefresher oldWidget) {
// TODO: implement didUpdateWidget
if (widget.controller != oldWidget.controller) {
widget.controller.headerMode.value =
oldWidget.controller.headerMode.value;
......@@ -501,7 +499,6 @@ class SmartRefresherState extends State<SmartRefresher> {
@override
void didChangeDependencies() {
// TODO: implement didChangeDependencies
super.didChangeDependencies();
if (_ifNeedUpdatePhysics()) {
_updatePhysics = !_updatePhysics;
......@@ -510,7 +507,6 @@ class SmartRefresherState extends State<SmartRefresher> {
@override
void initState() {
// TODO: implement initState
if (widget.controller.initialRefresh) {
WidgetsBinding.instance.addPostFrameCallback((_) {
// if mounted,it avoid one situation: when init done,then dispose the widget before build.
......@@ -523,7 +519,6 @@ class SmartRefresherState extends State<SmartRefresher> {
@override
void dispose() {
// TODO: implement dispose
widget.controller._detachPosition();
super.dispose();
}
......@@ -1004,7 +999,7 @@ class RefreshConfiguration extends InheritedWidget {
RefreshConfiguration.of(context).shouldFooterFollowWhenNotFull;
static RefreshConfiguration of(BuildContext context) {
return context.inheritFromWidgetOfExactType(RefreshConfiguration);
return context.dependOnInheritedWidgetOfExactType<RefreshConfiguration>();
}
@override
......
name: pull_to_refresh
description: a widget provided to the flutter scroll component drop-down refresh and pull up load.
version: 1.6.3
version: 2.5.0
homepage: https://github.com/peng8350/flutter_pulltorefresh
environment:
sdk: ">=2.1.0 <3.0.0"
flutter: ">=0.1.4 <2.0.0"
sdk: ">=2.7.0 <3.0.0"
flutter: ">=1.17.0"
dependencies:
flutter:
......
......@@ -12,7 +12,6 @@ class TestHeader extends RefreshIndicator {
const TestHeader();
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return _TestHeaderState();
}
}
......@@ -20,7 +19,6 @@ class TestHeader extends RefreshIndicator {
class _TestHeaderState extends RefreshIndicatorState<TestHeader> {
@override
Widget buildContent(BuildContext context, RefreshStatus mode) {
// TODO: implement buildContent
return Text(mode == RefreshStatus.idle
? "idle"
: mode == RefreshStatus.refreshing
......@@ -45,7 +43,6 @@ class TestFooter extends LoadIndicator {
const TestFooter();
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return _TestFooterState();
}
}
......@@ -53,7 +50,6 @@ class TestFooter extends LoadIndicator {
class _TestFooterState extends LoadIndicatorState<TestFooter> {
@override
Widget buildContent(BuildContext context, LoadStatus mode) {
// TODO: implement buildContent
return Text(mode == LoadStatus.failed
? "failed"
: mode == LoadStatus.loading
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment