├── .github
└── FUNDING.yml
├── .gitignore
├── CHANGELOG.md
├── Droid
├── Assets
│ └── AboutAssets.txt
├── MainActivity.cs
├── Properties
│ ├── AndroidManifest.xml
│ └── AssemblyInfo.cs
├── RefreshSample.Droid.csproj
└── Resources
│ ├── AboutResources.txt
│ ├── Resource.designer.cs
│ ├── drawable-hdpi
│ └── icon.png
│ ├── drawable-xhdpi
│ └── icon.png
│ ├── drawable-xxhdpi
│ └── icon.png
│ ├── drawable
│ └── icon.png
│ ├── values-v21
│ └── styles.xml
│ └── values
│ └── styles.xml
├── PullToRefresh
└── PullToRefresh.Standard
│ ├── PullToRefresh.csproj
│ ├── PullToRefreshLayout.shared.cs
│ ├── PullToRefreshLayoutRenderer.android.cs
│ └── PullToRefreshLayoutRenderer.ios.cs
├── PullToRefreshLayout.nuspec
├── PullToRefreshLayout.sln
├── README.md
├── RefreshSample.userprefs
├── RefreshSample
├── App.cs
├── RefreshSample.csproj
├── ViewModels
│ └── TestViewModel.cs
└── Views
│ ├── DisposeCrashPage.cs
│ ├── GridPage.cs
│ ├── ListViewPage.cs
│ ├── ScrollViewPage.cs
│ ├── ScrollViewPageManual.cs
│ ├── ScrollViewXamlPage.xaml
│ ├── ScrollViewXamlPage.xaml.cs
│ ├── StackLayoutPage.cs
│ ├── TabbedPage1.xaml
│ └── TabbedPage1.xaml.cs
├── appveyor.yml
├── build.cake
├── build.ps1
├── build.sh
├── cake.packages.config
├── demo.gif
└── iOS
├── AppDelegate.cs
├── Entitlements.plist
├── Info.plist
├── Main.cs
├── RefreshSample.iOS.csproj
└── Resources
├── Images.xcassets
└── AppIcons.appiconset
│ └── Contents.json
└── LaunchScreen.xib
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | patreon: mergeconflictfm
2 | custom: https://www.buymeacoffee.com/jamesmontemagno
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | #################
2 | ## Eclipse
3 | #################
4 |
5 | .vs/
6 |
7 | *.pydevproject
8 | .project
9 | .metadata
10 | bin/
11 | tmp/
12 | *.tmp
13 | *.bak
14 | *.swp
15 | *~.nib
16 | local.properties
17 | .classpath
18 | .settings/
19 | .loadpath
20 | .nuget/
21 |
22 | # External tool builders
23 | .externalToolBuilders/
24 |
25 | # Locally stored "Eclipse launch configurations"
26 | *.launch
27 |
28 | # CDT-specific
29 | .cproject
30 |
31 | # PDT-specific
32 | .buildpath
33 |
34 |
35 | #################
36 | ## Visual Studio
37 | #################
38 |
39 | ## Ignore Visual Studio temporary files, build results, and
40 | ## files generated by popular Visual Studio add-ons.
41 |
42 | # User-specific files
43 | *.suo
44 | *.user
45 | *.sln.docstates
46 |
47 | # Build results
48 |
49 | [Dd]ebug/
50 | [Rr]elease/
51 | x64/
52 | build/
53 | [Bb]in/
54 | [Oo]bj/
55 | [Pp]ackages/
56 |
57 | # MSTest test Results
58 | [Tt]est[Rr]esult*/
59 | [Bb]uild[Ll]og.*
60 |
61 | *_i.c
62 | *_p.c
63 | *.ilk
64 | *.meta
65 | *.obj
66 | *.pch
67 | *.pdb
68 | *.pgc
69 | *.pgd
70 | *.rsp
71 | *.sbr
72 | *.tlb
73 | *.tli
74 | *.tlh
75 | *.tmp
76 | *.tmp_proj
77 | *.log
78 | *.vspscc
79 | *.vssscc
80 | .builds
81 | *.pidb
82 | *.log
83 | *.scc
84 |
85 | # Visual C++ cache files
86 | ipch/
87 | *.aps
88 | *.ncb
89 | *.opensdf
90 | *.sdf
91 | *.cachefile
92 |
93 | # Visual Studio profiler
94 | *.psess
95 | *.vsp
96 | *.vspx
97 |
98 | # Guidance Automation Toolkit
99 | *.gpState
100 |
101 | # ReSharper is a .NET coding add-in
102 | _ReSharper*/
103 | *.[Rr]e[Ss]harper
104 |
105 | # TeamCity is a build add-in
106 | _TeamCity*
107 |
108 | # DotCover is a Code Coverage Tool
109 | *.dotCover
110 |
111 | # NCrunch
112 | *.ncrunch*
113 | .*crunch*.local.xml
114 |
115 | # Installshield output folder
116 | [Ee]xpress/
117 |
118 | # DocProject is a documentation generator add-in
119 | DocProject/buildhelp/
120 | DocProject/Help/*.HxT
121 | DocProject/Help/*.HxC
122 | DocProject/Help/*.hhc
123 | DocProject/Help/*.hhk
124 | DocProject/Help/*.hhp
125 | DocProject/Help/Html2
126 | DocProject/Help/html
127 |
128 | # Click-Once directory
129 | publish/
130 |
131 | # Publish Web Output
132 | *.Publish.xml
133 | *.pubxml
134 |
135 | # NuGet Packages Directory
136 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line
137 | #packages/
138 |
139 | # Windows Azure Build Output
140 | csx
141 | *.build.csdef
142 |
143 | # Windows Store app package directory
144 | AppPackages/
145 |
146 | # Others
147 | sql/
148 | *.Cache
149 | ClientBin/
150 | [Ss]tyle[Cc]op.*
151 | ~$*
152 | *~
153 | *.dbmdl
154 | *.[Pp]ublish.xml
155 | *.pfx
156 | *.publishsettings
157 |
158 | # RIA/Silverlight projects
159 | Generated_Code/
160 |
161 | # Backup & report files from converting an old project file to a newer
162 | # Visual Studio version. Backup files are not needed, because we have git ;-)
163 | _UpgradeReport_Files/
164 | Backup*/
165 | UpgradeLog*.XML
166 | UpgradeLog*.htm
167 |
168 | # SQL Server files
169 | App_Data/*.mdf
170 | App_Data/*.ldf
171 |
172 | #############
173 | ## Windows detritus
174 | #############
175 |
176 | # Windows image file caches
177 | Thumbs.db
178 | ehthumbs.db
179 |
180 | # Folder config file
181 | Desktop.ini
182 |
183 | # Recycle Bin used on file shares
184 | $RECYCLE.BIN/
185 |
186 | # Mac crap
187 | .DS_Store
188 |
189 |
190 | #############
191 | ## Python
192 | #############
193 |
194 | *.py[co]
195 |
196 | # Packages
197 | *.egg
198 | *.egg-info
199 | dist/
200 | build/
201 | eggs/
202 | parts/
203 | var/
204 | sdist/
205 | develop-eggs/
206 | .installed.cfg
207 |
208 | # Installer logs
209 | pip-log.txt
210 |
211 | # Unit test / coverage reports
212 | .coverage
213 | .tox
214 |
215 | #Translations
216 | *.mo
217 |
218 | #Mr Developer
219 | .mr.developer.cfg
220 | tools/**/*.*
221 | .vs/PullToRefreshLayout/v15/sqlite3/storage.ide
222 | *.ide-journal
223 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## 2.4.0
2 | * Multitarget and Azure DevOps
3 |
4 | ## 2.2.3
5 | * Fixes #45 Extra space on iOS
6 | * Fixes #37 Content Too Low
7 | * Fixes #27 Not whoswing when programmatically
8 | * Fixes #26 Missing RefreshCommandParameter
9 | * Fixes #3 iOS set to false
10 | * Update to newer Forms
11 |
12 | ## 2.0.1
13 | * Update Xamarin.Forms
14 | * .NET Standard Libary
15 | * Add command parameter #26
16 | * Fix for spinner now showing when setting IsRefreshing from code behind #27/#3
17 |
--------------------------------------------------------------------------------
/Droid/Assets/AboutAssets.txt:
--------------------------------------------------------------------------------
1 | Any raw assets you want to be deployed with your application can be placed in
2 | this directory (and child directories) and given a Build Action of "AndroidAsset".
3 |
4 | These files will be deployed with your package and will be accessible using Android's
5 | AssetManager, like this:
6 |
7 | public class ReadAsset : Activity
8 | {
9 | protected override void OnCreate (Bundle bundle)
10 | {
11 | base.OnCreate (bundle);
12 |
13 | InputStream input = Assets.Open ("my_asset.txt");
14 | }
15 | }
16 |
17 | Additionally, some Android functions will automatically load asset files:
18 |
19 | Typeface tf = Typeface.CreateFromAsset (Context.Assets, "fonts/samplefont.ttf");
20 |
--------------------------------------------------------------------------------
/Droid/MainActivity.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 Refractored LLC & James Montemagno:
3 | * http://github.com/JamesMontemagno
4 | * http://twitter.com/JamesMontemagno
5 | * http://refractored.com
6 | *
7 | * The MIT License (MIT) see GitHub For more information
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | using Android.App;
16 | using Android.Content.PM;
17 | using Android.OS;
18 | using Android.Graphics.Drawables;
19 | using Refractored.XamForms.PullToRefresh.Droid;
20 |
21 | namespace RefreshSample.Droid
22 | {
23 | [Activity(Label = "Pull to Refresh!", Icon = "@drawable/icon", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
24 | public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsApplicationActivity
25 | {
26 | protected override void OnCreate(Bundle bundle)
27 | {
28 | base.OnCreate(bundle);
29 |
30 | global::Xamarin.Forms.Forms.Init(this, bundle);
31 |
32 | PullToRefreshLayoutRenderer.Init();
33 |
34 | LoadApplication(new App());
35 |
36 | if((int)Build.VERSION.SdkInt >= 21)
37 | ActionBar.SetIcon ( new ColorDrawable (Resources.GetColor (Android.Resource.Color.Transparent)));
38 | }
39 | }
40 | }
41 |
42 |
--------------------------------------------------------------------------------
/Droid/Properties/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/Droid/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using Android.App;
4 |
5 | // Information about this assembly is defined by the following attributes.
6 | // Change them to the values specific to your project.
7 |
8 | [assembly: AssemblyTitle("RefreshSample.Droid")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("")]
13 | [assembly: AssemblyCopyright("jamesmontemagno")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
18 | // The form "{Major}.{Minor}.*" will automatically update the build and revision,
19 | // and "{Major}.{Minor}.{Build}.*" will update just the revision.
20 |
21 | [assembly: AssemblyVersion("1.0.1")]
22 |
23 | // The following attributes are used to specify the signing key for the assembly,
24 | // if desired. See the Mono documentation for more information about signing.
25 |
26 | //[assembly: AssemblyDelaySign(false)]
27 | //[assembly: AssemblyKeyFile("")]
28 |
29 |
--------------------------------------------------------------------------------
/Droid/RefreshSample.Droid.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | AnyCPU
6 | {EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
7 | {FED4CE90-0F61-492D-94A1-1B3229A6A75B}
8 | Library
9 | RefreshSample.Droid
10 | Assets
11 | Resources
12 | Resource
13 | Resources\Resource.designer.cs
14 | True
15 | RefreshSample.Droid
16 | Properties\AndroidManifest.xml
17 | v9.0
18 |
19 |
20 |
21 |
22 | true
23 | full
24 | false
25 | bin\Debug
26 | DEBUG;
27 | prompt
28 | 4
29 | None
30 | false
31 |
32 |
33 | full
34 | true
35 | bin\Release
36 | prompt
37 | 4
38 | false
39 | false
40 | armeabi-v7a;x86
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 | {10ab134c-d1b9-4589-8121-3ceb3d21d096}
51 | PullToRefresh
52 |
53 |
54 | {E8A3B142-4FDA-44D2-AC4C-2578150D4E27}
55 | RefreshSample
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 | 28.0.0.3
82 |
83 |
84 | 28.0.0.3
85 |
86 |
87 | 28.0.0.3
88 |
89 |
90 | 28.0.0.3
91 |
92 |
93 | 0.4.11
94 |
95 |
96 | 4.3.0.991211
97 |
98 |
99 |
100 |
--------------------------------------------------------------------------------
/Droid/Resources/AboutResources.txt:
--------------------------------------------------------------------------------
1 | Images, layout descriptions, binary blobs and string dictionaries can be included
2 | in your application as resource files. Various Android APIs are designed to
3 | operate on the resource IDs instead of dealing with images, strings or binary blobs
4 | directly.
5 |
6 | For example, a sample Android app that contains a user interface layout (main.axml),
7 | an internationalization string table (strings.xml) and some icons (drawable-XXX/icon.png)
8 | would keep its resources in the "Resources" directory of the application:
9 |
10 | Resources/
11 | drawable/
12 | icon.png
13 |
14 | layout/
15 | main.axml
16 |
17 | values/
18 | strings.xml
19 |
20 | In order to get the build system to recognize Android resources, set the build action to
21 | "AndroidResource". The native Android APIs do not operate directly with filenames, but
22 | instead operate on resource IDs. When you compile an Android application that uses resources,
23 | the build system will package the resources for distribution and generate a class called "R"
24 | (this is an Android convention) that contains the tokens for each one of the resources
25 | included. For example, for the above Resources layout, this is what the R class would expose:
26 |
27 | public class R {
28 | public class drawable {
29 | public const int icon = 0x123;
30 | }
31 |
32 | public class layout {
33 | public const int main = 0x456;
34 | }
35 |
36 | public class strings {
37 | public const int first_string = 0xabc;
38 | public const int second_string = 0xbcd;
39 | }
40 | }
41 |
42 | You would then use R.drawable.icon to reference the drawable/icon.png file, or R.layout.main
43 | to reference the layout/main.axml file, or R.strings.first_string to reference the first
44 | string in the dictionary file values/strings.xml.
45 |
--------------------------------------------------------------------------------
/Droid/Resources/drawable-hdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jamesmontemagno/Xamarin.Forms-PullToRefreshLayout/661faad38ad10bc7f8d5774c99cf989356fcbd4e/Droid/Resources/drawable-hdpi/icon.png
--------------------------------------------------------------------------------
/Droid/Resources/drawable-xhdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jamesmontemagno/Xamarin.Forms-PullToRefreshLayout/661faad38ad10bc7f8d5774c99cf989356fcbd4e/Droid/Resources/drawable-xhdpi/icon.png
--------------------------------------------------------------------------------
/Droid/Resources/drawable-xxhdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jamesmontemagno/Xamarin.Forms-PullToRefreshLayout/661faad38ad10bc7f8d5774c99cf989356fcbd4e/Droid/Resources/drawable-xxhdpi/icon.png
--------------------------------------------------------------------------------
/Droid/Resources/drawable/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jamesmontemagno/Xamarin.Forms-PullToRefreshLayout/661faad38ad10bc7f8d5774c99cf989356fcbd4e/Droid/Resources/drawable/icon.png
--------------------------------------------------------------------------------
/Droid/Resources/values-v21/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
14 |
--------------------------------------------------------------------------------
/Droid/Resources/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 | #3498db
3 | #2c3e50
4 | #FFC107
5 |
6 |
10 |
11 |
14 |
15 |
19 |
20 |
23 |
24 |
--------------------------------------------------------------------------------
/PullToRefresh/PullToRefresh.Standard/PullToRefresh.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | netstandard1.0;netstandard2.0;MonoAndroid81;MonoAndroid90;Xamarin.iOS10
4 | Refractored.XamForms.PullToRefresh
5 | Refractored.XamForms.PullToRefresh
6 | $(AssemblyName) ($(TargetFramework))
7 | 1.0.0.0
8 | 1.0.0.0
9 | 1.0.0.0
10 | James Montemagno
11 | Refractored.XamForms.PullToRefresh
12 | true
13 | http://www.refractored.com/images/pull_to_refresh.png
14 | https://github.com/jamesmontemagno/Xamarin.Forms-PullToRefreshLayout
15 | JamesMontemagno
16 | https://github.com/jamesmontemagno/Xamarin.Forms-PullToRefreshLayout
17 | Enhanced Pull To Refresh Layout for Xamarin.Forms
18 | xamarin, pcl, xam.pcl, android, xamarin.forms, ios, pull to refresh, refresh, swipe
19 | PullToRefresh Layout for Xamarin.Forms
20 |
21 | Add Pull to Refresh to ScrollView or group a ListView. See Project for more details
22 | Ensure you call PullToRefreshLayoutRenderer.Init() on each platform!
23 | Built against: 4.2.0.709249
24 |
25 | Copyright 2019
26 | https://github.com/jamesmontemagno/Xamarin.Forms-PullToRefreshLayout
27 | See: https://github.com/jamesmontemagno/Xamarin.Forms-PullToRefreshLayout
28 |
29 | en
30 | default
31 | false
32 |
33 | $(DefineConstants);
34 |
35 |
36 |
37 | full
38 | true
39 |
40 |
41 | pdbonly
42 | true
43 | true
44 |
45 |
46 | portable
47 |
48 | true
49 |
50 | true
51 |
52 | $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/PullToRefresh/PullToRefresh.Standard/PullToRefreshLayout.shared.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 Refractored LLC & James Montemagno:
3 | * http://github.com/JamesMontemagno
4 | * http://twitter.com/JamesMontemagno
5 | * http://refractored.com
6 | *
7 | * The MIT License (MIT) see GitHub For more information
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | using System;
17 | using System.Windows.Input;
18 | using Xamarin.Forms;
19 |
20 | namespace Refractored.XamForms.PullToRefresh
21 | {
22 | ///
23 | /// Pull to refresh layout.
24 | ///
25 | public class PullToRefreshLayout : ContentView
26 | {
27 | ///
28 | /// Initializes a new instance of the class.
29 | ///
30 | public PullToRefreshLayout()
31 | {
32 | IsClippedToBounds = true;
33 | VerticalOptions = LayoutOptions.FillAndExpand;
34 | HorizontalOptions = LayoutOptions.FillAndExpand;
35 | }
36 |
37 | ///
38 | /// The is refreshing property.
39 | ///
40 | public static readonly BindableProperty IsRefreshingProperty =
41 | BindableProperty.Create(nameof(IsRefreshing), typeof(bool), typeof(PullToRefreshLayout), false);
42 |
43 | ///
44 | /// Gets or sets a value indicating whether this instance is refreshing.
45 | ///
46 | /// true if this instance is refreshing; otherwise, false.
47 | public bool IsRefreshing
48 | {
49 | get { return (bool)GetValue(IsRefreshingProperty); }
50 | set
51 | {
52 | if ((bool)GetValue(IsRefreshingProperty) == value)
53 | OnPropertyChanged(nameof(IsRefreshing));
54 |
55 | SetValue(IsRefreshingProperty, value);
56 | }
57 | }
58 |
59 | ///
60 | /// The is pull to refresh enabled property.
61 | ///
62 | public static readonly BindableProperty IsPullToRefreshEnabledProperty =
63 | BindableProperty.Create(nameof(IsPullToRefreshEnabled), typeof(bool), typeof(PullToRefreshLayout), true);
64 |
65 | ///
66 | /// Gets or sets a value indicating whether this instance is pull to refresh enabled.
67 | ///
68 | /// true if this instance is pull to refresh enabled; otherwise, false.
69 | public bool IsPullToRefreshEnabled
70 | {
71 | get { return (bool)GetValue(IsPullToRefreshEnabledProperty); }
72 | set { SetValue(IsPullToRefreshEnabledProperty, value); }
73 | }
74 |
75 |
76 | ///
77 | /// The refresh command property.
78 | ///
79 | public static readonly BindableProperty RefreshCommandProperty =
80 | BindableProperty.Create(nameof(RefreshCommand), typeof(ICommand), typeof(PullToRefreshLayout));
81 |
82 | ///
83 | /// Gets or sets the refresh command.
84 | ///
85 | /// The refresh command.
86 | public ICommand RefreshCommand
87 | {
88 | get { return (ICommand)GetValue(RefreshCommandProperty); }
89 | set { SetValue(RefreshCommandProperty, value); }
90 | }
91 |
92 | ///
93 | /// Gets the Refresh command
94 | ///
95 | public static readonly BindableProperty RefreshCommandParameterProperty =
96 | BindableProperty.Create(nameof(RefreshCommandParameter),
97 | typeof(object),
98 | typeof(PullToRefreshLayout),
99 | null,
100 | propertyChanged: (bindable, oldvalue, newvalue) => ((PullToRefreshLayout)bindable).RefreshCommandCanExecuteChanged(bindable, EventArgs.Empty));
101 |
102 | ///
103 | /// Gets or sets the Refresh command parameter
104 | ///
105 | public object RefreshCommandParameter
106 | {
107 | get { return GetValue(RefreshCommandParameterProperty); }
108 | set { SetValue(RefreshCommandParameterProperty, value); }
109 | }
110 |
111 | ///
112 | /// Executes if enabled or not based on can execute changed
113 | ///
114 | ///
115 | ///
116 | void RefreshCommandCanExecuteChanged(object sender, EventArgs eventArgs)
117 | {
118 | ICommand cmd = RefreshCommand;
119 | if (cmd != null)
120 | IsEnabled = cmd.CanExecute(RefreshCommandParameter);
121 | }
122 |
123 | ///
124 | /// Color property of refresh spinner color
125 | ///
126 | public static readonly BindableProperty RefreshColorProperty =
127 | BindableProperty.Create(nameof(RefreshColor), typeof(Color), typeof(PullToRefreshLayout), Color.Default);
128 |
129 | ///
130 | /// Refresh color
131 | ///
132 | public Color RefreshColor
133 | {
134 | get { return (Color)GetValue(RefreshColorProperty); }
135 | set { SetValue(RefreshColorProperty, value); }
136 | }
137 |
138 |
139 |
140 | ///
141 | /// Color property of refresh background color
142 | ///
143 | public static readonly BindableProperty RefreshBackgroundColorProperty =
144 | BindableProperty.Create(nameof(RefreshBackgroundColor), typeof(Color), typeof(PullToRefreshLayout), Color.Default);
145 |
146 | ///
147 | /// Refresh background color
148 | ///
149 | public Color RefreshBackgroundColor
150 | {
151 | get { return (Color)GetValue(RefreshBackgroundColorProperty); }
152 | set { SetValue(RefreshBackgroundColorProperty, value); }
153 | }
154 |
155 |
156 | ///
157 | /// The Is Intercept Horizontal Scroll property.
158 | ///
159 | public static readonly BindableProperty IsInterceptHorizontalScrollProperty =
160 | BindableProperty.Create(nameof(IsInterceptHorizontalScroll), typeof(bool), typeof(PullToRefreshLayout), true);
161 |
162 | ///
163 | /// Gets or sets a value indicating whether the pull-to-refresh behaviour will intercept the inner horizontal scroll.
164 | /// By default, this value is true
165 | ///
166 | /// true if the pull-to-refresh will intercept horizontal scroll; otherwise, false.
167 | public bool IsInterceptHorizontalScroll
168 | {
169 | get { return (bool)GetValue(IsInterceptHorizontalScrollProperty); }
170 | set { SetValue(IsInterceptHorizontalScrollProperty, value); }
171 | }
172 |
173 |
174 | /// The available width for the element to use.
175 | /// The available height for the element to use.
176 | ///
177 | /// Optimization as we can get the size here of our content all in DIP
178 | ///
179 | protected override SizeRequest OnMeasure(double widthConstraint, double heightConstraint)
180 | {
181 | if (Content == null)
182 | return new SizeRequest(new Size(100, 100));
183 |
184 | return base.OnMeasure(widthConstraint, heightConstraint);
185 | }
186 | }
187 | }
188 |
189 |
--------------------------------------------------------------------------------
/PullToRefresh/PullToRefresh.Standard/PullToRefreshLayoutRenderer.android.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 Refractored LLC & James Montemagno:
3 | * http://github.com/JamesMontemagno
4 | * http://twitter.com/JamesMontemagno
5 | * http://refractored.com
6 | *
7 | * The MIT License (MIT) see GitHub For more information
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | using System;
16 | using System.ComponentModel;
17 | using System.Reflection;
18 | using Android.Runtime;
19 | using Android.Support.V4.Widget;
20 | using Android.Views;
21 | using Refractored.XamForms.PullToRefresh;
22 | using Refractored.XamForms.PullToRefresh.Droid;
23 | using Xamarin.Forms;
24 | using Xamarin.Forms.Platform.Android;
25 |
26 |
27 | [assembly: ExportRenderer(typeof(PullToRefreshLayout), typeof(PullToRefreshLayoutRenderer))]
28 | namespace Refractored.XamForms.PullToRefresh.Droid
29 | {
30 | ///
31 | /// Pull to refresh layout renderer.
32 | ///
33 | [Preserve(AllMembers = true)]
34 | public class PullToRefreshLayoutRenderer : SwipeRefreshLayout,
35 | IVisualElementRenderer,
36 | SwipeRefreshLayout.IOnRefreshListener
37 | {
38 | ///
39 | /// Used for registration with dependency service
40 | ///
41 | public async static void Init()
42 | {
43 | var temp = DateTime.Now;
44 | }
45 |
46 | ///
47 | /// Initializes a new instance of the
48 | /// class.
49 | ///
50 | public PullToRefreshLayoutRenderer(Android.Content.Context context)
51 | : base(context)
52 | {
53 | touchSlop = ViewConfiguration.Get(context).ScaledTouchSlop;
54 | }
55 |
56 | ///
57 | /// Occurs when element changed.
58 | ///
59 | public event EventHandler ElementChanged;
60 | public event EventHandler ElementPropertyChanged;
61 |
62 | bool init;
63 | IVisualElementRenderer packed;
64 | ///
65 | /// Setup our SwipeRefreshLayout and register for property changed notifications.
66 | ///
67 | /// Element.
68 | public void SetElement(VisualElement element)
69 | {
70 | var oldElement = Element;
71 |
72 | //unregister old and re-register new
73 | if (oldElement != null)
74 | oldElement.PropertyChanged -= HandlePropertyChanged;
75 |
76 | Element = element;
77 | if (Element != null)
78 | {
79 | UpdateContent();
80 | Element.PropertyChanged += HandlePropertyChanged;
81 | }
82 |
83 | if (!init)
84 | {
85 | init = true;
86 | //sizes to match the forms view
87 | //updates properties, handles visual element properties
88 | Tracker = new VisualElementTracker(this);
89 | SetOnRefreshListener(this);
90 | }
91 |
92 | UpdateColors();
93 | UpdateIsRefreshing();
94 | UpdateIsSwipeToRefreshEnabled();
95 | UpdateIsInterceptHorizontalScroll();
96 |
97 | if (ElementChanged != null)
98 | ElementChanged(this, new VisualElementChangedEventArgs(oldElement, this.Element));
99 | }
100 |
101 | ///
102 | /// Managest adding and removing the android viewgroup to our actual swiperefreshlayout
103 | ///
104 | void UpdateContent()
105 | {
106 | if (RefreshView.Content == null)
107 | return;
108 |
109 | if (packed != null)
110 | RemoveView(packed.View);
111 |
112 | packed = Platform.CreateRendererWithContext(RefreshView.Content, Context);
113 |
114 | try
115 | {
116 | RefreshView.Content.SetValue(RendererProperty, packed);
117 | }
118 | catch (Exception ex)
119 | {
120 | System.Diagnostics.Debug.WriteLine("Unable to sent renderer property, maybe an issue: " + ex);
121 | }
122 |
123 | AddView(packed.View, LayoutParams.MatchParent);
124 |
125 | }
126 |
127 | BindableProperty rendererProperty = null;
128 |
129 | ///
130 | /// Gets the bindable property.
131 | ///
132 | /// The bindable property.
133 | BindableProperty RendererProperty
134 | {
135 | get
136 | {
137 | if (rendererProperty != null)
138 | return rendererProperty;
139 |
140 | var type = Type.GetType("Xamarin.Forms.Platform.Android.Platform, Xamarin.Forms.Platform.Android");
141 | var prop = type.GetField("RendererProperty", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
142 | var val = prop.GetValue(null);
143 | rendererProperty = val as BindableProperty;
144 |
145 | return rendererProperty;
146 | }
147 | }
148 |
149 | void UpdateColors()
150 | {
151 | if (RefreshView == null)
152 | return;
153 | if (RefreshView.RefreshColor != Color.Default)
154 | SetColorSchemeColors(RefreshView.RefreshColor.ToAndroid());
155 | if (RefreshView.RefreshBackgroundColor != Color.Default)
156 | SetProgressBackgroundColorSchemeColor(RefreshView.RefreshBackgroundColor.ToAndroid());
157 | }
158 |
159 | bool refreshing;
160 | ///
161 | /// Gets or sets a value indicating whether this
162 | /// is refreshing.
163 | ///
164 | /// true if refreshing; otherwise, false.
165 | public override bool Refreshing
166 | {
167 | get
168 | {
169 | return refreshing;
170 | }
171 | set
172 | {
173 | try
174 | {
175 | refreshing = value;
176 | //this will break binding :( sad panda we need to wait for next version for this
177 | //right now you can't update the binding.. so it is 1 way
178 | if (RefreshView != null && RefreshView.IsRefreshing != refreshing)
179 | RefreshView.IsRefreshing = refreshing;
180 |
181 | if (base.Refreshing == refreshing)
182 | return;
183 |
184 | base.Refreshing = refreshing;
185 | }
186 | catch (Exception ex)
187 | {
188 | }
189 | }
190 | }
191 |
192 | void UpdateIsRefreshing() =>
193 | Refreshing = RefreshView.IsRefreshing;
194 |
195 |
196 | void UpdateIsSwipeToRefreshEnabled() =>
197 | Enabled = RefreshView.IsPullToRefreshEnabled;
198 |
199 |
200 |
201 | ///
202 | /// Determines whether this instance can child scroll up.
203 | /// We do this since the actual swipe refresh can't figure it out
204 | ///
205 | /// true if this instance can child scroll up; otherwise, false.
206 | public override bool CanChildScrollUp() =>
207 | CanScrollUp(packed.View);
208 |
209 |
210 | bool CanScrollUp(Android.Views.View view)
211 | {
212 | var viewGroup = view as ViewGroup;
213 | if (viewGroup == null)
214 | return base.CanChildScrollUp();
215 |
216 | var sdk = (int)global::Android.OS.Build.VERSION.SdkInt;
217 | if (sdk >= 16)
218 | {
219 | //is a scroll container such as listview, scroll view, gridview
220 | if (viewGroup.IsScrollContainer)
221 | {
222 | return base.CanChildScrollUp();
223 | }
224 | }
225 |
226 | //if you have something custom and you can't scroll up you might need to enable this
227 | //for instance on a custom recycler view where the code above isn't working!
228 | for (int i = 0; i < viewGroup.ChildCount; i++)
229 | {
230 | var child = viewGroup.GetChildAt(i);
231 | if (child is Android.Widget.AbsListView)
232 | {
233 | var list = child as Android.Widget.AbsListView;
234 | if (list != null)
235 | {
236 | if (list.FirstVisiblePosition == 0)
237 | {
238 | var subChild = list.GetChildAt(0);
239 |
240 | return subChild != null && subChild.Top != 0;
241 | }
242 |
243 | //if children are in list and we are scrolled a bit... sure you can scroll up
244 | return true;
245 | }
246 |
247 | }
248 | else if (child is Android.Widget.ScrollView)
249 | {
250 | var scrollview = child as Android.Widget.ScrollView;
251 | return (scrollview.ScrollY <= 0.0);
252 | }
253 | else if (child is Android.Webkit.WebView)
254 | {
255 | var webView = child as Android.Webkit.WebView;
256 | return (webView.ScrollY > 0.0);
257 | }
258 | else if (child is Android.Support.V4.Widget.SwipeRefreshLayout)
259 | {
260 | return CanScrollUp(child as ViewGroup);
261 | }
262 | //else if something else like a recycler view?
263 |
264 | }
265 |
266 | return false;
267 | }
268 |
269 |
270 | ///
271 | /// Helpers to cast our element easily
272 | /// Will throw an exception if the Element is not correct
273 | ///
274 | /// The refresh view.
275 | public Refractored.XamForms.PullToRefresh.PullToRefreshLayout RefreshView =>
276 | Element as PullToRefreshLayout;
277 |
278 | ///
279 | /// The refresh view has been refreshed
280 | ///
281 | public void OnRefresh()
282 | {
283 | if (RefreshView?.RefreshCommand?.CanExecute(RefreshView?.RefreshCommandParameter) ?? false)
284 | {
285 | RefreshView.RefreshCommand.Execute(RefreshView?.RefreshCommandParameter);
286 | }
287 | }
288 |
289 |
290 | ///
291 | /// Handles the property changed.
292 | /// Update the control and trigger refreshing
293 | ///
294 | /// Sender.
295 | /// E.
296 | void HandlePropertyChanged(object sender, PropertyChangedEventArgs e)
297 | {
298 | if (isDisposed)
299 | return;
300 | if (e.PropertyName == "Content")
301 | UpdateContent();
302 | else if (e.PropertyName == PullToRefreshLayout.IsPullToRefreshEnabledProperty.PropertyName)
303 | UpdateIsSwipeToRefreshEnabled();
304 | else if (e.PropertyName == PullToRefreshLayout.IsRefreshingProperty.PropertyName)
305 | UpdateIsRefreshing();
306 | else if (e.PropertyName == PullToRefreshLayout.RefreshColorProperty.PropertyName)
307 | UpdateColors();
308 | else if (e.PropertyName == PullToRefreshLayout.RefreshBackgroundColorProperty.PropertyName)
309 | UpdateColors();
310 | else if (e.PropertyName == PullToRefreshLayout.IsInterceptHorizontalScrollProperty.PropertyName)
311 | UpdateIsInterceptHorizontalScroll();
312 | }
313 |
314 | ///
315 | /// Gets the size of the desired.
316 | ///
317 | /// The desired size.
318 | /// Width constraint.
319 | /// Height constraint.
320 | public SizeRequest GetDesiredSize(int widthConstraint, int heightConstraint)
321 | {
322 | packed.View.Measure(widthConstraint, heightConstraint);
323 |
324 | //Measure child here and determine size
325 | return new SizeRequest(new Size(packed.View.MeasuredWidth, packed.View.MeasuredHeight));
326 | }
327 |
328 | ///
329 | /// Updates the layout.
330 | ///
331 | public void UpdateLayout() => Tracker?.UpdateLayout();
332 |
333 |
334 | ///
335 | /// Gets the tracker.
336 | ///
337 | /// The tracker.
338 | public VisualElementTracker Tracker { get; private set; }
339 |
340 |
341 | ///
342 | /// Gets the view group.
343 | ///
344 | /// The view group.
345 | public Android.Views.ViewGroup ViewGroup => this;
346 |
347 |
348 | public Android.Views.View View => this;
349 |
350 | ///
351 | /// Gets the element.
352 | ///
353 | /// The element.
354 | public VisualElement Element { get; private set; }
355 |
356 | bool isDisposed = false;
357 | ///
358 | /// Cleanup layout.
359 | ///
360 | ///
361 | protected override void Dispose(bool disposing)
362 | {
363 | base.Dispose(disposing);
364 | isDisposed = true;
365 |
366 | if (disposing)
367 | {
368 | if (Element != null)
369 | {
370 | Element.PropertyChanged -= HandlePropertyChanged;
371 | }
372 |
373 | if (packed != null)
374 | RemoveView(packed.View);
375 | }
376 |
377 | packed?.Dispose();
378 | packed = null;
379 |
380 | Tracker?.Dispose();
381 | Tracker = null;
382 |
383 |
384 | if (rendererProperty != null)
385 | {
386 | rendererProperty = null;
387 | }
388 | init = false;
389 | }
390 |
391 | void UpdateIsInterceptHorizontalScroll()
392 | {
393 | if (RefreshView == null)
394 | return;
395 |
396 | isInterceptHorizontalScroll = RefreshView.IsInterceptHorizontalScroll;
397 | }
398 |
399 | private bool isInterceptHorizontalScroll;
400 | private int touchSlop;
401 | private float previousX;
402 | public override bool OnInterceptTouchEvent(MotionEvent ev)
403 | {
404 | if (isInterceptHorizontalScroll)
405 | return base.OnInterceptTouchEvent(ev);
406 |
407 | switch (ev.Action)
408 | {
409 | case MotionEventActions.Down:
410 | previousX = MotionEvent.Obtain(ev).GetX();
411 | break;
412 |
413 | case MotionEventActions.Move:
414 | float eventX = ev.GetX();
415 | float xDiff = Math.Abs(eventX - previousX);
416 |
417 | if (xDiff > touchSlop)
418 | {
419 | return false;
420 | }
421 | break;
422 | }
423 |
424 | return base.OnInterceptTouchEvent(ev);
425 | }
426 |
427 | public void SetLabelFor(int? id)
428 | {
429 |
430 | }
431 | }
432 | }
433 |
434 |
--------------------------------------------------------------------------------
/PullToRefresh/PullToRefresh.Standard/PullToRefreshLayoutRenderer.ios.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 Refractored LLC & James Montemagno:
3 | * http://github.com/JamesMontemagno
4 | * http://twitter.com/JamesMontemagno
5 | * http://refractored.com
6 | *
7 | * The MIT License (MIT) see GitHub For more information
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | using System;
16 | using System.ComponentModel;
17 | using Foundation;
18 | using Refractored.XamForms.PullToRefresh;
19 | using Refractored.XamForms.PullToRefresh.iOS;
20 | using UIKit;
21 | using Xamarin.Forms;
22 | using Xamarin.Forms.Platform.iOS;
23 |
24 |
25 | [assembly: ExportRenderer(typeof(PullToRefreshLayout), typeof(PullToRefreshLayoutRenderer))]
26 | namespace Refractored.XamForms.PullToRefresh.iOS
27 | {
28 |
29 | ///
30 | /// Pull to refresh layout renderer.
31 | ///
32 | [Preserve(AllMembers = true)]
33 | public class PullToRefreshLayoutRenderer : ViewRenderer
34 | {
35 |
36 | ///
37 | /// Used for registration with dependency service
38 | ///
39 | public async static void Init()
40 | {
41 | var temp = DateTime.Now;
42 | }
43 |
44 | UIRefreshControl refreshControl;
45 | UIView refreshControlParent;
46 |
47 |
48 | ///
49 | /// Raises the element changed event.
50 | ///
51 | /// E.
52 | protected override void OnElementChanged(ElementChangedEventArgs e)
53 | {
54 | base.OnElementChanged(e);
55 |
56 | if (e.OldElement != null || Element == null)
57 | return;
58 |
59 | refreshControl = new UIRefreshControl();
60 |
61 | refreshControl.ValueChanged += OnRefresh;
62 |
63 | this.refreshControlParent = this;
64 |
65 | UpdateColors();
66 | UpdateIsRefreshing();
67 | UpdateIsSwipeToRefreshEnabled();
68 | }
69 |
70 | bool set;
71 | nfloat origininalY;
72 |
73 | bool TryOffsetRefresh(UIView view, bool refreshing, int index = 0)
74 | {
75 | if (view is UITableView)
76 | {
77 | var uiTableView = view as UITableView;
78 | if (!set)
79 | {
80 | origininalY = uiTableView.ContentOffset.Y;
81 | set = true;
82 | }
83 |
84 | if (origininalY < 0)
85 | return true;
86 |
87 | if (refreshing)
88 | uiTableView.SetContentOffset(new CoreGraphics.CGPoint(0, origininalY - refreshControl.Frame.Size.Height), true);
89 | else
90 | uiTableView.SetContentOffset(new CoreGraphics.CGPoint(0, origininalY), true);
91 | return true;
92 | }
93 |
94 | if (view is UICollectionView)
95 | {
96 |
97 | var uiCollectionView = view as UICollectionView;
98 | if (!set)
99 | {
100 | origininalY = uiCollectionView.ContentOffset.Y;
101 | set = true;
102 | }
103 |
104 | if (origininalY < 0)
105 | return true;
106 |
107 | if (refreshing)
108 | uiCollectionView.SetContentOffset(new CoreGraphics.CGPoint(0, origininalY - refreshControl.Frame.Size.Height), true);
109 | else
110 | uiCollectionView.SetContentOffset(new CoreGraphics.CGPoint(0, origininalY), true);
111 | return true;
112 | }
113 |
114 |
115 | if (view is UIWebView)
116 | {
117 | //can't do anything
118 | return true;
119 | }
120 |
121 |
122 | if (view is UIScrollView)
123 | {
124 | var uiScrollView = view as UIScrollView;
125 |
126 | if (!set)
127 | {
128 | origininalY = uiScrollView.ContentOffset.Y;
129 | set = true;
130 | }
131 |
132 | if (origininalY < 0)
133 | return true;
134 |
135 | if (refreshing)
136 | uiScrollView.SetContentOffset(new CoreGraphics.CGPoint(0, origininalY - refreshControl.Frame.Size.Height), true);
137 | else
138 | uiScrollView.SetContentOffset(new CoreGraphics.CGPoint(0, origininalY), true);
139 | return true;
140 | }
141 |
142 | if (view.Subviews == null)
143 | return false;
144 |
145 | for (int i = 0; i < view.Subviews.Length; i++)
146 | {
147 | var control = view.Subviews[i];
148 | if (TryOffsetRefresh(control, refreshing, i))
149 | return true;
150 | }
151 |
152 | return false;
153 | }
154 |
155 |
156 | bool TryInsertRefresh(UIView view, int index = 0)
157 | {
158 | this.refreshControlParent = view;
159 |
160 | if (view is UITableView || view is UICollectionView)
161 | {
162 | view.InsertSubview(refreshControl, index);
163 | return true;
164 | }
165 |
166 | if (view is UIWebView)
167 | {
168 | var uiWebView = view as UIWebView;
169 | uiWebView.ScrollView.InsertSubview(refreshControl, index);
170 | return true;
171 | }
172 |
173 | if (view is UIScrollView)
174 | {
175 | var uiScrollView = view as UIScrollView;
176 | view.InsertSubview(refreshControl, index);
177 | uiScrollView.AlwaysBounceVertical = true;
178 |
179 | //override default refreshcolor if in xaml or behind
180 | if (uiScrollView.ContentOffset.Y == 0)
181 | {
182 | uiScrollView.ContentOffset = (new CoreGraphics.CGPoint(0, -refreshControl.Frame.Size.Height * 2.0));
183 | }
184 |
185 | return true;
186 | }
187 |
188 | if (view.Subviews == null)
189 | return false;
190 |
191 | for (int i = 0; i < view.Subviews.Length; i++)
192 | {
193 | var control = view.Subviews[i];
194 | if (TryInsertRefresh(control, i))
195 | return true;
196 | }
197 |
198 | return false;
199 | }
200 |
201 |
202 |
203 | BindableProperty rendererProperty;
204 |
205 | ///
206 | /// Gets the bindable property.
207 | ///
208 | /// The bindable property.
209 | BindableProperty RendererProperty
210 | {
211 | get
212 | {
213 | if (rendererProperty != null)
214 | return rendererProperty;
215 |
216 | var type = Type.GetType("Xamarin.Forms.Platform.iOS.Platform, Xamarin.Forms.Platform.iOS");
217 | var prop = type.GetField("RendererProperty");
218 | var val = prop.GetValue(null);
219 | rendererProperty = val as BindableProperty;
220 |
221 | return rendererProperty;
222 | }
223 | }
224 |
225 | void UpdateColors()
226 | {
227 | if (RefreshView == null)
228 | return;
229 | if (RefreshView.RefreshColor != Color.Default)
230 | refreshControl.TintColor = RefreshView.RefreshColor.ToUIColor();
231 | if (RefreshView.RefreshBackgroundColor != Color.Default)
232 | refreshControl.BackgroundColor = RefreshView.RefreshBackgroundColor.ToUIColor();
233 | }
234 |
235 |
236 | void UpdateIsRefreshing()
237 | {
238 | IsRefreshing = RefreshView.IsRefreshing;
239 | }
240 |
241 | void UpdateIsSwipeToRefreshEnabled()
242 | {
243 | if (RefreshView.IsPullToRefreshEnabled)
244 | {
245 | this.TryInsertRefresh(this.refreshControlParent);
246 | }
247 | else
248 | {
249 | if (this.refreshControl.Superview != null)
250 | {
251 | this.refreshControl.RemoveFromSuperview();
252 | }
253 | }
254 | }
255 |
256 | ///
257 | /// Helpers to cast our element easily
258 | /// Will throw an exception if the Element is not correct
259 | ///
260 | /// The refresh view.
261 | public Refractored.XamForms.PullToRefresh.PullToRefreshLayout RefreshView
262 | {
263 | get { return Element; }
264 | }
265 |
266 |
267 |
268 | bool isRefreshing;
269 |
270 | ///
271 | /// Gets or sets a value indicating whether this instance is refreshing.
272 | ///
273 | /// true if this instance is refreshing; otherwise, false.
274 | public bool IsRefreshing
275 | {
276 | get { return isRefreshing; }
277 | set
278 | {
279 | bool changed = IsRefreshing != value;
280 |
281 | isRefreshing = value;
282 | if (isRefreshing)
283 | refreshControl.BeginRefreshing();
284 | else
285 | refreshControl.EndRefreshing();
286 |
287 | if (changed)
288 | TryOffsetRefresh(this, IsRefreshing);
289 | }
290 | }
291 |
292 | ///
293 | /// The refresh view has been refreshed
294 | ///
295 | void OnRefresh(object sender, EventArgs e)
296 | {
297 | if (RefreshView?.RefreshCommand?.CanExecute(RefreshView?.RefreshCommandParameter) ?? false)
298 | {
299 | RefreshView.RefreshCommand.Execute(RefreshView?.RefreshCommandParameter);
300 | }
301 | }
302 |
303 | ///
304 | /// Raises the element property changed event.
305 | ///
306 | /// Sender.
307 | /// E.
308 | protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
309 | {
310 | base.OnElementPropertyChanged(sender, e);
311 | if (e.PropertyName == PullToRefreshLayout.IsPullToRefreshEnabledProperty.PropertyName)
312 | UpdateIsSwipeToRefreshEnabled();
313 | else if (e.PropertyName == PullToRefreshLayout.IsRefreshingProperty.PropertyName)
314 | UpdateIsRefreshing();
315 | else if (e.PropertyName == PullToRefreshLayout.RefreshColorProperty.PropertyName)
316 | UpdateColors();
317 | else if (e.PropertyName == PullToRefreshLayout.RefreshBackgroundColorProperty.PropertyName)
318 | UpdateColors();
319 | }
320 |
321 | ///
322 | /// Dispose the specified disposing.
323 | ///
324 | /// If set to true disposing.
325 | protected override void Dispose(bool disposing)
326 | {
327 | base.Dispose(disposing);
328 | if (refreshControl != null)
329 | {
330 | refreshControl.ValueChanged -= OnRefresh;
331 | }
332 |
333 | this.refreshControlParent = null;
334 | }
335 |
336 | }
337 |
338 |
339 | }
340 |
341 |
--------------------------------------------------------------------------------
/PullToRefreshLayout.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Refractored.XamForms.PullToRefresh
5 | $version$
6 | PullToRefresh Layout for Xamarin.Forms
7 | James Montemagno
8 | James Montemagno
9 | https://github.com/jamesmontemagno/Xamarin.Forms-PullToRefreshLayout
10 | https://github.com/jamesmontemagno/Xamarin.Forms-PullToRefreshLayout
11 | http://www.refractored.com/images/pull_to_refresh.png
12 | false
13 |
14 | Add Pull to Refresh to ScrollView or group a ListView. See Project for more details
15 | Ensure you call PullToRefreshLayoutRenderer.Init() on each platform!
16 | Built against: 3.6.0.220655
17 |
18 | Enhanced Pull To Refresh Layout for Xamarin.Forms
19 | xamarin, pcl, xam.pcl, android, xamarin.forms, ios, pull to refresh, refresh, swipe
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/PullToRefreshLayout.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.27130.2027
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RefreshSample", "RefreshSample\RefreshSample.csproj", "{E8A3B142-4FDA-44D2-AC4C-2578150D4E27}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RefreshSample.iOS", "iOS\RefreshSample.iOS.csproj", "{D2E6E0DD-948A-425C-9947-970223689429}"
9 | EndProject
10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RefreshSample.Droid", "Droid\RefreshSample.Droid.csproj", "{FED4CE90-0F61-492D-94A1-1B3229A6A75B}"
11 | EndProject
12 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Library", "Library", "{A93D74B9-4C48-418F-BD96-9456DE5408BB}"
13 | EndProject
14 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{6E0D1FE0-81AF-48A0-82D9-C9ADD3336E9D}"
15 | ProjectSection(SolutionItems) = preProject
16 | CHANGELOG.md = CHANGELOG.md
17 | README.md = README.md
18 | EndProjectSection
19 | EndProject
20 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PullToRefresh", "PullToRefresh\PullToRefresh.Standard\PullToRefresh.csproj", "{10AB134C-D1B9-4589-8121-3CEB3D21D096}"
21 | EndProject
22 | Global
23 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
24 | Debug|Any CPU = Debug|Any CPU
25 | Debug|iPhone = Debug|iPhone
26 | Debug|iPhoneSimulator = Debug|iPhoneSimulator
27 | Release|Any CPU = Release|Any CPU
28 | Release|iPhone = Release|iPhone
29 | Release|iPhoneSimulator = Release|iPhoneSimulator
30 | EndGlobalSection
31 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
32 | {E8A3B142-4FDA-44D2-AC4C-2578150D4E27}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
33 | {E8A3B142-4FDA-44D2-AC4C-2578150D4E27}.Debug|Any CPU.Build.0 = Debug|Any CPU
34 | {E8A3B142-4FDA-44D2-AC4C-2578150D4E27}.Debug|iPhone.ActiveCfg = Debug|Any CPU
35 | {E8A3B142-4FDA-44D2-AC4C-2578150D4E27}.Debug|iPhone.Build.0 = Debug|Any CPU
36 | {E8A3B142-4FDA-44D2-AC4C-2578150D4E27}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
37 | {E8A3B142-4FDA-44D2-AC4C-2578150D4E27}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
38 | {E8A3B142-4FDA-44D2-AC4C-2578150D4E27}.Release|Any CPU.ActiveCfg = Release|Any CPU
39 | {E8A3B142-4FDA-44D2-AC4C-2578150D4E27}.Release|iPhone.ActiveCfg = Release|Any CPU
40 | {E8A3B142-4FDA-44D2-AC4C-2578150D4E27}.Release|iPhone.Build.0 = Release|Any CPU
41 | {E8A3B142-4FDA-44D2-AC4C-2578150D4E27}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
42 | {E8A3B142-4FDA-44D2-AC4C-2578150D4E27}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
43 | {D2E6E0DD-948A-425C-9947-970223689429}.Debug|Any CPU.ActiveCfg = Debug|iPhoneSimulator
44 | {D2E6E0DD-948A-425C-9947-970223689429}.Debug|Any CPU.Build.0 = Debug|iPhoneSimulator
45 | {D2E6E0DD-948A-425C-9947-970223689429}.Debug|iPhone.ActiveCfg = Debug|iPhone
46 | {D2E6E0DD-948A-425C-9947-970223689429}.Debug|iPhone.Build.0 = Debug|iPhone
47 | {D2E6E0DD-948A-425C-9947-970223689429}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
48 | {D2E6E0DD-948A-425C-9947-970223689429}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
49 | {D2E6E0DD-948A-425C-9947-970223689429}.Release|Any CPU.ActiveCfg = Release|iPhone
50 | {D2E6E0DD-948A-425C-9947-970223689429}.Release|iPhone.ActiveCfg = Release|iPhone
51 | {D2E6E0DD-948A-425C-9947-970223689429}.Release|iPhone.Build.0 = Release|iPhone
52 | {D2E6E0DD-948A-425C-9947-970223689429}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
53 | {D2E6E0DD-948A-425C-9947-970223689429}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
54 | {FED4CE90-0F61-492D-94A1-1B3229A6A75B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
55 | {FED4CE90-0F61-492D-94A1-1B3229A6A75B}.Debug|Any CPU.Build.0 = Debug|Any CPU
56 | {FED4CE90-0F61-492D-94A1-1B3229A6A75B}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
57 | {FED4CE90-0F61-492D-94A1-1B3229A6A75B}.Debug|iPhone.ActiveCfg = Debug|Any CPU
58 | {FED4CE90-0F61-492D-94A1-1B3229A6A75B}.Debug|iPhone.Build.0 = Debug|Any CPU
59 | {FED4CE90-0F61-492D-94A1-1B3229A6A75B}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
60 | {FED4CE90-0F61-492D-94A1-1B3229A6A75B}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
61 | {FED4CE90-0F61-492D-94A1-1B3229A6A75B}.Release|Any CPU.ActiveCfg = Release|Any CPU
62 | {FED4CE90-0F61-492D-94A1-1B3229A6A75B}.Release|iPhone.ActiveCfg = Release|Any CPU
63 | {FED4CE90-0F61-492D-94A1-1B3229A6A75B}.Release|iPhone.Build.0 = Release|Any CPU
64 | {FED4CE90-0F61-492D-94A1-1B3229A6A75B}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
65 | {FED4CE90-0F61-492D-94A1-1B3229A6A75B}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
66 | {10AB134C-D1B9-4589-8121-3CEB3D21D096}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
67 | {10AB134C-D1B9-4589-8121-3CEB3D21D096}.Debug|Any CPU.Build.0 = Debug|Any CPU
68 | {10AB134C-D1B9-4589-8121-3CEB3D21D096}.Debug|iPhone.ActiveCfg = Debug|Any CPU
69 | {10AB134C-D1B9-4589-8121-3CEB3D21D096}.Debug|iPhone.Build.0 = Debug|Any CPU
70 | {10AB134C-D1B9-4589-8121-3CEB3D21D096}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
71 | {10AB134C-D1B9-4589-8121-3CEB3D21D096}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
72 | {10AB134C-D1B9-4589-8121-3CEB3D21D096}.Release|Any CPU.ActiveCfg = Release|Any CPU
73 | {10AB134C-D1B9-4589-8121-3CEB3D21D096}.Release|Any CPU.Build.0 = Release|Any CPU
74 | {10AB134C-D1B9-4589-8121-3CEB3D21D096}.Release|iPhone.ActiveCfg = Release|Any CPU
75 | {10AB134C-D1B9-4589-8121-3CEB3D21D096}.Release|iPhone.Build.0 = Release|Any CPU
76 | {10AB134C-D1B9-4589-8121-3CEB3D21D096}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
77 | {10AB134C-D1B9-4589-8121-3CEB3D21D096}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
78 | EndGlobalSection
79 | GlobalSection(SolutionProperties) = preSolution
80 | HideSolutionNode = FALSE
81 | EndGlobalSection
82 | GlobalSection(NestedProjects) = preSolution
83 | {10AB134C-D1B9-4589-8121-3CEB3D21D096} = {A93D74B9-4C48-418F-BD96-9456DE5408BB}
84 | EndGlobalSection
85 | GlobalSection(ExtensibilityGlobals) = postSolution
86 | SolutionGuid = {8BF71540-5C4B-4293-AEAB-506D03CE04C7}
87 | EndGlobalSection
88 | EndGlobal
89 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | PullToRefreshLayout for Xamarin.Forms
2 | ===================================
3 |
4 | ## Update - Officially Deprecated
5 |
6 | This library is officially deprecated and you can now use the official [RefreshView](https://github.com/xamarin/Xamarin.Forms/issues/5882) as part of [Xamarin.Forms 4.3](https://docs.microsoft.com/xamarin/xamarin-forms/release-notes/4.3/4.3.0-pre3?WT.mc_id=xamarin.formspulltorefreshlayout-github-jamont). No further work will be done on this library and all issues will be closed.
7 |
8 |
9 | --------------------------------
10 |
11 |
12 | Implementation of pull to refresh layout for Xamarin.Forms targeting iOS and Android.
13 |
14 | The goal was to create a cross-platform Xamarin.Forms Layout that could have it’s content set to anything and would enable pull to refresh capabilities.
15 |
16 | A BIG thank you to [Jason Smith](https://twitter.com/jassmith87) for his assistance on some tricky logic.
17 |
18 | For a detailed overview of the API and sample please read through my blog:
19 | http://motzcod.es/post/128274430137/pull-to-refresh-anyish-xamarinforms-view
20 |
21 | Also available as a NuGet: https://www.nuget.org/packages/Refractored.XamForms.PullToRefresh/
22 |
23 | Build Status: [](https://dev.azure.com/jamesmontemagno/Plugins%20for%20Xamarin/_build/latest?definitionId=0)
24 |
25 | **Important**
26 |
27 | If you are using the NuGet ensure that you call “PullToRefreshLayoutRenderer.Init();” in both your MainActivity and AppDelegate. (Similar to Xamarin.Forms.Maps).
28 |
29 |
30 | Android: You must build and compile against SDK 8.1 or 9.0.
31 |
32 |
33 | 
34 |
35 | ### API
36 | Simply create a PullToRefreshLayout like any other Layout and set the Content to a supported view.
37 |
38 |
39 | ```csharp
40 | var scrollView = new ScrollView
41 | {
42 | VerticalOptions = LayoutOptions.FillAndExpand,
43 | HorizontalOptions = LayoutOptions.FillAndExpand,
44 | Content = /* Anything you want in your ScrollView */
45 | };
46 |
47 | var refreshView = new PullToRefreshLayout {
48 | VerticalOptions = LayoutOptions.FillAndExpand,
49 | HorizontalOptions = LayoutOptions.FillAndExpand,
50 | Content = scrollView,
51 | RefreshColor = Color.FromHex("#3498db")
52 | };
53 |
54 | //Set Bindings
55 | refreshView.SetBinding (PullToRefreshLayout.IsRefreshingProperty, vm => vm.IsBusy, BindingMode.OneWay);
56 | refreshView.SetBinding(PullToRefreshLayout.RefreshCommandProperty, vm => vm.RefreshCommand);
57 |
58 | Content = refreshView;
59 | ```
60 |
61 | Additionally, your content could be anything you want including a StackLayout:
62 |
63 | ```csharp
64 | Content = new StackLayout
65 | {
66 | Children =
67 | {
68 | new Label { Text = “Hello Pull to Refresh“ },
69 | refreshView
70 | }
71 | };
72 | ```
73 |
74 | You can of course do it in XAML:
75 | ```
76 |
77 |
83 |
88 |
91 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | ```
110 |
111 | ### Officially Supported Views:
112 | * ListView
113 | * ScrollView
114 | * CollectionView
115 |
116 | ### Unofficial Supported Views
117 | * UICollectionView (iOS)
118 | * RecyclerView (Android)
119 | * GridView (Android)
120 | * Potentially all Android Views without a scroll, but it acts a bit odd on some
121 | * ^^You should probably use a ScrollView^^
122 |
123 | ### License
124 | The MIT License (MIT)
125 |
126 | Copyright (c) 2015 Refractored LLC & James Montemagno
127 |
128 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
129 |
130 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
131 |
132 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
133 |
134 |
135 |
136 |
--------------------------------------------------------------------------------
/RefreshSample.userprefs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/RefreshSample/App.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 Refractored LLC & James Montemagno:
3 | * http://github.com/JamesMontemagno
4 | * http://twitter.com/JamesMontemagno
5 | * http://refractored.com
6 | *
7 | * The MIT License (MIT) see GitHub For more information
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | using Xamarin.Forms;
16 | using RefreshSample.Views;
17 |
18 | namespace RefreshSample
19 | {
20 | public class App : Application
21 | {
22 | Page scrollViewPage;
23 | public App()
24 | {
25 |
26 | var scrollView = new Button { Text = "ScrollView" };
27 | var scrollViewXaml = new Button { Text = "ScrollView Xaml" };
28 | var listView = new Button { Text = "ListView" };
29 | var stackLayout = new Button { Text = "StackLayout" };
30 | var grid = new Button { Text = "Grid" };
31 | var scrollViewIn = new Button { Text = "ScrollView" };
32 | var scrollViewManual = new Button { Text = "ScrollView Manual" };
33 | var listViewIn = new Button { Text = "ListView" };
34 | var stackLayoutIn = new Button { Text = "StackLayout" };
35 | var gridIn = new Button { Text = "Grid" };
36 | var disposeCrash = new Button { Text = "Dispose Crash" };
37 | var disposeCrash2 = new Button { Text = "Dispose Crash" };
38 |
39 |
40 | scrollViewPage = new ScrollViewPage(false);
41 | Page page;
42 | // The root page of your application
43 | MainPage = page = new NavigationPage(new ContentPage
44 | {
45 | Title = "Pull to Refresh!",
46 | Content = new ScrollView
47 | {
48 | Content = new StackLayout
49 | {
50 | Padding = 25,
51 | Children =
52 | {
53 | new Label
54 | {
55 | Text = "Pull to Refresh in:"
56 | },
57 | scrollView,
58 | listView,
59 | stackLayout,
60 | grid,
61 | scrollViewXaml,
62 | new Label
63 | {
64 | Text = "Inside a layout:"
65 | },
66 | scrollViewIn,
67 | scrollViewManual,
68 | listViewIn,
69 | stackLayoutIn,
70 | gridIn,
71 | new Label
72 | {
73 | Text = "Misc"
74 | },
75 | disposeCrash,
76 | disposeCrash2
77 | }
78 | }
79 | }
80 | })
81 | {
82 | BackgroundColor = Color.FromHex("3498db"),
83 | BarTextColor = Color.White
84 | };
85 |
86 | scrollView.Clicked += async (sender, e) =>
87 | {
88 | var page2 = new ScrollViewXamlPage();
89 | await page.Navigation.PushAsync(scrollViewPage);
90 | await scrollViewPage.Navigation.PushAsync(page2);
91 | };
92 | scrollViewXaml.Clicked += (sender, e) => page.Navigation.PushAsync(new ScrollViewXamlPage());
93 | scrollViewIn.Clicked += (sender, e) => page.Navigation.PushAsync(new ScrollViewPage(true));
94 | listView.Clicked += (sender, e) => page.Navigation.PushAsync(new ListViewPage(false));
95 | listViewIn.Clicked += (sender, e) => page.Navigation.PushAsync(new ListViewPage(true));
96 | stackLayout.Clicked += (sender, e) => page.Navigation.PushAsync(new StackLayoutPage(false));
97 | stackLayoutIn.Clicked += (sender, e) => page.Navigation.PushAsync(new StackLayoutPage(true));
98 | grid.Clicked += (sender, e) => page.Navigation.PushAsync(new GridPage(false));
99 | gridIn.Clicked += (sender, e) => page.Navigation.PushAsync(new GridPage(true));
100 | disposeCrash.Clicked += (sender, e) => MainPage = new TabbedPage1();
101 | disposeCrash2.Clicked += (sender, e) => MainPage = new DisposeCrashPage();
102 | scrollViewManual.Clicked += (sender, e) => page.Navigation.PushAsync(new ScrollViewPageManual(true));
103 | }
104 |
105 | protected override void OnStart()
106 | {
107 | // Handle when your app starts
108 | }
109 |
110 | protected override void OnSleep()
111 | {
112 | // Handle when your app sleeps
113 | }
114 |
115 | protected override void OnResume()
116 | {
117 | // Handle when your app resumes
118 | }
119 | }
120 | }
121 |
122 |
--------------------------------------------------------------------------------
/RefreshSample/RefreshSample.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 | RefreshSample
6 | RefreshSample
7 | 1.0.0.0
8 | 1.0.0.0
9 | 1.0.0.0
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/RefreshSample/ViewModels/TestViewModel.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 Refractored LLC & James Montemagno:
3 | * http://github.com/JamesMontemagno
4 | * http://twitter.com/JamesMontemagno
5 | * http://refractored.com
6 | *
7 | * The MIT License (MIT) see GitHub For more information
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 | using System;
17 | using System.ComponentModel;
18 | using System.Collections.ObjectModel;
19 | using Xamarin.Forms;
20 | using System.Threading.Tasks;
21 | using System.Windows.Input;
22 |
23 | namespace RefreshSample.ViewModels
24 | {
25 | public class TestViewModel : INotifyPropertyChanged
26 | {
27 | public ObservableCollection Items { get; set; }
28 | Page page;
29 | public TestViewModel(Page page)
30 | {
31 | this.page = page;
32 | Items = new ObservableCollection();
33 | }
34 |
35 | bool canRefresh = true;
36 |
37 | public bool CanRefresh
38 | {
39 | get { return canRefresh; }
40 | set
41 | {
42 | if (canRefresh == value)
43 | return;
44 |
45 | canRefresh = value;
46 | OnPropertyChanged("CanRefresh");
47 | }
48 | }
49 |
50 |
51 | bool isBusy;
52 |
53 | public bool IsBusy
54 | {
55 | get { return isBusy; }
56 | set
57 | {
58 | if (isBusy == value)
59 | return;
60 |
61 | isBusy = value;
62 | OnPropertyChanged("IsBusy");
63 | }
64 | }
65 |
66 | ICommand refreshCommand;
67 |
68 | public ICommand RefreshCommand
69 | {
70 | get { return refreshCommand ?? (refreshCommand = new Command(async () => await ExecuteRefreshCommand())); }
71 | }
72 |
73 | async Task ExecuteRefreshCommand()
74 | {
75 | if (IsBusy)
76 | return;
77 |
78 | IsBusy = true;
79 | Items.Clear();
80 |
81 | Device.StartTimer(TimeSpan.FromSeconds(5), () =>
82 | {
83 |
84 | for (int i = 0; i < 100; i++)
85 | Items.Add(DateTime.Now.AddMinutes(i).ToString("F"));
86 |
87 | IsBusy = false;
88 |
89 | page.DisplayAlert("Refreshed", "You just refreshed the page! Nice job! Pull to refresh is now disabled", "OK");
90 | this.CanRefresh = false;
91 |
92 | return false;
93 | });
94 | }
95 |
96 | #region INotifyPropertyChanged implementation
97 |
98 | public event PropertyChangedEventHandler PropertyChanged;
99 |
100 | #endregion
101 |
102 | public void OnPropertyChanged(string propertyName)
103 | {
104 | if (PropertyChanged == null)
105 | return;
106 |
107 | PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
108 | }
109 | }
110 | }
111 |
112 |
--------------------------------------------------------------------------------
/RefreshSample/Views/DisposeCrashPage.cs:
--------------------------------------------------------------------------------
1 | using Refractored.XamForms.PullToRefresh;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using Xamarin.Forms;
8 |
9 | namespace RefreshSample.Views
10 | {
11 | class DisposeCrashPage : ContentPage
12 | {
13 | private readonly View mainView;
14 |
15 | public DisposeCrashPage()
16 | {
17 | Title = "Test Page";
18 | mainView = new PullToRefreshLayout
19 | {
20 | Content = new ScrollView()
21 | {
22 | Content = new Label() { Text = "This is a test." }
23 | }
24 | };
25 | Content = mainView;
26 | }
27 |
28 | protected override async void OnAppearing()
29 | {
30 | base.OnAppearing();
31 |
32 | Content = new ActivityIndicator { HorizontalOptions = LayoutOptions.Center, IsEnabled = true, IsVisible = true, IsRunning = true };
33 | await Task.Delay(3000);
34 | try
35 | {
36 | Content = mainView;
37 | }
38 | catch (ObjectDisposedException ex)
39 | {
40 | // Just a place to put a debug breakpoint
41 | throw;
42 | }
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/RefreshSample/Views/GridPage.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 Refractored LLC & James Montemagno:
3 | * http://github.com/JamesMontemagno
4 | * http://twitter.com/JamesMontemagno
5 | * http://refractored.com
6 | *
7 | * The MIT License (MIT) see GitHub For more information
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | using System;
16 | using Xamarin.Forms;
17 | using RefreshSample.ViewModels;
18 | using Refractored.XamForms.PullToRefresh;
19 |
20 | namespace RefreshSample.Views
21 | {
22 | public class GridPage : ContentPage
23 | {
24 | public GridPage(bool insideLayout)
25 | {var random = new Random();
26 | Title = "StackLayout (Pull to Refresh)";
27 |
28 | BindingContext = new TestViewModel (this);
29 |
30 | var grid = new Grid
31 | {
32 | VerticalOptions = LayoutOptions.FillAndExpand,
33 | HorizontalOptions = LayoutOptions.FillAndExpand,
34 | RowSpacing = 0,
35 | ColumnSpacing = 0
36 | };
37 |
38 | for (int i = 0; i < 20; i++)
39 | {
40 | grid.ColumnDefinitions.Add(new ColumnDefinition{ Width = GridLength.Auto });
41 | for (int j = 0; j < 20; j++)
42 | {
43 |
44 | if (i == 0)
45 | {
46 | grid.RowDefinitions.Add(new RowDefinition{ Height = GridLength.Auto });
47 |
48 | }
49 |
50 | grid.Children.Add(new BoxView
51 | {
52 | HeightRequest = 50,
53 | VerticalOptions = LayoutOptions.FillAndExpand,
54 | HorizontalOptions = LayoutOptions.FillAndExpand,
55 | BackgroundColor = Color.FromRgb(random.Next(0, 255), random.Next(0, 255), random.Next(0, 255))
56 | }, i, j);
57 | }
58 |
59 | }
60 |
61 | var refreshView = new PullToRefreshLayout {
62 | VerticalOptions = LayoutOptions.FillAndExpand,
63 | HorizontalOptions = LayoutOptions.FillAndExpand,
64 | Content = grid,
65 | RefreshColor = Color.FromHex("#3498db")
66 | };
67 |
68 | refreshView.SetBinding (PullToRefreshLayout.IsRefreshingProperty, vm => vm.IsBusy, BindingMode.OneWay);
69 | refreshView.SetBinding(PullToRefreshLayout.RefreshCommandProperty, vm => vm.RefreshCommand);
70 |
71 |
72 | if (insideLayout)
73 | {
74 | var activity = new ActivityIndicator();
75 | activity.SetBinding(ActivityIndicator.IsRunningProperty, "IsBusy");
76 |
77 | Content = new StackLayout
78 | {
79 | Spacing = 0,
80 | Children =
81 | {
82 | activity,
83 | new Label
84 | {
85 | TextColor = Color.White,
86 | Text = "In a StackLayout",
87 | FontSize = Device.GetNamedSize (NamedSize.Large, typeof(Label)),
88 | BackgroundColor = Color.FromHex("#3498db"),
89 | XAlign = TextAlignment.Center,
90 | HorizontalOptions = LayoutOptions.FillAndExpand
91 | },
92 | refreshView
93 | }
94 | };
95 | }
96 | else
97 | {
98 | Content = refreshView;
99 | }
100 | }
101 | }
102 | }
103 |
104 |
--------------------------------------------------------------------------------
/RefreshSample/Views/ListViewPage.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 Refractored LLC & James Montemagno:
3 | * http://github.com/JamesMontemagno
4 | * http://twitter.com/JamesMontemagno
5 | * http://refractored.com
6 | *
7 | * The MIT License (MIT) see GitHub For more information
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | using System;
16 | using Xamarin.Forms;
17 | using RefreshSample.ViewModels;
18 | using Refractored.XamForms.PullToRefresh;
19 | using System.Threading.Tasks;
20 |
21 | namespace RefreshSample.Views
22 | {
23 | public class ListViewPage : ContentPage
24 | {
25 | public ListViewPage(bool insideLayout)
26 | {
27 | Title = "ListView (Pull to Refresh)";
28 |
29 | BindingContext = new TestViewModel(this);
30 |
31 | var listView = new ListView();
32 | //ListView now has a built in pull to refresh!
33 | //You most likely could enable the listview pull to refresh and use it instead of the refresh view
34 | //listView.IsPullToRefreshEnabled = true;
35 | //
36 | //listView.SetBinding(ListView.IsRefreshingProperty, vm => vm.IsBusy, BindingMode.OneWay);
37 | //listView.SetBinding(ListView.RefreshCommandProperty, vm => vm.RefreshCommand);
38 |
39 |
40 |
41 | listView.SetBinding(ItemsView.ItemsSourceProperty, new Binding("Items"));
42 |
43 | //ListView now has a built in pull to refresh!
44 | //You most likely could disable the listview pull to refresh and re-enable this
45 | //However, I wouldn't recommend that.
46 | var refreshView = new PullToRefreshLayout
47 | {
48 | VerticalOptions = LayoutOptions.FillAndExpand,
49 | HorizontalOptions = LayoutOptions.FillAndExpand,
50 | Content = new StackLayout
51 | {
52 | Spacing = 0,
53 | Children =
54 | {
55 | new Label
56 | {
57 | TextColor = Color.White,
58 | Text = "In a StackLayout",
59 | FontSize = Device.GetNamedSize (NamedSize.Large, typeof(Label)),
60 | BackgroundColor = Color.FromHex("#3498db"),
61 | VerticalTextAlignment = TextAlignment.Center,
62 | HorizontalOptions = LayoutOptions.FillAndExpand
63 | },
64 | listView
65 | }
66 | },
67 | RefreshColor = Color.FromHex("#3498db")
68 | };
69 |
70 | refreshView.SetBinding(PullToRefreshLayout.IsRefreshingProperty, new Binding("IsBusy", BindingMode.OneWay));
71 | refreshView.SetBinding(PullToRefreshLayout.RefreshCommandProperty, new Binding("RefreshCommand"));
72 | refreshView.SetBinding(PullToRefreshLayout.IsPullToRefreshEnabledProperty, new Binding("CanRefresh"));
73 |
74 | if (insideLayout)
75 | {
76 | Content = new StackLayout
77 | {
78 | Spacing = 0,
79 | Children =
80 | {
81 | new Label
82 | {
83 | TextColor = Color.White,
84 | Text = "In a StackLayout",
85 | FontSize = Device.GetNamedSize (NamedSize.Large, typeof(Label)),
86 | BackgroundColor = Color.FromHex("#3498db"),
87 | VerticalTextAlignment = TextAlignment.Center,
88 | HorizontalOptions = LayoutOptions.FillAndExpand
89 | },
90 | refreshView
91 | }
92 | };
93 | }
94 | else
95 | {
96 | Content = refreshView;
97 | }
98 | }
99 | }
100 | }
101 |
102 |
--------------------------------------------------------------------------------
/RefreshSample/Views/ScrollViewPage.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 Refractored LLC & James Montemagno:
3 | * http://github.com/JamesMontemagno
4 | * http://twitter.com/JamesMontemagno
5 | * http://refractored.com
6 | *
7 | * The MIT License (MIT) see GitHub For more information
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | using System;
16 | using Xamarin.Forms;
17 | using RefreshSample.ViewModels;
18 | using Refractored.XamForms.PullToRefresh;
19 |
20 | namespace RefreshSample.Views
21 | {
22 | public class ScrollViewPage : ContentPage
23 | {
24 | public ScrollViewPage(bool insideLayout)
25 | {
26 | var random = new Random();
27 | Title = "ScrollView (Pull to Refresh)";
28 |
29 | BindingContext = new TestViewModel(this);
30 |
31 |
32 | var grid = new Grid
33 | {
34 | VerticalOptions = LayoutOptions.FillAndExpand,
35 | HorizontalOptions = LayoutOptions.FillAndExpand,
36 | RowSpacing = 0,
37 | ColumnSpacing = 0
38 | };
39 |
40 | var scrollView = new ScrollView
41 | {
42 | VerticalOptions = LayoutOptions.FillAndExpand,
43 | HorizontalOptions = LayoutOptions.FillAndExpand,
44 | Content = grid
45 | };
46 |
47 |
48 | for (int i = 0; i < 20; i++)
49 | {
50 | grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });
51 | for (int j = 0; j < 20; j++)
52 | {
53 |
54 | if (i == 0)
55 | {
56 | grid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
57 |
58 | }
59 |
60 | grid.Children.Add(new BoxView
61 | {
62 | HeightRequest = 50,
63 | VerticalOptions = LayoutOptions.FillAndExpand,
64 | HorizontalOptions = LayoutOptions.FillAndExpand,
65 | BackgroundColor = Color.FromRgb(random.Next(0, 255), random.Next(0, 255), random.Next(0, 255))
66 | }, i, j);
67 | }
68 |
69 | }
70 |
71 |
72 | var refreshView = new PullToRefreshLayout
73 | {
74 | VerticalOptions = LayoutOptions.FillAndExpand,
75 | HorizontalOptions = LayoutOptions.FillAndExpand,
76 | Content = scrollView,
77 | RefreshColor = Color.FromHex("#3498db")
78 | };
79 |
80 | refreshView.SetBinding(PullToRefreshLayout.IsRefreshingProperty, new Binding("IsBusy", BindingMode.OneWay));
81 | refreshView.SetBinding(PullToRefreshLayout.RefreshCommandProperty, new Binding("RefreshCommand"));
82 |
83 |
84 |
85 | if (insideLayout)
86 | {
87 | Content = new StackLayout
88 | {
89 | Spacing = 0,
90 | Children =
91 | {
92 | new Label
93 | {
94 | TextColor = Color.White,
95 | Text = "In a StackLayout",
96 | FontSize = Device.GetNamedSize (NamedSize.Large, typeof(Label)),
97 | BackgroundColor = Color.FromHex("#3498db"),
98 | VerticalTextAlignment = TextAlignment.Center,
99 | HorizontalOptions = LayoutOptions.FillAndExpand
100 | },
101 | refreshView
102 | }
103 | };
104 | }
105 | else
106 | {
107 | Content = refreshView;
108 | }
109 | }
110 | }
111 | }
112 |
113 |
--------------------------------------------------------------------------------
/RefreshSample/Views/ScrollViewPageManual.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 Refractored LLC & James Montemagno:
3 | * http://github.com/JamesMontemagno
4 | * http://twitter.com/JamesMontemagno
5 | * http://refractored.com
6 | *
7 | * The MIT License (MIT) see GitHub For more information
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | using System;
16 | using Xamarin.Forms;
17 | using RefreshSample.ViewModels;
18 | using Refractored.XamForms.PullToRefresh;
19 |
20 | namespace RefreshSample.Views
21 | {
22 | public class ScrollViewPageManual : ContentPage
23 | {
24 | public ScrollViewPageManual(bool insideLayout)
25 | {
26 | var random = new Random();
27 | Title = "ScrollView (Pull to Refresh)";
28 |
29 | BindingContext = new TestViewModel (this);
30 | var buttonStart = new Button { Text = "Start" };
31 | var buttonStop = new Button { Text = "Stop" };
32 | var buttonStartStop = new Button { Text = "Start/Stop" };
33 |
34 | var grid = new Grid
35 | {
36 | VerticalOptions = LayoutOptions.FillAndExpand,
37 | HorizontalOptions = LayoutOptions.FillAndExpand,
38 | RowSpacing = 0,
39 | ColumnSpacing = 0
40 | };
41 |
42 | var scrollView = new ScrollView
43 | {
44 | VerticalOptions = LayoutOptions.FillAndExpand,
45 | HorizontalOptions = LayoutOptions.FillAndExpand,
46 | Content = grid
47 | };
48 |
49 |
50 | for (int i = 0; i < 20; i++)
51 | {
52 | grid.ColumnDefinitions.Add(new ColumnDefinition{ Width = GridLength.Auto });
53 | for (int j = 0; j < 20; j++)
54 | {
55 |
56 | if (i == 0)
57 | {
58 | grid.RowDefinitions.Add(new RowDefinition{ Height = GridLength.Auto });
59 |
60 | }
61 |
62 | grid.Children.Add(new BoxView
63 | {
64 | HeightRequest = 50,
65 | VerticalOptions = LayoutOptions.FillAndExpand,
66 | HorizontalOptions = LayoutOptions.FillAndExpand,
67 | BackgroundColor = Color.FromRgb(random.Next(0, 255), random.Next(0, 255), random.Next(0, 255))
68 | }, i, j);
69 | }
70 |
71 | }
72 |
73 |
74 | var refreshView = new PullToRefreshLayout {
75 | VerticalOptions = LayoutOptions.FillAndExpand,
76 | HorizontalOptions = LayoutOptions.FillAndExpand,
77 | Content = scrollView,
78 | RefreshColor = Color.FromHex("#3498db")
79 | };
80 |
81 |
82 | buttonStart.Clicked += (sender, args) => refreshView.IsRefreshing = true;
83 | buttonStop.Clicked += (sender, args) => refreshView.IsRefreshing = false;
84 | buttonStartStop.Clicked += (sender, args) =>
85 | {
86 | refreshView.IsRefreshing = true;
87 | refreshView.IsRefreshing = false;
88 | };
89 |
90 |
91 | if (insideLayout)
92 | {
93 | Content = new StackLayout
94 | {
95 | Spacing = 0,
96 | Children =
97 | {
98 | new Label
99 | {
100 | TextColor = Color.White,
101 | Text = "In a StackLayout",
102 | FontSize = Device.GetNamedSize (NamedSize.Large, typeof(Label)),
103 | BackgroundColor = Color.FromHex("#3498db"),
104 | HorizontalTextAlignment = TextAlignment.Center,
105 | HorizontalOptions = LayoutOptions.FillAndExpand
106 | },
107 | buttonStart,
108 | buttonStop,
109 | buttonStartStop,
110 | refreshView
111 | }
112 | };
113 | }
114 | else
115 | {
116 | Content = refreshView;
117 | }
118 | }
119 | }
120 | }
121 |
122 |
--------------------------------------------------------------------------------
/RefreshSample/Views/ScrollViewXamlPage.xaml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
13 |
16 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/RefreshSample/Views/ScrollViewXamlPage.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | using Xamarin.Forms;
5 | using RefreshSample.ViewModels;
6 |
7 | namespace RefreshSample.Views
8 | {
9 | public partial class ScrollViewXamlPage : ContentPage
10 | {
11 | public ScrollViewXamlPage()
12 | {
13 | InitializeComponent();
14 | BindingContext = new TestViewModel(this);
15 | }
16 | }
17 | }
18 |
19 |
--------------------------------------------------------------------------------
/RefreshSample/Views/StackLayoutPage.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 Refractored LLC & James Montemagno:
3 | * http://github.com/JamesMontemagno
4 | * http://twitter.com/JamesMontemagno
5 | * http://refractored.com
6 | *
7 | * The MIT License (MIT) see GitHub For more information
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | using System;
16 | using Xamarin.Forms;
17 | using RefreshSample.ViewModels;
18 | using Refractored.XamForms.PullToRefresh;
19 |
20 | namespace RefreshSample.Views
21 | {
22 | public class StackLayoutPage: ContentPage
23 | {
24 | public StackLayoutPage(bool insideLayout)
25 | {
26 | var random = new Random();
27 | Title = "StackLayout (Pull to Refresh)";
28 |
29 | BindingContext = new TestViewModel (this);
30 |
31 | var stack = new StackLayout
32 | {
33 | VerticalOptions = LayoutOptions.FillAndExpand,
34 | HorizontalOptions = LayoutOptions.FillAndExpand,
35 | Spacing = 0
36 | };
37 |
38 | for (int i = 0; i < 20; i++)
39 | {
40 | stack.Children.Add(new BoxView
41 | {
42 | HeightRequest = 150,
43 | HorizontalOptions = LayoutOptions.FillAndExpand,
44 | BackgroundColor = Color.FromRgb(random.Next(0, 255), random.Next(0, 255), random.Next(0, 255))
45 | });
46 | }
47 |
48 | var refreshView = new PullToRefreshLayout {
49 | VerticalOptions = LayoutOptions.FillAndExpand,
50 | HorizontalOptions = LayoutOptions.FillAndExpand,
51 | Content = stack,
52 | RefreshColor = Color.FromHex("#3498db")
53 | };
54 |
55 | refreshView.SetBinding (PullToRefreshLayout.IsRefreshingProperty, vm => vm.IsBusy, BindingMode.OneWay);
56 | refreshView.SetBinding(PullToRefreshLayout.RefreshCommandProperty, vm => vm.RefreshCommand);
57 |
58 |
59 | if (insideLayout)
60 | {
61 | var activity = new ActivityIndicator();
62 | activity.SetBinding(ActivityIndicator.IsRunningProperty, "IsBusy");
63 | Content = new StackLayout
64 | {
65 | Spacing = 0,
66 | Children =
67 | {
68 | activity,
69 | new Label
70 | {
71 | TextColor = Color.White,
72 | Text = "In a StackLayout",
73 | FontSize = Device.GetNamedSize (NamedSize.Large, typeof(Label)),
74 | BackgroundColor = Color.FromHex("#3498db"),
75 | XAlign = TextAlignment.Center,
76 | HorizontalOptions = LayoutOptions.FillAndExpand
77 | },
78 | refreshView
79 | }
80 | };
81 | }
82 | else
83 | {
84 | Content = refreshView;
85 | }
86 | }
87 | }
88 | }
89 |
90 |
--------------------------------------------------------------------------------
/RefreshSample/Views/TabbedPage1.xaml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
13 |
16 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/RefreshSample/Views/TabbedPage1.xaml.cs:
--------------------------------------------------------------------------------
1 | using RefreshSample.ViewModels;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | using Xamarin.Forms;
9 | using Xamarin.Forms.Xaml;
10 |
11 | namespace RefreshSample.Views
12 | {
13 | [XamlCompilation(XamlCompilationOptions.Compile)]
14 | public partial class TabbedPage1 : TabbedPage
15 | {
16 | public TabbedPage1()
17 | {
18 | InitializeComponent();
19 | BindingContext = new TestViewModel(this);
20 | }
21 | }
22 | }
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | version: 2.3.0.{build}-beta
2 | image: Visual Studio 2017
3 | configuration: Release
4 | assembly_info:
5 | patch: true
6 | file: '**\AssemblyInfo.*'
7 | assembly_version: '{version}'
8 | assembly_file_version: '{version}'
9 | assembly_informational_version: '{version}'
10 | install:
11 | - echo y | "C:\Program Files (x86)\Android\android-sdk\tools\android.bat" update sdk -u -a -t tools
12 | - echo y | "C:\Program Files (x86)\Android\android-sdk\tools\android.bat" update sdk -u -a -t platform-tools
13 | - echo y | "C:\Program Files (x86)\Android\android-sdk\tools\android.bat" update sdk -u -a -t build-tools-25.0.6
14 | - echo y | "C:\Program Files (x86)\Android\android-sdk\tools\android.bat" update sdk -u -a -t android-28
15 | - echo y | "C:\Program Files (x86)\Android\android-sdk\tools\android.bat" update sdk -u -a -t android-15
16 | build_script:
17 | - cmd: >-
18 | powershell .\build.ps1 -Target Default -Verbosity diagnostic
19 | artifacts:
20 | - path: ./Build/nuget/*.nupkg
21 | name: NuGet
22 |
--------------------------------------------------------------------------------
/build.cake:
--------------------------------------------------------------------------------
1 | var TARGET = Argument ("target", Argument ("t", "Default"));
2 | var VERSION = EnvironmentVariable ("APPVEYOR_BUILD_VERSION") ?? Argument("version", "0.0.9999");
3 | var CONFIG = Argument("configuration", EnvironmentVariable ("CONFIGURATION") ?? "Release");
4 | var SLN = "./PullToRefreshLayout.sln";
5 |
6 | Task("Libraries").Does(()=>
7 | {
8 | NuGetRestore (SLN);
9 | MSBuild (SLN, c => {
10 | c.Configuration = CONFIG;
11 | c.MSBuildPlatform = Cake.Common.Tools.MSBuild.MSBuildPlatform.x86;
12 | });
13 | });
14 |
15 | Task ("NuGet")
16 | .IsDependentOn ("Libraries")
17 | .Does (() =>
18 | {
19 | if(!DirectoryExists("./Build/nuget/"))
20 | CreateDirectory("./Build/nuget");
21 |
22 | NuGetPack ("./PullToRefreshLayout.nuspec", new NuGetPackSettings {
23 | Version = VERSION,
24 | OutputDirectory = "./Build/nuget/",
25 | BasePath = "./"
26 | });
27 | });
28 |
29 | //Build the component, which build samples, nugets, and libraries
30 | Task ("Default").IsDependentOn("NuGet");
31 |
32 | Task ("Clean").Does (() =>
33 | {
34 | CleanDirectory ("./component/tools/");
35 | CleanDirectories ("./Build/");
36 | CleanDirectories ("./**/bin");
37 | CleanDirectories ("./**/obj");
38 | });
39 |
40 | RunTarget (TARGET);
41 |
--------------------------------------------------------------------------------
/build.ps1:
--------------------------------------------------------------------------------
1 | ##########################################################################
2 | # This is the Cake bootstrapper script for PowerShell.
3 | # This file was downloaded from https://github.com/cake-build/resources
4 | # Feel free to change this file to fit your needs.
5 | ##########################################################################
6 |
7 | <#
8 |
9 | .SYNOPSIS
10 | This is a Powershell script to bootstrap a Cake build.
11 |
12 | .DESCRIPTION
13 | This Powershell script will download NuGet if missing, restore NuGet tools (including Cake)
14 | and execute your Cake build script with the parameters you provide.
15 |
16 | .PARAMETER Script
17 | The build script to execute.
18 | .PARAMETER Target
19 | The build script target to run.
20 | .PARAMETER Configuration
21 | The build configuration to use.
22 | .PARAMETER Verbosity
23 | Specifies the amount of information to be displayed.
24 | .PARAMETER Experimental
25 | Tells Cake to use the latest Roslyn release.
26 | .PARAMETER WhatIf
27 | Performs a dry run of the build script.
28 | No tasks will be executed.
29 | .PARAMETER Mono
30 | Tells Cake to use the Mono scripting engine.
31 | .PARAMETER SkipToolPackageRestore
32 | Skips restoring of packages.
33 | .PARAMETER ScriptArgs
34 | Remaining arguments are added here.
35 |
36 | .LINK
37 | http://cakebuild.net
38 |
39 | #>
40 |
41 | [CmdletBinding()]
42 | Param(
43 | [string]$Script = "build.cake",
44 | [string]$Target = "Default",
45 | [ValidateSet("Release", "Debug")]
46 | [string]$Configuration = "Release",
47 | [ValidateSet("Quiet", "Minimal", "Normal", "Verbose", "Diagnostic")]
48 | [string]$Verbosity = "Verbose",
49 | [switch]$Experimental,
50 | [Alias("DryRun","Noop")]
51 | [switch]$WhatIf,
52 | [switch]$Mono,
53 | [switch]$SkipToolPackageRestore,
54 | [Parameter(Position=0,Mandatory=$false,ValueFromRemainingArguments=$true)]
55 | [string[]]$ScriptArgs
56 | )
57 |
58 | [Reflection.Assembly]::LoadWithPartialName("System.Security") | Out-Null
59 | function MD5HashFile([string] $filePath)
60 | {
61 | if ([string]::IsNullOrEmpty($filePath) -or !(Test-Path $filePath -PathType Leaf))
62 | {
63 | return $null
64 | }
65 |
66 | [System.IO.Stream] $file = $null;
67 | [System.Security.Cryptography.MD5] $md5 = $null;
68 | try
69 | {
70 | $md5 = [System.Security.Cryptography.MD5]::Create()
71 | $file = [System.IO.File]::OpenRead($filePath)
72 | return [System.BitConverter]::ToString($md5.ComputeHash($file))
73 | }
74 | finally
75 | {
76 | if ($file -ne $null)
77 | {
78 | $file.Dispose()
79 | }
80 | }
81 | }
82 |
83 | Write-Host "Preparing to run build script..."
84 |
85 | if(!$PSScriptRoot){
86 | $PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent
87 | }
88 |
89 | $TOOLS_DIR = Join-Path $PSScriptRoot "tools"
90 | $NUGET_EXE = Join-Path $TOOLS_DIR "nuget.exe"
91 | $CAKE_EXE = Join-Path $TOOLS_DIR "Cake/Cake.exe"
92 | $NUGET_URL = "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe"
93 | $PACKAGES_CONFIG = Join-Path $TOOLS_DIR "packages.config"
94 | $PACKAGES_CONFIG_MD5 = Join-Path $TOOLS_DIR "packages.config.md5sum"
95 |
96 | # Should we use mono?
97 | $UseMono = "";
98 | if($Mono.IsPresent) {
99 | Write-Verbose -Message "Using the Mono based scripting engine."
100 | $UseMono = "-mono"
101 | }
102 |
103 | # Should we use the new Roslyn?
104 | $UseExperimental = "";
105 | if($Experimental.IsPresent -and !($Mono.IsPresent)) {
106 | Write-Verbose -Message "Using experimental version of Roslyn."
107 | $UseExperimental = "-experimental"
108 | }
109 |
110 | # Is this a dry run?
111 | $UseDryRun = "";
112 | if($WhatIf.IsPresent) {
113 | $UseDryRun = "-dryrun"
114 | }
115 |
116 | # Make sure tools folder exists
117 | if ((Test-Path $PSScriptRoot) -and !(Test-Path $TOOLS_DIR)) {
118 | Write-Verbose -Message "Creating tools directory..."
119 | New-Item -Path $TOOLS_DIR -Type directory | out-null
120 | }
121 |
122 | # Make sure that packages.config exist.
123 | if (!(Test-Path $PACKAGES_CONFIG)) {
124 | Write-Verbose -Message "Downloading packages.config..."
125 | try { (New-Object System.Net.WebClient).DownloadFile("http://cakebuild.net/download/bootstrapper/packages", $PACKAGES_CONFIG) } catch {
126 | Throw "Could not download packages.config."
127 | }
128 | }
129 |
130 | # Try find NuGet.exe in path if not exists
131 | if (!(Test-Path $NUGET_EXE)) {
132 | Write-Verbose -Message "Trying to find nuget.exe in PATH..."
133 | $existingPaths = $Env:Path -Split ';' | Where-Object { (![string]::IsNullOrEmpty($_)) -and (Test-Path $_ -PathType Container) }
134 | $NUGET_EXE_IN_PATH = Get-ChildItem -Path $existingPaths -Filter "nuget.exe" | Select -First 1
135 | if ($NUGET_EXE_IN_PATH -ne $null -and (Test-Path $NUGET_EXE_IN_PATH.FullName)) {
136 | Write-Verbose -Message "Found in PATH at $($NUGET_EXE_IN_PATH.FullName)."
137 | $NUGET_EXE = $NUGET_EXE_IN_PATH.FullName
138 | }
139 | }
140 |
141 | # Try download NuGet.exe if not exists
142 | if (!(Test-Path $NUGET_EXE)) {
143 | Write-Verbose -Message "Downloading NuGet.exe..."
144 | try {
145 | (New-Object System.Net.WebClient).DownloadFile($NUGET_URL, $NUGET_EXE)
146 | } catch {
147 | Throw "Could not download NuGet.exe."
148 | }
149 | }
150 |
151 | $newVersion = $env:APPVEYOR_BUILD_VERSION.Replace("-beta","")
152 | $configFiles = Get-ChildItem . *.csproj -rec
153 | $assemblyVersionString = "" + $newVersion + ""
154 | $assemblyFileVersionString = "" + $newVersion + ""
155 | $versionString = "" + $newVersion + ""
156 | foreach ($file in $configFiles)
157 | {
158 | (Get-Content $file.PSPath) |
159 | Foreach-Object { $_ -replace "1.0.0.0", $assemblyVersionString } |
160 | Set-Content $file.PSPath
161 | }
162 |
163 | foreach ($file in $configFiles)
164 | {
165 | (Get-Content $file.PSPath) |
166 | Foreach-Object { $_ -replace "1.0.0.0", $assemblyFileVersionString } |
167 | Set-Content $file.PSPath
168 | }
169 |
170 | foreach ($file in $configFiles)
171 | {
172 | (Get-Content $file.PSPath) |
173 | Foreach-Object { $_ -replace "1.0.0.0", $versionString } |
174 | Set-Content $file.PSPath
175 | }
176 |
177 | # Save nuget.exe path to environment to be available to child processed
178 | $ENV:NUGET_EXE = $NUGET_EXE
179 |
180 | # Restore tools from NuGet?
181 | if(-Not $SkipToolPackageRestore.IsPresent) {
182 | Push-Location
183 | Set-Location $TOOLS_DIR
184 |
185 | # Check for changes in packages.config and remove installed tools if true.
186 | [string] $md5Hash = MD5HashFile($PACKAGES_CONFIG)
187 | if((!(Test-Path $PACKAGES_CONFIG_MD5)) -Or
188 | ($md5Hash -ne (Get-Content $PACKAGES_CONFIG_MD5 ))) {
189 | Write-Verbose -Message "Missing or changed package.config hash..."
190 | Remove-Item * -Recurse -Exclude packages.config,nuget.exe
191 | }
192 |
193 | Write-Verbose -Message "Restoring tools from NuGet..."
194 | $NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$TOOLS_DIR`""
195 |
196 | if ($LASTEXITCODE -ne 0) {
197 | Throw "An error occured while restoring NuGet tools."
198 | }
199 | else
200 | {
201 | $md5Hash | Out-File $PACKAGES_CONFIG_MD5 -Encoding "ASCII"
202 | }
203 | Write-Verbose -Message ($NuGetOutput | out-string)
204 | Pop-Location
205 | }
206 |
207 | # Make sure that Cake has been installed.
208 | if (!(Test-Path $CAKE_EXE)) {
209 | Throw "Could not find Cake.exe at $CAKE_EXE"
210 | }
211 |
212 | # Start Cake
213 | Write-Host "Running build script..."
214 | Invoke-Expression "& `"$CAKE_EXE`" `"$Script`" -target=`"$Target`" -configuration=`"$Configuration`" -verbosity=`"$Verbosity`" $UseMono $UseDryRun $UseExperimental $ScriptArgs"
215 | exit $LASTEXITCODE
216 |
--------------------------------------------------------------------------------
/build.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##########################################################################
4 | # This is the Cake bootstrapper script for Linux and OS X.
5 | # This file was downloaded from https://github.com/cake-build/resources
6 | # Feel free to change this file to fit your needs.
7 | ##########################################################################
8 |
9 | # Define directories.
10 | SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
11 | TOOLS_DIR=$SCRIPT_DIR/tools
12 | NUGET_EXE=$TOOLS_DIR/nuget.exe
13 | CAKE_EXE=$TOOLS_DIR/Cake/Cake.exe
14 | PACKAGES_CONFIG=$TOOLS_DIR/packages.config
15 | PACKAGES_CONFIG_MD5=$TOOLS_DIR/packages.config.md5sum
16 |
17 | # Define md5sum or md5 depending on Linux/OSX
18 | MD5_EXE=
19 | if [[ "$(uname -s)" == "Darwin" ]]; then
20 | MD5_EXE="md5 -r"
21 | else
22 | MD5_EXE="md5sum"
23 | fi
24 |
25 | # Define default arguments.
26 | SCRIPT="build.cake"
27 | TARGET="Default"
28 | CONFIGURATION="Release"
29 | VERBOSITY="verbose"
30 | DRYRUN=
31 | SHOW_VERSION=false
32 | SCRIPT_ARGUMENTS=()
33 |
34 | # Parse arguments.
35 | for i in "$@"; do
36 | case $1 in
37 | -s|--script) SCRIPT="$2"; shift ;;
38 | -t|--target) TARGET="$2"; shift ;;
39 | -c|--configuration) CONFIGURATION="$2"; shift ;;
40 | -v|--verbosity) VERBOSITY="$2"; shift ;;
41 | -d|--dryrun) DRYRUN="-dryrun" ;;
42 | --version) SHOW_VERSION=true ;;
43 | --) shift; SCRIPT_ARGUMENTS+=("$@"); break ;;
44 | *) SCRIPT_ARGUMENTS+=("$1") ;;
45 | esac
46 | shift
47 | done
48 |
49 | # Make sure the tools folder exist.
50 | if [ ! -d "$TOOLS_DIR" ]; then
51 | mkdir "$TOOLS_DIR"
52 | fi
53 |
54 | # Make sure that packages.config exist.
55 | if [ ! -f "$TOOLS_DIR/packages.config" ]; then
56 | echo "Downloading packages.config..."
57 | curl -Lsfo "$TOOLS_DIR/packages.config" http://cakebuild.net/download/bootstrapper/packages
58 | if [ $? -ne 0 ]; then
59 | echo "An error occured while downloading packages.config."
60 | exit 1
61 | fi
62 | fi
63 |
64 | # Download NuGet if it does not exist.
65 | if [ ! -f "$NUGET_EXE" ]; then
66 | echo "Downloading NuGet..."
67 | curl -Lsfo "$NUGET_EXE" https://dist.nuget.org/win-x86-commandline/latest/nuget.exe
68 | if [ $? -ne 0 ]; then
69 | echo "An error occured while downloading nuget.exe."
70 | exit 1
71 | fi
72 | fi
73 |
74 | # Restore tools from NuGet.
75 | pushd "$TOOLS_DIR" >/dev/null
76 | if [ ! -f $PACKAGES_CONFIG_MD5 ] || [ "$( cat $PACKAGES_CONFIG_MD5 | sed 's/\r$//' )" != "$( $MD5_EXE $PACKAGES_CONFIG | awk '{ print $1 }' )" ]; then
77 | find . -type d ! -name . | xargs rm -rf
78 | fi
79 |
80 | mono "$NUGET_EXE" install -ExcludeVersion
81 | if [ $? -ne 0 ]; then
82 | echo "Could not restore NuGet packages."
83 | exit 1
84 | fi
85 |
86 | $MD5_EXE $PACKAGES_CONFIG | awk '{ print $1 }' >| $PACKAGES_CONFIG_MD5
87 |
88 | popd >/dev/null
89 |
90 | # Make sure that Cake has been installed.
91 | if [ ! -f "$CAKE_EXE" ]; then
92 | echo "Could not find Cake.exe at '$CAKE_EXE'."
93 | exit 1
94 | fi
95 |
96 | # Start Cake
97 | if $SHOW_VERSION; then
98 | exec mono "$CAKE_EXE" -version
99 | else
100 | exec mono "$CAKE_EXE" $SCRIPT -verbosity=$VERBOSITY -configuration=$CONFIGURATION -target=$TARGET $DRYRUN "${SCRIPT_ARGUMENTS[@]}"
101 | fi
--------------------------------------------------------------------------------
/cake.packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jamesmontemagno/Xamarin.Forms-PullToRefreshLayout/661faad38ad10bc7f8d5774c99cf989356fcbd4e/demo.gif
--------------------------------------------------------------------------------
/iOS/AppDelegate.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 |
5 | using Foundation;
6 | using UIKit;
7 | using Refractored.XamForms.PullToRefresh.iOS;
8 |
9 | namespace RefreshSample.iOS
10 | {
11 | [Register("AppDelegate")]
12 | public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
13 | {
14 | public override bool FinishedLaunching(UIApplication app, NSDictionary options)
15 | {
16 |
17 | UINavigationBar.Appearance.BarTintColor = UIColor.FromRGB(43, 132, 211); //bar background
18 | UINavigationBar.Appearance.TintColor = UIColor.White; //Tint color of button items
19 | UINavigationBar.Appearance.SetTitleTextAttributes(new UITextAttributes()
20 | {
21 | Font = UIFont.FromName("HelveticaNeue-Light", (nfloat)20f),
22 | TextColor = UIColor.White
23 | });
24 |
25 | global::Xamarin.Forms.Forms.Init();
26 |
27 | PullToRefreshLayoutRenderer.Init();
28 |
29 | LoadApplication(new App());
30 |
31 | return base.FinishedLaunching(app, options);
32 | }
33 | }
34 | }
35 |
36 |
--------------------------------------------------------------------------------
/iOS/Entitlements.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/iOS/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDisplayName
6 | RefreshSample
7 | CFBundleIdentifier
8 | com.refractored.refreshsample
9 | CFBundleShortVersionString
10 | 1.0
11 | CFBundleVersion
12 | 1.0
13 | LSRequiresIPhoneOS
14 |
15 | MinimumOSVersion
16 | 7.0
17 | UIDeviceFamily
18 |
19 | 1
20 | 2
21 |
22 | UILaunchStoryboardName
23 | LaunchScreen
24 | UIRequiredDeviceCapabilities
25 |
26 | armv7
27 |
28 | UISupportedInterfaceOrientations
29 |
30 | UIInterfaceOrientationPortrait
31 | UIInterfaceOrientationLandscapeLeft
32 | UIInterfaceOrientationLandscapeRight
33 |
34 | UISupportedInterfaceOrientations~ipad
35 |
36 | UIInterfaceOrientationPortrait
37 | UIInterfaceOrientationPortraitUpsideDown
38 | UIInterfaceOrientationLandscapeLeft
39 | UIInterfaceOrientationLandscapeRight
40 |
41 | XSAppIconAssets
42 | Resources/Images.xcassets/AppIcons.appiconset
43 | UIStatusBarStyle
44 | UIStatusBarStyleLightContent
45 | UIViewControllerBasedStatusBarAppearance
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/iOS/Main.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 |
5 | using Foundation;
6 | using UIKit;
7 |
8 | namespace RefreshSample.iOS
9 | {
10 | public class Application
11 | {
12 | // This is the main entry point of the application.
13 | static void Main(string[] args)
14 | {
15 | // if you want to use a different Application Delegate class from "AppDelegate"
16 | // you can specify it here.
17 | UIApplication.Main(args, null, "AppDelegate");
18 | }
19 | }
20 | }
21 |
22 |
--------------------------------------------------------------------------------
/iOS/RefreshSample.iOS.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | iPhoneSimulator
6 | {FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
7 | {D2E6E0DD-948A-425C-9947-970223689429}
8 | Exe
9 | RefreshSample.iOS
10 | Resources
11 | RefreshSampleiOS
12 |
13 |
14 |
15 |
16 | true
17 | full
18 | false
19 | bin\iPhoneSimulator\Debug
20 | DEBUG;ENABLE_TEST_CLOUD;
21 | prompt
22 | 4
23 | false
24 | i386, x86_64
25 | None
26 | true
27 | iPhone Developer
28 | true
29 |
30 |
31 | true
32 |
33 |
34 | full
35 | true
36 | bin\iPhone\Release
37 | prompt
38 | 4
39 | false
40 | ARMv7, ARM64
41 | Entitlements.plist
42 | true
43 | iPhone Developer
44 |
45 |
46 | full
47 | true
48 | bin\iPhoneSimulator\Release
49 | prompt
50 | 4
51 | false
52 | i386
53 | None
54 | iPhone Developer
55 |
56 |
57 | true
58 | full
59 | false
60 | bin\iPhone\Debug
61 | DEBUG;ENABLE_TEST_CLOUD;
62 | prompt
63 | 4
64 | false
65 | ARMv7, ARM64
66 | Entitlements.plist
67 | true
68 | iPhone Developer
69 | true
70 | true
71 | true
72 |
73 |
74 | None
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 | {10ab134c-d1b9-4589-8121-3ceb3d21d096}
87 | PullToRefresh
88 |
89 |
90 | {E8A3B142-4FDA-44D2-AC4C-2578150D4E27}
91 | RefreshSample
92 |
93 |
94 |
95 |
96 | false
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 | 4.3.0.991211
113 |
114 |
115 |
116 |
--------------------------------------------------------------------------------
/iOS/Resources/Images.xcassets/AppIcons.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images": [
3 | {
4 | "size": "29x29",
5 | "scale": "1x",
6 | "idiom": "iphone"
7 | },
8 | {
9 | "size": "29x29",
10 | "scale": "2x",
11 | "idiom": "iphone"
12 | },
13 | {
14 | "size": "29x29",
15 | "scale": "3x",
16 | "idiom": "iphone"
17 | },
18 | {
19 | "size": "40x40",
20 | "scale": "2x",
21 | "idiom": "iphone"
22 | },
23 | {
24 | "size": "40x40",
25 | "scale": "3x",
26 | "idiom": "iphone"
27 | },
28 | {
29 | "size": "57x57",
30 | "scale": "1x",
31 | "idiom": "iphone"
32 | },
33 | {
34 | "size": "57x57",
35 | "scale": "2x",
36 | "idiom": "iphone"
37 | },
38 | {
39 | "size": "60x60",
40 | "scale": "2x",
41 | "idiom": "iphone"
42 | },
43 | {
44 | "size": "60x60",
45 | "scale": "3x",
46 | "idiom": "iphone"
47 | },
48 | {
49 | "size": "29x29",
50 | "scale": "1x",
51 | "idiom": "ipad"
52 | },
53 | {
54 | "size": "29x29",
55 | "scale": "2x",
56 | "idiom": "ipad"
57 | },
58 | {
59 | "size": "40x40",
60 | "scale": "1x",
61 | "idiom": "ipad"
62 | },
63 | {
64 | "size": "40x40",
65 | "scale": "2x",
66 | "idiom": "ipad"
67 | },
68 | {
69 | "size": "50x50",
70 | "scale": "1x",
71 | "idiom": "ipad"
72 | },
73 | {
74 | "size": "50x50",
75 | "scale": "2x",
76 | "idiom": "ipad"
77 | },
78 | {
79 | "size": "72x72",
80 | "scale": "1x",
81 | "idiom": "ipad"
82 | },
83 | {
84 | "size": "72x72",
85 | "scale": "2x",
86 | "idiom": "ipad"
87 | },
88 | {
89 | "size": "76x76",
90 | "scale": "1x",
91 | "idiom": "ipad"
92 | },
93 | {
94 | "size": "76x76",
95 | "scale": "2x",
96 | "idiom": "ipad"
97 | },
98 | {
99 | "size": "120x120",
100 | "scale": "1x",
101 | "idiom": "car"
102 | }
103 | ],
104 | "info": {
105 | "version": 1,
106 | "author": "xcode"
107 | }
108 | }
--------------------------------------------------------------------------------
/iOS/Resources/LaunchScreen.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
21 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
|