Skip to content

Instantly share code, notes, and snippets.

@RedTahr
Created January 6, 2016 20:01
Show Gist options
  • Save RedTahr/9474b7b1fd5c305b5e20 to your computer and use it in GitHub Desktop.
Save RedTahr/9474b7b1fd5c305b5e20 to your computer and use it in GitHub Desktop.
My copy of chrisriesgo / xamarin-forms-carouselview using Montemagno's FrenchPressTimer (see gist > Timer.cs)
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
// using System.Timers;
using Xamarin.Forms;
namespace ....Core.Control
{
public class CarouselLayout : ScrollView, IDisposable
{
public enum IndicatorStyleEnum
{
None,
Dots,
Tabs
}
readonly StackLayout stack;
Timer selectedItemTimer;
int selectedIndex;
readonly int timerDelayWhenSliding = 300;
public CarouselLayout()
{
Orientation = ScrollOrientation.Horizontal;
stack = new StackLayout
{
Orientation = StackOrientation.Horizontal,
Spacing = 0
};
Content = stack;
selectedItemTimerStop();
selectedItemTimerStart();
//_selectedItemTimer = new Timer
//{
// AutoReset = false,
// Interval = 300
//};
//_selectedItemTimer.Elapsed += SelectedItemTimerElapsed;
}
public IndicatorStyleEnum IndicatorStyle { get; set; }
public IList<Xamarin.Forms.View> Children {
get {
return stack.Children;
}
}
private bool _layingOutChildren;
protected override void LayoutChildren(double x, double y, double width, double height)
{
base.LayoutChildren(x, y, width, height);
if (_layingOutChildren) return;
_layingOutChildren = true;
foreach (var child in Children) child.WidthRequest = width;
_layingOutChildren = false;
}
public static readonly BindableProperty SelectedIndexProperty =
BindableProperty.Create<CarouselLayout, int>(
carousel => carousel.SelectedIndex,
0,
BindingMode.TwoWay,
propertyChanged: (bindable, oldValue, newValue) => {
((CarouselLayout)bindable).UpdateSelectedItem();
}
);
public int SelectedIndex {
get {
return (int)GetValue(SelectedIndexProperty);
}
set {
SetValue(SelectedIndexProperty, value);
}
}
void UpdateSelectedItem()
{
selectedItemTimerStop();
selectedItemTimerStart();
//_selectedItemTimer.Stop();
//_selectedItemTimer.Start();
}
void SelectedItemTimerCallback(object args)
{
// check children has a count, otherwise windows phone throws an out of range exception, why the others don't I'm not sure, haven't looked into it.
SelectedItem = SelectedIndex > -1 && Children?.Count > 0 ? Children[SelectedIndex].BindingContext : null;
selectedItemTimerStop();
}
//void SelectedItemTimerElapsed(object sender, ElapsedEventArgs e)
//{
// SelectedItem = SelectedIndex > -1 ? Children[SelectedIndex].BindingContext : null;
//}
public static readonly BindableProperty ItemsSourceProperty =
BindableProperty.Create<CarouselLayout, IList>(
view => view.ItemsSource,
null,
propertyChanging: (bindableObject, oldValue, newValue) => {
((CarouselLayout)bindableObject).ItemsSourceChanging();
},
propertyChanged: (bindableObject, oldValue, newValue) => {
((CarouselLayout)bindableObject).ItemsSourceChanged();
}
);
public IList ItemsSource {
get {
return (IList)GetValue(ItemsSourceProperty);
}
set {
SetValue(ItemsSourceProperty, value);
}
}
void ItemsSourceChanging()
{
if (ItemsSource == null) return;
selectedIndex = ItemsSource.IndexOf(SelectedItem);
}
void ItemsSourceChanged()
{
stack.Children.Clear();
foreach (var item in ItemsSource)
{
var view = (Xamarin.Forms.View)ItemTemplate.CreateContent();
var bindableObject = view as BindableObject;
if (bindableObject != null)
bindableObject.BindingContext = item;
stack.Children.Add(view);
}
if (selectedIndex >= 0) SelectedIndex = selectedIndex;
}
public DataTemplate ItemTemplate {
get;
set;
}
public static readonly BindableProperty SelectedItemProperty =
BindableProperty.Create<CarouselLayout, object>(
view => view.SelectedItem,
null,
BindingMode.TwoWay,
propertyChanged: (bindable, oldValue, newValue) => {
((CarouselLayout)bindable).UpdateSelectedIndex();
}
);
public object SelectedItem {
get {
return GetValue(SelectedItemProperty);
}
set {
SetValue(SelectedItemProperty, value);
}
}
void UpdateSelectedIndex()
{
if (SelectedItem == BindingContext) return;
SelectedIndex = Children
.Select(c => c.BindingContext)
.ToList()
.IndexOf(SelectedItem);
}
private void selectedItemTimerStop()
{
if (selectedItemTimer != null)
{
selectedItemTimer.Dispose();
selectedItemTimer = null;
}
}
private void selectedItemTimerStart()
{
if (selectedItemTimer == null)
{
selectedItemTimer = new Timer(SelectedItemTimerCallback, null, timerDelayWhenSliding, timerDelayWhenSliding);
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool flag)
{
selectedItemTimer.Dispose();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment