This time from Steve Dunford and the Cross Platform app development team working inside SequenceAgency on some really awesome projects.
They've taken binding code from MvvmCross and inspiration from @CheeseBaron's HorizontalListView and combined them with the Android v3 HorizontalPager in order to provide a new implementation for fast fluid horizontal paging. Code is provided as MS-PL - so expect to see this integrated back into v3 :)
Thanks for contributing back to the project - totally awesome - a badge of awesomeness well deserved!
The code is here:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* BindableViewPager.cs | |
* | |
* Copyright (c) 2012 Tomasz Cielecki (tomasz@ostebaronen.dk) | |
* | |
* The MIT License | |
* Permission is hereby granted, free of charge, to any person obtaining a copy | |
* of this software and associated documentation files (the "Software"), to deal | |
* in the Software without restriction, including without limitation the rights | |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
* copies of the Software, and to permit persons to whom the Software is | |
* furnished to do so, subject to the following conditions: | |
* | |
* The above copyright notice and this permission notice shall be included in | |
* all copies or substantial portions of the Software. | |
* | |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
* THE SOFTWARE. | |
*/ | |
using System.Collections; | |
using System.Windows.Input; | |
using Android.Content; | |
using Android.Support.V4.View; | |
using Android.Util; | |
using Cirrious.MvvmCross.Binding.Attributes; | |
using Cirrious.MvvmCross.Binding.Droid; | |
using Cirrious.MvvmCross.Binding.Droid.Views; | |
using Sequence.TopSecretProject.UI.Droid.Adaptors; | |
namespace Sequence.TopSecretProject.UI.Droid.Controls | |
{ | |
public class BindableViewPager | |
: ViewPager | |
{ | |
public BindableViewPager(Context context, IAttributeSet attrs) | |
: this(context, attrs, new MvxBindablePagerAdapter(context)) | |
{ | |
} | |
public BindableViewPager(Context context, IAttributeSet attrs, MvxBindablePagerAdapter adapter) | |
: base(context, attrs) | |
{ | |
var itemTemplateId = MvxBindableListViewHelpers.ReadAttributeValue(context, attrs, MvxAndroidBindingResource.Instance.BindableListViewStylableGroupId, MvxAndroidBindingResource.Instance.BindableListItemTemplateId); | |
adapter.ItemTemplateId = itemTemplateId; | |
Adapter = adapter; | |
} | |
public new MvxBindablePagerAdapter Adapter | |
{ | |
get { return base.Adapter as MvxBindablePagerAdapter; } | |
set | |
{ | |
var existing = Adapter; | |
if (existing == value) | |
return; | |
if (existing != null && value != null) | |
{ | |
value.ItemsSource = existing.ItemsSource; | |
value.ItemTemplateId = existing.ItemTemplateId; | |
} | |
base.Adapter = value; | |
} | |
} | |
[MvxSetToNullAfterBinding] | |
public IEnumerable ItemsSource | |
{ | |
get { return Adapter.ItemsSource; } | |
set { Adapter.ItemsSource = value; } | |
} | |
public int ItemTemplateId | |
{ | |
get { return Adapter.ItemTemplateId; } | |
set { Adapter.ItemTemplateId = value; } | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections; | |
using System.Collections.Generic; | |
using System.Collections.Specialized; | |
using System.Linq; | |
using System.Text; | |
using Android.App; | |
using Android.Content; | |
using Android.OS; | |
using Android.Runtime; | |
using Android.Support.V4.View; | |
using Android.Views; | |
using Android.Widget; | |
using Cirrious.MvvmCross.Binding; | |
using Cirrious.MvvmCross.Binding.Attributes; | |
using Cirrious.MvvmCross.Binding.Droid.Interfaces.Views; | |
using Cirrious.MvvmCross.Binding.Droid.Views; | |
using Cirrious.MvvmCross.Binding.ExtensionMethods; | |
using Cirrious.MvvmCross.Exceptions; | |
using Cirrious.MvvmCross.Interfaces.Platform.Diagnostics; | |
namespace Sequence.TopSecretProject.UI.Droid.Adaptors | |
{ | |
// MvxBindablePagerAdapter.cs | |
// (c) Copyright Cirrious Ltd. http://www.cirrious.com | |
// MvvmCross is licensed using Microsoft Public License (Ms-PL) | |
// Contributions and inspirations noted in readme.md and license.txt | |
// | |
// Project Lead - Stuart Lodge, @slodge, me@slodge.com | |
public class MvxBindablePagerAdapter | |
: PagerAdapter | |
{ | |
private readonly IMvxBindingActivity _bindingActivity; | |
private readonly Context _context; | |
private int _itemTemplateId; | |
private int _dropDownItemTemplateId; | |
private IEnumerable _itemsSource; | |
public MvxBindablePagerAdapter(Context context) | |
{ | |
_context = context; | |
_bindingActivity = context as IMvxBindingActivity; | |
if (_bindingActivity == null) | |
throw new MvxException( | |
"MvxBindableListView can only be used within a Context which supports IMvxBindingActivity"); | |
} | |
protected Context Context | |
{ | |
get { return _context; } | |
} | |
protected IMvxBindingActivity BindingActivity | |
{ | |
get { return _bindingActivity; } | |
} | |
public int SimpleViewLayoutId { get; set; } | |
[MvxSetToNullAfterBinding] | |
public IEnumerable ItemsSource | |
{ | |
get { return _itemsSource; } | |
set { SetItemsSource(value); } | |
} | |
public int ItemTemplateId | |
{ | |
get { return _itemTemplateId; } | |
set | |
{ | |
if (_itemTemplateId == value) | |
return; | |
_itemTemplateId = value; | |
// since the template has changed then let's force the list to redisplay by firing NotifyDataSetChanged() | |
if (_itemsSource != null) | |
NotifyDataSetChanged(); | |
} | |
} | |
public int DropDownItemTemplateId | |
{ | |
get { return _dropDownItemTemplateId; } | |
set | |
{ | |
if (_dropDownItemTemplateId == value) | |
return; | |
_dropDownItemTemplateId = value; | |
// since the template has changed then let's force the list to redisplay by firing NotifyDataSetChanged() | |
if (_itemsSource != null) | |
NotifyDataSetChanged(); | |
} | |
} | |
public override int Count | |
{ | |
get { return _itemsSource.Count(); } | |
} | |
protected virtual void SetItemsSource(IEnumerable value) | |
{ | |
if (_itemsSource == value) | |
return; | |
var existingObservable = _itemsSource as INotifyCollectionChanged; | |
if (existingObservable != null) | |
existingObservable.CollectionChanged -= OnItemsSourceCollectionChanged; | |
_itemsSource = value; | |
if (_itemsSource != null && !(_itemsSource is IList)) | |
MvxBindingTrace.Trace(MvxTraceLevel.Warning, | |
"Binding to IEnumerable rather than IList - this can be inefficient, especially for large lists"); | |
var newObservable = _itemsSource as INotifyCollectionChanged; | |
if (newObservable != null) | |
newObservable.CollectionChanged += OnItemsSourceCollectionChanged; | |
NotifyDataSetChanged(); | |
} | |
private void OnItemsSourceCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) | |
{ | |
NotifyDataSetChanged(e); | |
} | |
public virtual void NotifyDataSetChanged(NotifyCollectionChangedEventArgs e) | |
{ | |
base.NotifyDataSetChanged(); | |
} | |
public int GetPosition(object item) | |
{ | |
return _itemsSource.GetPosition(item); | |
} | |
public System.Object GetRawItem(int position) | |
{ | |
return _itemsSource.ElementAt(position); | |
} | |
private View GetView(int position, View convertView, ViewGroup parent, int templateId) | |
{ | |
if (_itemsSource == null) | |
{ | |
MvxBindingTrace.Trace(MvxTraceLevel.Error, "GetView called when ItemsSource is null"); | |
return null; | |
} | |
// 15 Oct 2012 - this position check removed as it's inefficient, especially for IEnumerable based collections | |
/* | |
if (position < 0 || position >= Count) | |
{ | |
MvxBindingTrace.Trace(MvxTraceLevel.Error, "GetView called with invalid Position - zero indexed {0} out of {1}", position, Count); | |
return null; | |
} | |
*/ | |
var source = GetRawItem(position); | |
return GetBindableView(convertView, source, templateId); | |
} | |
protected virtual View GetSimpleView(View convertView, object source) | |
{ | |
if (convertView == null) | |
{ | |
convertView = CreateSimpleView(source); | |
} | |
else | |
{ | |
BindSimpleView(convertView, source); | |
} | |
return convertView; | |
} | |
protected virtual void BindSimpleView(View convertView, object source) | |
{ | |
var textView = convertView as TextView; | |
if (textView != null) | |
{ | |
textView.Text = (source ?? string.Empty).ToString(); | |
} | |
} | |
protected virtual View CreateSimpleView(object source) | |
{ | |
var view = _bindingActivity.NonBindingInflate(SimpleViewLayoutId, null); | |
BindSimpleView(view, source); | |
return view; | |
} | |
protected virtual View GetBindableView(View convertView, object source) | |
{ | |
return GetBindableView(convertView, source, ItemTemplateId); | |
} | |
protected virtual View GetBindableView(View convertView, object source, int templateId) | |
{ | |
if (templateId == 0) | |
{ | |
// no template seen - so use a standard string view from Android and use ToString() | |
return GetSimpleView(convertView, source); | |
} | |
// we have a templateid so lets use bind and inflate on it :) | |
var viewToUse = convertView as IMvxBindableListItemView; | |
if (viewToUse != null) | |
{ | |
if (viewToUse.TemplateId != templateId) | |
{ | |
viewToUse = null; | |
} | |
} | |
if (viewToUse == null) | |
{ | |
viewToUse = CreateBindableView(source, templateId); | |
} | |
else | |
{ | |
BindBindableView(source, viewToUse); | |
} | |
return viewToUse as View; | |
} | |
protected virtual void BindBindableView(object source, IMvxBindableListItemView viewToUse) | |
{ | |
viewToUse.BindTo(source); | |
} | |
protected virtual MvxBindableListItemView CreateBindableView(object source, int templateId) | |
{ | |
return new MvxBindableListItemView(_context, _bindingActivity, templateId, source); | |
} | |
public override Java.Lang.Object InstantiateItem(ViewGroup container, int position) | |
{ | |
var view = GetView(position, null, null, 0); | |
container.AddView(view); | |
return view; | |
} | |
public override void DestroyItem(ViewGroup container, int position, Java.Lang.Object obj) | |
{ | |
var view = (MvxBindableListItemView) obj; | |
container.RemoveView(view); | |
view.Dispose(); | |
} | |
public override bool IsViewFromObject(View p0, Java.Lang.Object p1) | |
{ | |
return p0 == p1; | |
} | |
} | |
} | |
No comments:
Post a Comment