Fixed TabViewItem Content BindingContext issue

This commit is contained in:
Javier Suárez Ruiz 2020-05-01 20:39:02 +02:00
Родитель a68387668f
Коммит a431fb7d90
10 изменённых файлов: 313 добавлений и 54 удалений

Просмотреть файл

@ -0,0 +1,114 @@
using System.Collections.ObjectModel;
using TabView.Sample.Models;
using Xamarin.Forms;
namespace TabView.Sample.ViewModels
{
public class PerformanceViewModel : BindableObject
{
public PerformanceViewModel()
{
LoadMonkeys();
}
public ObservableCollection<Monkey> Monkeys1 { get; set; }
public ObservableCollection<Monkey> Monkeys2 { get; set; }
public ObservableCollection<Monkey> Monkeys3 { get; set; }
void LoadMonkeys()
{
Monkeys1 = new ObservableCollection<Monkey>
{
new Monkey
{
Index = 0,
Name = "Baboon",
Location = "Africa & Asia",
Details = "Baboons are African and Arabian Old World monkeys belonging to the genus Papio, part of the subfamily Cercopithecinae.",
Image = "http://upload.wikimedia.org/wikipedia/commons/thumb/f/fc/Papio_anubis_%28Serengeti%2C_2009%29.jpg/200px-Papio_anubis_%28Serengeti%2C_2009%29.jpg",
Color = Color.LightSalmon
},
new Monkey
{
Index = 1,
Name = "Capuchin Monkey",
Location = "Central & South America",
Details = "The capuchin monkeys are New World monkeys of the subfamily Cebinae. Prior to 2011, the subfamily contained only a single genus, Cebus.",
Image = "http://upload.wikimedia.org/wikipedia/commons/thumb/4/40/Capuchin_Costa_Rica.jpg/200px-Capuchin_Costa_Rica.jpg",
Color = Color.LightBlue
},
new Monkey
{
Index = 2,
Name = "Blue Monkey",
Location = "Central and East Africa",
Details = "The blue monkey or diademed monkey is a species of Old World monkey native to Central and East Africa, ranging from the upper Congo River basin east to the East African Rift and south to northern Angola and Zambia",
Image = "http://upload.wikimedia.org/wikipedia/commons/thumb/8/83/BlueMonkey.jpg/220px-BlueMonkey.jpg",
Color = Color.LightSlateGray
}
};
Monkeys2 = new ObservableCollection<Monkey>
{
new Monkey
{
Index = 3,
Name = "Squirrel Monkey",
Location = "Central & South America",
Details = "The squirrel monkeys are the New World monkeys of the genus Saimiri. They are the only genus in the subfamily Saimirinae. The name of the genus Saimiri is of Tupi origin, and was also used as an English name by early researchers.",
Image = "http://upload.wikimedia.org/wikipedia/commons/thumb/2/20/Saimiri_sciureus-1_Luc_Viatour.jpg/220px-Saimiri_sciureus-1_Luc_Viatour.jpg",
Color = Color.Chocolate
},
new Monkey
{
Index = 4,
Name = "Golden Lion Tamarin",
Location = "Brazil",
Details = "The golden lion tamarin also known as the golden marmoset, is a small New World monkey of the family Callitrichidae.",
Image = "http://upload.wikimedia.org/wikipedia/commons/thumb/8/87/Golden_lion_tamarin_portrait3.jpg/220px-Golden_lion_tamarin_portrait3.jpg",
Color = Color.Violet
},
new Monkey
{
Index = 5,
Name = "Howler Monkey",
Location = "South America",
Details = "Howler monkeys are among the largest of the New World monkeys. Fifteen species are currently recognised. Previously classified in the family Cebidae, they are now placed in the family Atelidae.",
Image = "http://upload.wikimedia.org/wikipedia/commons/thumb/0/0d/Alouatta_guariba.jpg/200px-Alouatta_guariba.jpg",
Color = Color.Aqua
}
};
Monkeys3 = new ObservableCollection<Monkey>
{
new Monkey
{
Index = 6,
Name = "Japanese Macaque",
Location = "Japan",
Details = "The Japanese macaque, is a terrestrial Old World monkey species native to Japan. They are also sometimes known as the snow monkey because they live in areas where snow covers the ground for months each",
Image = "http://upload.wikimedia.org/wikipedia/commons/thumb/c/c1/Macaca_fuscata_fuscata1.jpg/220px-Macaca_fuscata_fuscata1.jpg",
Color = Color.OrangeRed
},
new Monkey
{
Index = 7,
Name = "Mandrill",
Location = "Southern Cameroon, Gabon, Equatorial Guinea, and Congo",
Details = "The mandrill is a primate of the Old World monkey family, closely related to the baboons and even more closely to the drill. It is found in southern Cameroon, Gabon, Equatorial Guinea, and Congo.",
Image = "http://upload.wikimedia.org/wikipedia/commons/thumb/7/75/Mandrill_at_san_francisco_zoo.jpg/220px-Mandrill_at_san_francisco_zoo.jpg",
Color = Color.MediumPurple
},
new Monkey
{
Index = 8,
Name = "Proboscis Monkey",
Location = "Borneo",
Details = "The proboscis monkey or long-nosed monkey, known as the bekantan in Malay, is a reddish-brown arboreal Old World monkey that is endemic to the south-east Asian island of Borneo.",
Image = "http://upload.wikimedia.org/wikipedia/commons/thumb/e/e5/Proboscis_Monkey_in_Borneo.jpg/250px-Proboscis_Monkey_in_Borneo.jpg",
Color = Color.Pink
}
};
}
}
}

Просмотреть файл

@ -37,21 +37,24 @@ namespace TabView.Sample.Views
{
var tcs = new TaskCompletionSource<bool>();
Animation resetAnimation = new Animation();
var animationPercentLength = AnimationLength;
if (args.CurrentView != null)
resetAnimation.Add(0, 1, new Animation(v => args.CurrentView.TranslationY = v, args.CurrentView.TranslationY, 0));
if (args.NextView != null)
Device.BeginInvokeOnMainThread(() =>
{
resetAnimation.Add(0, 1, new Animation(v => args.NextView.TranslationY = v, args.NextView.TranslationY, Math.Sign((int)args.Direction) * args.Parent.Height));
animationPercentLength = (uint)(AnimationLength * (args.Parent.Height - Math.Abs(args.NextView.TranslationY)) / args.Parent.Height);
}
Animation resetAnimation = new Animation();
resetAnimation.Commit(args.Parent, nameof(OnSelectionChanged), length: animationPercentLength, easing: AnimationEasing,
finished: (v, t) => tcs.SetResult(true));
var animationPercentLength = AnimationLength;
if (args.CurrentView != null)
resetAnimation.Add(0, 1, new Animation(v => args.CurrentView.TranslationY = v, args.CurrentView.TranslationY, 0));
if (args.NextView != null)
{
resetAnimation.Add(0, 1, new Animation(v => args.NextView.TranslationY = v, args.NextView.TranslationY, Math.Sign((int)args.Direction) * args.Parent.Height));
animationPercentLength = (uint)(AnimationLength * (args.Parent.Height - Math.Abs(args.NextView.TranslationY)) / args.Parent.Height);
}
resetAnimation.Commit(args.Parent, nameof(OnSelectionChanged), length: animationPercentLength, easing: AnimationEasing,
finished: (v, t) => tcs.SetResult(true));
});
return tcs.Task;
}
@ -60,21 +63,24 @@ namespace TabView.Sample.Views
{
var tcs = new TaskCompletionSource<bool>();
Animation completeAnimation = new Animation();
var animationPercentLength = AnimationLength;
if (args.CurrentView != null)
Device.BeginInvokeOnMainThread(() =>
{
completeAnimation.Add(0, 1, new Animation(v => args.CurrentView.TranslationY = v, args.CurrentView.TranslationY, -Math.Sign((int)args.Direction) * args.Parent.Height));
animationPercentLength = (uint)(AnimationLength * (args.Parent.Height - Math.Abs(args.CurrentView.TranslationY)) / args.Parent.Height);
}
Animation completeAnimation = new Animation();
if (args.NextView != null)
completeAnimation.Add(0, 1, new Animation(v => args.NextView.TranslationY = v, args.NextView.TranslationY, 0));
var animationPercentLength = AnimationLength;
completeAnimation.Commit(args.Parent, nameof(OnSelectionChanged), length: animationPercentLength, easing: AnimationEasing,
finished: (v, t) => tcs.SetResult(true));
if (args.CurrentView != null)
{
completeAnimation.Add(0, 1, new Animation(v => args.CurrentView.TranslationY = v, args.CurrentView.TranslationY, -Math.Sign((int)args.Direction) * args.Parent.Height));
animationPercentLength = (uint)(AnimationLength * (args.Parent.Height - Math.Abs(args.CurrentView.TranslationY)) / args.Parent.Height);
}
if (args.NextView != null)
completeAnimation.Add(0, 1, new Animation(v => args.NextView.TranslationY = v, args.NextView.TranslationY, 0));
completeAnimation.Commit(args.Parent, nameof(OnSelectionChanged), length: animationPercentLength, easing: AnimationEasing,
finished: (v, t) => tcs.SetResult(true));
});
return tcs.Task;
}

Просмотреть файл

@ -100,6 +100,10 @@
x:Name="TabStripBackgroundViewBtn"
Text="Animated TabStrip Gallery"
Clicked="OnTabStripBackgroundViewBtnClicked"/>
<Button
x:Name="PerfBtn"
Text="Performance Test Gallery"
Clicked="OnPerfBtnClicked"/>
</StackLayout>
</ScrollView>
</ContentPage.Content>

Просмотреть файл

@ -114,5 +114,10 @@ namespace TabView.Sample.Views
{
Navigation.PushAsync(new TabStripBackgroundViewGallery());
}
void OnPerfBtnClicked(object sender, EventArgs e)
{
Navigation.PushAsync(new PerformanceTestGallery());
}
}
}

Просмотреть файл

@ -0,0 +1,94 @@
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:controls="clr-namespace:Xamarin.Forms.TabView;assembly=Xamarin.Forms.TabView"
xmlns:viewmodels="clr-namespace:TabView.Sample.ViewModels"
x:Class="TabView.Sample.Views.PerformanceTestGallery"
Title="PerformanceTest Gallery">
<ContentPage.Resources>
<ResourceDictionary>
<DataTemplate x:Key="MonkeyItemTemplate">
<Grid
BackgroundColor="{Binding Color}"
Padding="10"
RowSpacing="10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Image
Aspect="AspectFill"
Source="{Binding Image}"/>
<StackLayout
Grid.Column="1">
<Label
Text="{Binding Index}"
HorizontalOptions="Center"/>
<Label
Text="{Binding Name}"
FontSize="Title"
HorizontalOptions="Center"/>
<Label
Text="{Binding Location}"
FontSize="Subtitle"
HorizontalOptions="Center"/>
</StackLayout>
</Grid>
</DataTemplate>
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.BindingContext>
<viewmodels:PerformanceViewModel />
</ContentPage.BindingContext>
<ContentPage.Content>
<Grid>
<controls:TabView
TabStripPlacement="Bottom"
TabStripBackgroundColor="Blue"
TabStripHeight="60"
TabIndicatorColor="Yellow"
TabContentBackgroundColor="White">
<controls:TabViewItem
Icon="triangle.png"
Text="Tab 1"
TextColor="White"
TextColorSelected="Yellow"
FontSize="12">
<Grid
BackgroundColor="Gray">
<CollectionView
ItemsSource="{Binding Monkeys1}"
ItemTemplate="{StaticResource MonkeyItemTemplate}"/>
</Grid>
</controls:TabViewItem>
<controls:TabViewItem
Icon="circle.png"
Text="Tab 2"
TextColor="White"
TextColorSelected="Yellow"
FontSize="12">
<Grid>
<CollectionView
ItemsSource="{Binding Monkeys2}"
ItemTemplate="{StaticResource MonkeyItemTemplate}"/>
</Grid>
</controls:TabViewItem>
<controls:TabViewItem
Icon="square.png"
Text="Tab 3"
TextColor="White"
TextColorSelected="Yellow"
FontSize="12">
<Grid>
<CollectionView
ItemsSource="{Binding Monkeys3}"
ItemTemplate="{StaticResource MonkeyItemTemplate}"/>
</Grid>
</controls:TabViewItem>
</controls:TabView>
</Grid>
</ContentPage.Content>
</ContentPage>

Просмотреть файл

@ -0,0 +1,12 @@
using Xamarin.Forms;
namespace TabView.Sample.Views
{
public partial class PerformanceTestGallery : ContentPage
{
public PerformanceTestGallery()
{
InitializeComponent();
}
}
}

Просмотреть файл

@ -176,7 +176,7 @@ namespace Xamarin.Forms.TabView
var index = position > Position ? (position - 1) : (position + 1);
UpdateOtherViews(index);
var threshold = Width / 2;
var threshold = (Width * CompletedTransitionPercentage) + 1;
double offset = position > Position ? -threshold : threshold;
if (!UpdateBackView(offset))

Просмотреть файл

@ -15,7 +15,7 @@ namespace Xamarin.Forms.TabView
var nextTabTranslationX = Math.Sign((int)args.Direction) * args.Parent.Width + args.Offset;
if (args.NextView != null && Math.Abs(nextTabTranslationX) < args.Parent.Width)
if (args.NextView != null && Math.Abs(nextTabTranslationX) < args.Parent.Width)
args.NextView.TranslationX = nextTabTranslationX;
return Task.FromResult(true);
@ -27,21 +27,24 @@ namespace Xamarin.Forms.TabView
{
var tcs = new TaskCompletionSource<bool>();
Animation resetAnimation = new Animation();
var animationPercentLength = AnimationLength;
if (args.CurrentView != null)
resetAnimation.Add(0, 1, new Animation(v => args.CurrentView.TranslationX = v, args.CurrentView.TranslationX, 0));
if (args.NextView != null)
Device.BeginInvokeOnMainThread(() =>
{
resetAnimation.Add(0, 1, new Animation(v => args.NextView.TranslationX = v, args.NextView.TranslationX, Math.Sign((int)args.Direction) * args.Parent.Width));
animationPercentLength = (uint)(AnimationLength * (args.Parent.Width - Math.Abs(args.NextView.TranslationX)) / args.Parent.Width);
}
Animation resetAnimation = new Animation();
resetAnimation.Commit(args.Parent, nameof(OnSelectionChanged), length: animationPercentLength, easing: AnimationEasing,
finished: (v, t) => tcs.SetResult(true));
var animationPercentLength = AnimationLength;
if (args.CurrentView != null)
resetAnimation.Add(0, 1, new Animation(v => args.CurrentView.TranslationX = v, args.CurrentView.TranslationX, 0));
if (args.NextView != null)
{
resetAnimation.Add(0, 1, new Animation(v => args.NextView.TranslationX = v, args.NextView.TranslationX, Math.Sign((int)args.Direction) * args.Parent.Width));
animationPercentLength = (uint)(AnimationLength * (args.Parent.Width - Math.Abs(args.NextView.TranslationX)) / args.Parent.Width);
}
resetAnimation.Commit(args.Parent, nameof(OnSelectionChanged), length: animationPercentLength, easing: AnimationEasing,
finished: (v, t) => tcs.SetResult(true));
});
return tcs.Task;
}
@ -50,21 +53,24 @@ namespace Xamarin.Forms.TabView
{
var tcs = new TaskCompletionSource<bool>();
Animation completeAnimation = new Animation();
var animationPercentLength = AnimationLength;
if (args.CurrentView != null)
Device.BeginInvokeOnMainThread(() =>
{
completeAnimation.Add(0, 1, new Animation(v => args.CurrentView.TranslationX = v, args.CurrentView.TranslationX, -Math.Sign((int)args.Direction) * args.Parent.Width));
animationPercentLength = (uint)(AnimationLength * (args.Parent.Width - Math.Abs(args.CurrentView.TranslationX)) / args.Parent.Width);
}
Animation completeAnimation = new Animation();
if (args.NextView != null)
completeAnimation.Add(0, 1, new Animation(v => args.NextView.TranslationX = v, args.NextView.TranslationX, 0));
var animationPercentLength = AnimationLength;
completeAnimation.Commit(args.Parent, nameof(OnSelectionChanged), length: animationPercentLength, easing: AnimationEasing,
finished: (v, t) => tcs.SetResult(true));
if (args.CurrentView != null)
{
completeAnimation.Add(0, 1, new Animation(v => args.CurrentView.TranslationX = v, args.CurrentView.TranslationX, -Math.Sign((int)args.Direction) * args.Parent.Width));
animationPercentLength = (uint)(AnimationLength * (args.Parent.Width - Math.Abs(args.CurrentView.TranslationX)) / args.Parent.Width);
}
if (args.NextView != null)
completeAnimation.Add(0, 1, new Animation(v => args.NextView.TranslationX = v, args.NextView.TranslationX, 0));
completeAnimation.Commit(args.Parent, nameof(OnSelectionChanged), length: animationPercentLength, easing: AnimationEasing,
finished: (v, t) => tcs.SetResult(true));
});
return tcs.Task;
}

Просмотреть файл

@ -456,6 +456,17 @@ namespace Xamarin.Forms.TabView
UpdateFlowDirection();
}
protected override void OnBindingContextChanged()
{
base.OnBindingContextChanged();
if (TabItems == null || TabItems.Count == 0)
return;
foreach (var tabViewItem in TabItems)
UpdateTabViewItemBindingContext(tabViewItem);
}
void OnTabViewItemPropertyChanged(object sender, PropertyChangedEventArgs e)
{
var tabViewItem = (TabViewItem)sender;
@ -568,6 +579,14 @@ namespace Xamarin.Forms.TabView
AddTabViewItemFromTemplateToTabStrip(item, index);
}
void UpdateTabViewItemBindingContext(TabViewItem tabViewItem)
{
if (tabViewItem == null || tabViewItem.Content == null)
return;
tabViewItem.Content.BindingContext = BindingContext;
}
void AddSelectionTapRecognizer(View view)
{
var tapRecognizer = new TapGestureRecognizer();

Просмотреть файл

@ -1,5 +1,4 @@
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using System.Windows.Input;