Merge branch '3.1.0'
This commit is contained in:
Коммит
67d2be4cd2
|
@ -10,7 +10,7 @@
|
|||
<iconUrl>http://xamarin.com/content/images/nuget/xamarin.png</iconUrl>
|
||||
<projectUrl>http://xamarin.com/forms</projectUrl>
|
||||
<requireLicenseAcceptance>true</requireLicenseAcceptance>
|
||||
<description>Build native UIs for iOS, Android, and Windows Phone from a single, shared C# codebase</description>
|
||||
<description>Build native UIs for iOS, Android, UWP, macOS, Tizen and many more from a single, shared C# codebase</description>
|
||||
<copyright>© Microsoft Corporation. All rights reserved.</copyright>
|
||||
<dependencies>
|
||||
<group targetFramework="MonoAndroid10">
|
||||
|
|
|
@ -0,0 +1,302 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Xamarin.Forms.CustomAttributes;
|
||||
using Xamarin.Forms.Internals;
|
||||
using Xamarin.Forms.PlatformConfiguration;
|
||||
using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
|
||||
using System.Collections.Specialized;
|
||||
|
||||
#if UITEST
|
||||
using NUnit.Framework;
|
||||
using Xamarin.UITest;
|
||||
#endif
|
||||
|
||||
namespace Xamarin.Forms.Controls.Issues
|
||||
{
|
||||
[Preserve(AllMembers = true)]
|
||||
[Issue(IssueTracker.Github, 1675, "Bottom Tabbed Page Basic Test", PlatformAffected.All)]
|
||||
public class BottomTabbedPageTests : TestTabbedPage
|
||||
{
|
||||
Label pageCountLabel = null;
|
||||
public BottomTabbedPageTests() : base()
|
||||
{
|
||||
}
|
||||
|
||||
protected override void Init()
|
||||
{
|
||||
On<Android>().SetToolbarPlacement(ToolbarPlacement.Bottom);
|
||||
|
||||
pageCountLabel = new Label() { AutomationId = "PageCount" };
|
||||
var popButton1 = new Button() { Text = "Pop", BackgroundColor = Color.Blue };
|
||||
popButton1.Clicked += (s, a) => Navigation.PopModalAsync();
|
||||
|
||||
var popButton2 = new Button() { Text = "Pop 2", BackgroundColor = Color.Blue };
|
||||
popButton2.Clicked += (s, a) => Navigation.PopModalAsync();
|
||||
|
||||
var longerTest = new Button() { Text = "Manual Color Tests", BackgroundColor = Color.Blue };
|
||||
|
||||
Children.Add(new ContentPage() { Title = "Page 1", Content = popButton1, Icon = "coffee.png" });
|
||||
Children.Add(new ContentPage() { Title = "Page 2", Content = popButton2, Icon = "bank.png" });
|
||||
Button btnChangeBarText = null;
|
||||
Button btnChangeBarItemColorText = null;
|
||||
Button btnChangeBarSelectedItemColorText = null;
|
||||
Button btnAddPage = null;
|
||||
Button btnRemovePage = null;
|
||||
Label lblSuccess = new Label() { AutomationId = "Outcome" };
|
||||
|
||||
btnChangeBarText = new Button()
|
||||
{
|
||||
Text = "Change Bar Text",
|
||||
Command = new Command(() =>
|
||||
{
|
||||
if (BarTextColor == Color.Default)
|
||||
{
|
||||
BarTextColor = Color.HotPink;
|
||||
btnChangeBarText.Text = $"Bar Text: HotPink";
|
||||
}
|
||||
else
|
||||
{
|
||||
BarTextColor = Color.Default;
|
||||
btnChangeBarText.Text = $"Bar Text: Default";
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
|
||||
btnChangeBarItemColorText = new Button()
|
||||
{
|
||||
Text = "Change Item Color",
|
||||
Command = new Command(() =>
|
||||
{
|
||||
if (On<Android>().GetBarItemColor() == Color.Default)
|
||||
{
|
||||
On<Android>().SetBarItemColor(new Color(0, 255, 0, 128));
|
||||
btnChangeBarItemColorText.Text = $"Item Color: Less Green";
|
||||
}
|
||||
else
|
||||
{
|
||||
On<Android>().SetBarItemColor(Color.Default);
|
||||
btnChangeBarItemColorText.Text = $"Item Color: Default";
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
|
||||
btnChangeBarSelectedItemColorText = new Button()
|
||||
{
|
||||
Text = "Change Selected Item Color",
|
||||
Command = new Command(() =>
|
||||
{
|
||||
if (On<Android>().GetBarSelectedItemColor() == Color.Default)
|
||||
{
|
||||
On<Android>().SetBarSelectedItemColor(Color.Green);
|
||||
btnChangeBarSelectedItemColorText.Text = $"Selected Item Color: Green";
|
||||
}
|
||||
else
|
||||
{
|
||||
On<Android>().SetBarSelectedItemColor(Color.Default);
|
||||
btnChangeBarSelectedItemColorText.Text = $"Selected Item Color: Default";
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
btnAddPage = new Button()
|
||||
{
|
||||
Text = $"Add Page (more than {On<Android>().GetMaxItemCount()} will crash)",
|
||||
Command = new Command(() =>
|
||||
{
|
||||
Children.Add(new ContentPage()
|
||||
{
|
||||
Content = new Label() { Text = (Children.Count + 1).ToString() },
|
||||
Title = (Children.Count + 1).ToString(),
|
||||
Icon = "calculator.png"
|
||||
});
|
||||
btnRemovePage.IsEnabled = true;
|
||||
}),
|
||||
AutomationId = "AddPage"
|
||||
};
|
||||
|
||||
btnRemovePage = new Button()
|
||||
{
|
||||
Text = "Remove Page",
|
||||
Command = new Command(() =>
|
||||
{
|
||||
Children.Remove(Children.Last());
|
||||
if (Children.Count == 3)
|
||||
{
|
||||
btnRemovePage.IsEnabled = false;
|
||||
}
|
||||
}),
|
||||
IsEnabled = false,
|
||||
AutomationId = "RemovePage"
|
||||
};
|
||||
|
||||
var layout = new StackLayout()
|
||||
{
|
||||
Children =
|
||||
{
|
||||
btnChangeBarText,
|
||||
new Button()
|
||||
{
|
||||
Text = "Change Bar Background Color",
|
||||
Command = new Command(()=>
|
||||
{
|
||||
if(BarBackgroundColor == Color.Default)
|
||||
BarBackgroundColor = Color.Fuchsia;
|
||||
else
|
||||
BarBackgroundColor = Color.Default;
|
||||
})
|
||||
},
|
||||
btnAddPage,
|
||||
btnRemovePage,
|
||||
new Button()
|
||||
{
|
||||
Text = "Page Add/Remove Permutations",
|
||||
Command = new Command(() =>
|
||||
{
|
||||
while(Children.Count > 3)
|
||||
{
|
||||
Children.Remove(Children.Last());
|
||||
}
|
||||
|
||||
Children.Insert(1, new ContentPage(){ Icon = "bank.png" });
|
||||
Children.Insert(1, new ContentPage(){ Icon = "bank.png" });
|
||||
int i = 0;
|
||||
Device.StartTimer(TimeSpan.FromSeconds(3), () =>
|
||||
{
|
||||
if(i == 0)
|
||||
{
|
||||
// Ensure inserting didn't change current page
|
||||
if (CurrentPage != Children[4])
|
||||
{
|
||||
throw new Exception("Inserting page caused Current Page to Change");
|
||||
}
|
||||
Children.RemoveAt(1);
|
||||
}
|
||||
else if(i == 1)
|
||||
{
|
||||
// Ensure removing didn't change current page
|
||||
if (CurrentPage != Children[3])
|
||||
{
|
||||
throw new Exception("Removing page caused Current Page to Change");
|
||||
}
|
||||
Children.Insert(1, new ContentPage(){ Icon = "bank.png" });
|
||||
CurrentPage = Children[1];
|
||||
}
|
||||
else if(i == 2)
|
||||
{
|
||||
if (CurrentPage != Children[1])
|
||||
{
|
||||
throw new Exception("Current Page not correctly set to new page inserted");
|
||||
}
|
||||
|
||||
Children.RemoveAt(1);
|
||||
Children.RemoveAt(1);
|
||||
}
|
||||
else if(i == 3)
|
||||
{
|
||||
if(CurrentPage != Children[0])
|
||||
{
|
||||
throw new Exception("Current Page not reset to Page one after Current Page was Removed");
|
||||
}
|
||||
CurrentPage = Children.Last();
|
||||
lblSuccess.Text = "Success";
|
||||
}
|
||||
else if(i >= 4)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
i++;
|
||||
return true;
|
||||
});
|
||||
})
|
||||
},
|
||||
pageCountLabel,
|
||||
lblSuccess
|
||||
},
|
||||
};
|
||||
|
||||
if (Device.RuntimePlatform == Device.Android)
|
||||
{
|
||||
layout.Children.Insert(1, btnChangeBarItemColorText);
|
||||
layout.Children.Insert(2, btnChangeBarSelectedItemColorText);
|
||||
}
|
||||
|
||||
Children.Add(new ContentPage()
|
||||
{
|
||||
Title = "Test",
|
||||
Content = layout,
|
||||
Icon = "calculator.png"
|
||||
});
|
||||
}
|
||||
|
||||
protected override void OnCurrentPageChanged()
|
||||
{
|
||||
base.OnCurrentPageChanged();
|
||||
pageCountLabel.Text = $"{Children.Count} Pages";
|
||||
}
|
||||
|
||||
protected override void OnPagesChanged(NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
base.OnPagesChanged(e);
|
||||
pageCountLabel.Text = $"{Children.Count} Pages";
|
||||
}
|
||||
|
||||
#if UITEST
|
||||
[Test]
|
||||
public async Task AddAndRemovePages()
|
||||
{
|
||||
RunningApp.WaitForElement(q => q.Marked("Test"));
|
||||
RunningApp.Tap(q => q.Marked("Test"));
|
||||
RunningApp.WaitForElement(q => q.Marked("3 Pages"));
|
||||
RunningApp.Tap(q => q.Button("AddPage"));
|
||||
RunningApp.WaitForElement(q => q.Marked("4 Pages"));
|
||||
RunningApp.Tap(q => q.Button("AddPage"));
|
||||
RunningApp.WaitForElement(q => q.Marked("5 Pages"));
|
||||
RunningApp.Tap(q => q.Button("RemovePage"));
|
||||
RunningApp.WaitForElement(q => q.Marked("4 Pages"));
|
||||
RunningApp.Tap(q => q.Button("RemovePage"));
|
||||
RunningApp.WaitForElement(q => q.Marked("3 Pages"));
|
||||
RunningApp.Tap(q => q.Button("Page Add/Remove Permutations"));
|
||||
// This test cakes about 12 seconds so just adding a delay so WaitForElement doesn't time out
|
||||
await Task.Delay(10000);
|
||||
RunningApp.WaitForElement(q => q.Marked("Success"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void BottomTabbedPageWithModalIssueTestsAllElementsPresent()
|
||||
{
|
||||
RunningApp.WaitForElement(q => q.Marked("Page 1"));
|
||||
RunningApp.WaitForElement(q => q.Marked("Page 2"));
|
||||
RunningApp.WaitForElement(q => q.Button("Pop"));
|
||||
|
||||
RunningApp.Screenshot("All elements present");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void BottomTabbedPageWithModalIssueTestsPopFromFirstTab()
|
||||
{
|
||||
RunningApp.Tap(q => q.Button("Pop"));
|
||||
RunningApp.WaitForElement(q => q.Marked("Bug Repro's"));
|
||||
|
||||
RunningApp.Screenshot("Popped from first tab");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void BottomTabbedPageWithModalIssueTestsPopFromSecondTab()
|
||||
{
|
||||
RunningApp.Tap(q => q.Marked("Page 2"));
|
||||
RunningApp.WaitForElement(q => q.Button("Pop 2"));
|
||||
RunningApp.Screenshot("On second tab");
|
||||
|
||||
RunningApp.Tap(q => q.Button("Pop 2"));
|
||||
RunningApp.WaitForElement(q => q.Marked("Bug Repro's"));
|
||||
RunningApp.Screenshot("Popped from second tab");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
|
@ -18,7 +18,8 @@ namespace Xamarin.Forms.Controls.Issues
|
|||
Content = new StackLayout
|
||||
{
|
||||
Children = {
|
||||
new Button { Text = "Call 123 4567", AutomationId = "tel", Command = new Command(() => Device.OpenUri(new System.Uri("tel:123 4567"))) }
|
||||
new Button { Text = "Call 123 4567", AutomationId = "tel", Command = new Command(() => Device.OpenUri(new System.Uri("tel:123 4567"))) },
|
||||
new Button { Text = "Mail support@xamarin.com", AutomationId = "mailto", Command = new Command(() => Device.OpenUri(new System.Uri("mailto:support@xamarin.com"))) }
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Xamarin.Forms.CustomAttributes;
|
||||
using Xamarin.Forms.Internals;
|
||||
|
||||
namespace Xamarin.Forms.Controls.Issues
|
||||
{
|
||||
[Preserve(AllMembers = true)]
|
||||
[Issue(IssueTracker.Github, 1760, "Content set after an await is not visible", PlatformAffected.Android)]
|
||||
public class Issue1760 : TestMasterDetailPage
|
||||
{
|
||||
const string Before = "Before";
|
||||
const string After = "After";
|
||||
const int Wait = 3;
|
||||
|
||||
protected override void Init()
|
||||
{
|
||||
Master = new _1760Master();
|
||||
Detail = new _1760TestPage();
|
||||
IsPresented = true;
|
||||
}
|
||||
|
||||
[Preserve(AllMembers = true)]
|
||||
public class _1760Master : ContentPage
|
||||
{
|
||||
public _1760Master()
|
||||
{
|
||||
var instructions = new Label { Text = $"Select one of the menu items. The detail page text should change to {Before}. After {Wait} seconds the text should change to {After}." };
|
||||
|
||||
var menuView = new ListView(ListViewCachingStrategy.RetainElement)
|
||||
{
|
||||
ItemsSource = new List<string> { "Test Page 1", "Test Page 2" }
|
||||
};
|
||||
|
||||
menuView.ItemSelected += OnMenuClicked;
|
||||
|
||||
Content = new StackLayout{Children = { instructions, menuView }};
|
||||
Title = "GH 1760 Test App";
|
||||
}
|
||||
|
||||
void OnMenuClicked(object sender, SelectedItemChangedEventArgs e)
|
||||
{
|
||||
var mainPage = (MasterDetailPage)Parent;
|
||||
mainPage.Detail = new _1760TestPage();
|
||||
mainPage.IsPresented = false;
|
||||
}
|
||||
}
|
||||
|
||||
[Preserve(AllMembers = true)]
|
||||
public class _1760TestPage : ContentPage
|
||||
{
|
||||
public async Task DisplayPage()
|
||||
{
|
||||
IsBusy = true;
|
||||
HeaderPageContent = new Label {Text = Before, TextColor = Color.Black};
|
||||
|
||||
await Task.Delay(Wait * 1000);
|
||||
|
||||
HeaderPageContent = new Label { Text = After, TextColor = Color.Black};
|
||||
IsBusy = false;
|
||||
}
|
||||
|
||||
ContentView _headerPageContent;
|
||||
public View HeaderPageContent
|
||||
{
|
||||
set => _headerPageContent.Content = value;
|
||||
}
|
||||
|
||||
public _1760TestPage()
|
||||
{
|
||||
CreateHeaderPage();
|
||||
DisplayPage();
|
||||
}
|
||||
|
||||
void CreateHeaderPage()
|
||||
{
|
||||
|
||||
_headerPageContent = new ContentView
|
||||
{
|
||||
Content = new Label { Text = "_1760 Test Page Content" },
|
||||
BackgroundColor = Color.White,
|
||||
Margin = 40
|
||||
};
|
||||
|
||||
Title = "_1760 Test Page";
|
||||
|
||||
Content = new ScrollView
|
||||
{
|
||||
Content = _headerPageContent
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Timers;
|
||||
using Xamarin.Forms.CustomAttributes;
|
||||
using Xamarin.Forms.Internals;
|
||||
|
||||
namespace Xamarin.Forms.Controls.Issues
|
||||
{
|
||||
[Preserve(AllMembers = true)]
|
||||
[Issue(IssueTracker.Github, 2595, "ScrollView.Content is not re-layouted on Android", PlatformAffected.Android)]
|
||||
public class Issue2595 : TestMasterDetailPage
|
||||
{
|
||||
protected override void Init()
|
||||
{
|
||||
Master = new _2595Master();
|
||||
Detail = new _2595ScrollPage();
|
||||
IsPresented = true;
|
||||
}
|
||||
|
||||
[Preserve(AllMembers = true)]
|
||||
public class _2595Master : ContentPage
|
||||
{
|
||||
public _2595Master()
|
||||
{
|
||||
var instructions = new Label { Text = $"Select one of the menu items. The detail page text should "
|
||||
+ $"display a label which disappears after 1 second and is"
|
||||
+ $" replaced by an updating list of labels which grows vertically." };
|
||||
|
||||
var menuView = new ListView(ListViewCachingStrategy.RetainElement)
|
||||
{
|
||||
ItemsSource = new List<string> { "Test Page 1", "Test Page 2" }
|
||||
};
|
||||
|
||||
menuView.ItemSelected += OnMenuClicked;
|
||||
|
||||
Content = new StackLayout{Children = { instructions, menuView }};
|
||||
Title = "GH 2595 Test App";
|
||||
}
|
||||
|
||||
void OnMenuClicked(object sender, SelectedItemChangedEventArgs e)
|
||||
{
|
||||
var mainPage = (MasterDetailPage)Parent;
|
||||
mainPage.Detail = new _2595ScrollPage ();
|
||||
mainPage.IsPresented = false;
|
||||
}
|
||||
}
|
||||
|
||||
[Preserve(AllMembers = true)]
|
||||
public class _2595ScrollPage : ContentPage
|
||||
{
|
||||
readonly Timer _timer = new Timer(1000);
|
||||
protected Label Label;
|
||||
|
||||
public _2595ScrollPage() {
|
||||
Content = new ScrollView {
|
||||
|
||||
BackgroundColor = Color.Red,
|
||||
|
||||
Content = new StackLayout {
|
||||
BackgroundColor = Color.BlueViolet,
|
||||
Children = {
|
||||
(Label = new Label {
|
||||
Text = "this text should disappear after 1 sec",
|
||||
BackgroundColor = Color.LightBlue,
|
||||
HorizontalOptions = LayoutOptions.StartAndExpand,
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected StackLayout ScrollContent {
|
||||
get => (Content as ScrollView).Content as StackLayout;
|
||||
set => (Content as ScrollView).Content = value;
|
||||
}
|
||||
|
||||
protected override void OnAppearing() {
|
||||
base.OnAppearing();
|
||||
_timer.Elapsed += (s, e) => Device.BeginInvokeOnMainThread(OnTimerElapsed);
|
||||
|
||||
_timer.Start();
|
||||
}
|
||||
|
||||
void OnTimerElapsed() {
|
||||
Label.Text = $"{ DateTime.Now.ToString() }: expecting {ScrollContent?.Children.Count} dates to show up.";
|
||||
ScrollContent.Children.Add(new Label { Text = DateTime.Now.ToString() });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -250,6 +250,7 @@
|
|||
<Compile Include="$(MSBuildThisFileDirectory)Issue1415.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Issue2247.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)GroupListViewHeaderIndexOutOfRange.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Issue1760.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Issue1975.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Issue1601.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Issue1717.cs" />
|
||||
|
@ -304,6 +305,7 @@
|
|||
<Compile Include="$(MSBuildThisFileDirectory)Issue1908.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Issue1672.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Issue2394.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Issue2595.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Issue2983.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Issue2963.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Issue2981.cs" />
|
||||
|
@ -372,6 +374,7 @@
|
|||
</Compile>
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Bugzilla53179_1.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)RestartAppTest.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)BottomTabbedPageTests.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)TestPages\QuickCollectNavigationPage.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)TestPages\ScreenshotConditionalApp.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Bugzilla41842.cs" />
|
||||
|
|
|
@ -6,9 +6,9 @@ using Xamarin.Forms.Controls.GalleryPages;
|
|||
using Xamarin.Forms.CustomAttributes;
|
||||
using Xamarin.Forms.Internals;
|
||||
using Xamarin.Forms.PlatformConfiguration;
|
||||
using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
|
||||
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
|
||||
using Xamarin.Forms.Controls.GalleryPages.VisualStateManagerGalleries;
|
||||
|
||||
namespace Xamarin.Forms.Controls
|
||||
{
|
||||
[Preserve(AllMembers = true)]
|
||||
|
@ -19,37 +19,38 @@ namespace Xamarin.Forms.Controls
|
|||
[Preserve(AllMembers = true)]
|
||||
internal class CoreCarouselPage : CarouselPage
|
||||
{
|
||||
public CoreCarouselPage ()
|
||||
public CoreCarouselPage()
|
||||
{
|
||||
AutomationId = "CarouselPageRoot";
|
||||
Children.Add (new CoreRootPage (this, NavigationBehavior.PushModalAsync) { Title = "Page 1" });
|
||||
Children.Add (new CoreRootPage (this, NavigationBehavior.PushModalAsync) { Title = "Page 2" });
|
||||
Children.Add(new CoreRootPage(this, NavigationBehavior.PushModalAsync) { Title = "Page 1" });
|
||||
Children.Add(new CoreRootPage(this, NavigationBehavior.PushModalAsync) { Title = "Page 2" });
|
||||
}
|
||||
}
|
||||
[Preserve(AllMembers = true)]
|
||||
internal class CoreContentPage : ContentPage
|
||||
{
|
||||
public CoreContentPage ()
|
||||
public CoreContentPage()
|
||||
{
|
||||
On<iOS>().SetUseSafeArea(true);
|
||||
AutomationId = "ContentPageRoot";
|
||||
Content = new StackLayout { Children = { new CoreRootView (), new CorePageView (this, NavigationBehavior.PushModalAsync) } };
|
||||
Content = new StackLayout { Children = { new CoreRootView(), new CorePageView(this, NavigationBehavior.PushModalAsync) } };
|
||||
}
|
||||
}
|
||||
[Preserve(AllMembers = true)]
|
||||
internal class CoreMasterDetailPage : MasterDetailPage
|
||||
{
|
||||
public CoreMasterDetailPage ()
|
||||
public CoreMasterDetailPage()
|
||||
{
|
||||
AutomationId = "MasterDetailPageRoot";
|
||||
|
||||
var toCrashButton = new Button {Text = "Crash Me"};
|
||||
var toCrashButton = new Button { Text = "Crash Me" };
|
||||
|
||||
var masterPage = new ContentPage {Title = "Menu", Icon = "bank.png", Content = toCrashButton};
|
||||
var detailPage = new CoreRootPage (this, NavigationBehavior.PushModalAsync) { Title = "DetailPage" };
|
||||
var masterPage = new ContentPage { Title = "Menu", Icon = "bank.png", Content = toCrashButton };
|
||||
var detailPage = new CoreRootPage(this, NavigationBehavior.PushModalAsync) { Title = "DetailPage" };
|
||||
|
||||
bool toggle = false;
|
||||
toCrashButton.Clicked += (sender, args) => {
|
||||
toCrashButton.Clicked += (sender, args) =>
|
||||
{
|
||||
if (toggle)
|
||||
Detail = new ContentPage { BackgroundColor = Color.Green, };
|
||||
else
|
||||
|
@ -65,14 +66,15 @@ namespace Xamarin.Forms.Controls
|
|||
[Preserve(AllMembers = true)]
|
||||
internal class CoreNavigationPage : NavigationPage
|
||||
{
|
||||
public CoreNavigationPage ()
|
||||
public CoreNavigationPage()
|
||||
{
|
||||
AutomationId = "NavigationPageRoot";
|
||||
|
||||
BarBackgroundColor = Color.Maroon;
|
||||
BarTextColor = Color.Yellow;
|
||||
|
||||
Device.StartTimer(TimeSpan.FromSeconds(2), () => {
|
||||
Device.StartTimer(TimeSpan.FromSeconds(2), () =>
|
||||
{
|
||||
BarBackgroundColor = Color.Default;
|
||||
BarTextColor = Color.Default;
|
||||
|
||||
|
@ -80,29 +82,45 @@ namespace Xamarin.Forms.Controls
|
|||
});
|
||||
|
||||
On<iOS>().SetPrefersLargeTitles(true);
|
||||
|
||||
Navigation.PushAsync (new CoreRootPage (this));
|
||||
|
||||
Navigation.PushAsync(new CoreRootPage(this));
|
||||
}
|
||||
}
|
||||
[Preserve(AllMembers = true)]
|
||||
public class CoreTabbedPageAsBottomNavigation : CoreTabbedPageBase
|
||||
{
|
||||
protected override void Init()
|
||||
{
|
||||
On<Android>().SetToolbarPlacement(ToolbarPlacement.Bottom);
|
||||
base.Init();
|
||||
}
|
||||
}
|
||||
|
||||
[Preserve (AllMembers = true)]
|
||||
[Issue (IssueTracker.Github, 2456, "StackOverflow after reordering tabs in a TabbedPageView", PlatformAffected.All)]
|
||||
public class CoreTabbedPage : TestTabbedPage
|
||||
[Preserve(AllMembers = true)]
|
||||
[Issue(IssueTracker.Github, 2456, "StackOverflow after reordering tabs in a TabbedPageView", PlatformAffected.All)]
|
||||
public class CoreTabbedPage : CoreTabbedPageBase
|
||||
{
|
||||
protected override void Init ()
|
||||
}
|
||||
|
||||
[Preserve(AllMembers = true)]
|
||||
public class CoreTabbedPageBase : TestTabbedPage
|
||||
{
|
||||
protected override void Init()
|
||||
{
|
||||
}
|
||||
#if APP
|
||||
public CoreTabbedPage ()
|
||||
public CoreTabbedPageBase()
|
||||
{
|
||||
AutomationId = "TabbedPageRoot";
|
||||
|
||||
|
||||
Device.StartTimer(TimeSpan.FromSeconds(6), () => {
|
||||
Device.StartTimer(TimeSpan.FromSeconds(6), () =>
|
||||
{
|
||||
BarBackgroundColor = Color.Maroon;
|
||||
BarTextColor = Color.Yellow;
|
||||
|
||||
Device.StartTimer(TimeSpan.FromSeconds(6), () => {
|
||||
Device.StartTimer(TimeSpan.FromSeconds(6), () =>
|
||||
{
|
||||
BarBackgroundColor = Color.Default;
|
||||
BarTextColor = Color.Default;
|
||||
|
||||
|
@ -115,37 +133,40 @@ namespace Xamarin.Forms.Controls
|
|||
Children.Add(new CoreRootPage(this, NavigationBehavior.PushModalAsync) { Title = "Tab 1" });
|
||||
Children.Add(new CoreRootPage(this, NavigationBehavior.PushModalAsync) { Title = "Tab 2" });
|
||||
Children.Add(new NavigationPage(new Page())
|
||||
{
|
||||
Title = "Rubriques",
|
||||
Icon = "coffee.png",
|
||||
BarBackgroundColor = Color.Blue,
|
||||
BarTextColor = Color.Aqua
|
||||
});
|
||||
{
|
||||
Title = "Rubriques",
|
||||
Icon = "coffee.png",
|
||||
BarBackgroundColor = Color.Blue,
|
||||
BarTextColor = Color.Aqua
|
||||
});
|
||||
|
||||
Children.Add(new NavigationPage(new Page())
|
||||
{
|
||||
Title = "Le Club"
|
||||
});
|
||||
{
|
||||
Title = "Le Club"
|
||||
});
|
||||
|
||||
Children.Add(new NavigationPage(new Page { Title = "Bookmarks" })
|
||||
{
|
||||
Title = "Bookmarks",
|
||||
});
|
||||
|
||||
if (On<Android>().GetMaxItemCount() > 5)
|
||||
{
|
||||
Children.Add(new NavigationPage(new Page { Title = "Alertes" })
|
||||
{
|
||||
Title = "Bookmarks",
|
||||
Title = "Notifications",
|
||||
});
|
||||
|
||||
Children.Add(new NavigationPage(new Page { Title = "Alertes" })
|
||||
{
|
||||
Title = "Notifications",
|
||||
});
|
||||
|
||||
Children.Add(new NavigationPage(new Page { Title = "My account" })
|
||||
Children.Add(new NavigationPage(new Page { Title = "My account" })
|
||||
{
|
||||
Title = "My account",
|
||||
});
|
||||
|
||||
Children.Add(new NavigationPage(new Page { Title = "About" })
|
||||
Children.Add(new NavigationPage(new Page { Title = "About" })
|
||||
{
|
||||
Title = "About",
|
||||
});
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -171,13 +192,13 @@ namespace Xamarin.Forms.Controls
|
|||
#endif
|
||||
}
|
||||
|
||||
[Preserve (AllMembers = true)]
|
||||
[Preserve(AllMembers = true)]
|
||||
internal class CoreViewContainer
|
||||
{
|
||||
public string Name { get; private set; }
|
||||
public Type PageType { get; private set; }
|
||||
|
||||
public CoreViewContainer (string name, Type pageType)
|
||||
public CoreViewContainer(string name, Type pageType)
|
||||
{
|
||||
Name = name;
|
||||
PageType = pageType;
|
||||
|
@ -186,31 +207,34 @@ namespace Xamarin.Forms.Controls
|
|||
[Preserve(AllMembers = true)]
|
||||
public class CoreRootView : ListView
|
||||
{
|
||||
public CoreRootView ()
|
||||
public CoreRootView()
|
||||
{
|
||||
var roots = new [] {
|
||||
new CoreViewContainer ("SwapRoot - CarouselPage", typeof(CoreCarouselPage)),
|
||||
var roots = new[] {
|
||||
new CoreViewContainer ("SwapRoot - CarouselPage", typeof(CoreCarouselPage)),
|
||||
new CoreViewContainer ("SwapRoot - ContentPage", typeof(CoreContentPage)),
|
||||
new CoreViewContainer ("SwapRoot - MasterDetailPage", typeof(CoreMasterDetailPage)),
|
||||
new CoreViewContainer ("SwapRoot - NavigationPage", typeof(CoreNavigationPage)),
|
||||
new CoreViewContainer ("SwapRoot - TabbedPage", typeof(CoreTabbedPage)),
|
||||
new CoreViewContainer ("SwapRoot - BottomNavigation TabbedPage", typeof(CoreTabbedPageAsBottomNavigation)),
|
||||
};
|
||||
|
||||
var template = new DataTemplate (typeof(TextCell));
|
||||
template.SetBinding (TextCell.TextProperty, "Name");
|
||||
var template = new DataTemplate(typeof(TextCell));
|
||||
template.SetBinding(TextCell.TextProperty, "Name");
|
||||
|
||||
ItemTemplate = template;
|
||||
ItemsSource = roots;
|
||||
|
||||
#if PRE_APPLICATION_CLASS
|
||||
ItemSelected += (sender, args) => MessagingCenter.Send (this, Messages.ChangeRoot, ((CoreViewContainer)args.SelectedItem).PageType);
|
||||
#else
|
||||
ItemSelected += (sender, args) => {
|
||||
#else
|
||||
ItemSelected += (sender, args) =>
|
||||
{
|
||||
var app = Application.Current as App;
|
||||
if (app != null) {
|
||||
var page = (Page)Activator.CreateInstance (((CoreViewContainer)args.SelectedItem).PageType);
|
||||
app.SetMainPage (page);
|
||||
}
|
||||
if (app != null)
|
||||
{
|
||||
var page = (Page)Activator.CreateInstance(((CoreViewContainer)args.SelectedItem).PageType);
|
||||
app.SetMainPage(page);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
SetValue(AutomationProperties.NameProperty, "SwapRoot");
|
||||
|
@ -231,7 +255,7 @@ namespace Xamarin.Forms.Controls
|
|||
p.Title = title;
|
||||
return p;
|
||||
};
|
||||
|
||||
|
||||
Title = title;
|
||||
}
|
||||
|
||||
|
@ -239,7 +263,7 @@ namespace Xamarin.Forms.Controls
|
|||
public string Title { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
{
|
||||
// a11y: let Narrator read a friendly string instead of the default ToString()
|
||||
return Title;
|
||||
}
|
||||
|
@ -354,30 +378,32 @@ namespace Xamarin.Forms.Controls
|
|||
new GalleryPageFactory(() => new WebViewGallery(), "WebView Gallery - Legacy"),
|
||||
};
|
||||
|
||||
public CorePageView (Page rootPage, NavigationBehavior navigationBehavior = NavigationBehavior.PushAsync)
|
||||
public CorePageView(Page rootPage, NavigationBehavior navigationBehavior = NavigationBehavior.PushAsync)
|
||||
{
|
||||
_titleToPage = _pages.ToDictionary (o => o.Title);
|
||||
_titleToPage = _pages.ToDictionary(o => o.Title);
|
||||
|
||||
// avoid NRE for root pages without NavigationBar
|
||||
if (navigationBehavior == NavigationBehavior.PushAsync && rootPage.GetType () == typeof (CoreNavigationPage)) {
|
||||
_pages.Add (new GalleryPageFactory(() => new NavigationBarGallery((NavigationPage)rootPage), "NavigationBar Gallery - Legacy"));
|
||||
if (navigationBehavior == NavigationBehavior.PushAsync && rootPage.GetType() == typeof(CoreNavigationPage))
|
||||
{
|
||||
_pages.Add(new GalleryPageFactory(() => new NavigationBarGallery((NavigationPage)rootPage), "NavigationBar Gallery - Legacy"));
|
||||
}
|
||||
|
||||
var template = new DataTemplate (typeof(TextCell));
|
||||
template.SetBinding (TextCell.TextProperty, "Title");
|
||||
var template = new DataTemplate(typeof(TextCell));
|
||||
template.SetBinding(TextCell.TextProperty, "Title");
|
||||
|
||||
BindingContext = _pages;
|
||||
ItemTemplate = template;
|
||||
ItemsSource = _pages;
|
||||
|
||||
ItemSelected += async (sender, args) => {
|
||||
ItemSelected += async (sender, args) =>
|
||||
{
|
||||
if (SelectedItem == null)
|
||||
return;
|
||||
|
||||
var item = args.SelectedItem;
|
||||
var page = item as GalleryPageFactory;
|
||||
if (page != null)
|
||||
await PushPage (page.Realize());
|
||||
await PushPage(page.Realize());
|
||||
|
||||
SelectedItem = null;
|
||||
};
|
||||
|
@ -387,60 +413,67 @@ namespace Xamarin.Forms.Controls
|
|||
|
||||
NavigationBehavior navigationBehavior;
|
||||
|
||||
async Task PushPage (Page contentPage)
|
||||
async Task PushPage(Page contentPage)
|
||||
{
|
||||
if (navigationBehavior == NavigationBehavior.PushModalAsync) {
|
||||
await Navigation.PushModalAsync (contentPage);
|
||||
} else {
|
||||
await Navigation.PushAsync (contentPage);
|
||||
if (navigationBehavior == NavigationBehavior.PushModalAsync)
|
||||
{
|
||||
await Navigation.PushModalAsync(contentPage);
|
||||
}
|
||||
else
|
||||
{
|
||||
await Navigation.PushAsync(contentPage);
|
||||
}
|
||||
}
|
||||
|
||||
readonly Dictionary<string, GalleryPageFactory> _titleToPage;
|
||||
public async Task PushPage (string pageTitle)
|
||||
public async Task PushPage(string pageTitle)
|
||||
{
|
||||
|
||||
GalleryPageFactory pageFactory = null;
|
||||
if (!_titleToPage.TryGetValue (pageTitle, out pageFactory))
|
||||
if (!_titleToPage.TryGetValue(pageTitle, out pageFactory))
|
||||
return;
|
||||
|
||||
var page = pageFactory.Realize();
|
||||
|
||||
await PushPage (page);
|
||||
await PushPage(page);
|
||||
}
|
||||
}
|
||||
[Preserve(AllMembers = true)]
|
||||
internal class CoreRootPage : ContentPage
|
||||
{
|
||||
public CoreRootPage (Page rootPage, NavigationBehavior navigationBehavior = NavigationBehavior.PushAsync)
|
||||
public CoreRootPage(Page rootPage, NavigationBehavior navigationBehavior = NavigationBehavior.PushAsync)
|
||||
{
|
||||
IStringProvider stringProvider = DependencyService.Get<IStringProvider> ();
|
||||
IStringProvider stringProvider = DependencyService.Get<IStringProvider>();
|
||||
|
||||
Title = stringProvider.CoreGalleryTitle;
|
||||
|
||||
var corePageView = new CorePageView (rootPage, navigationBehavior);
|
||||
var corePageView = new CorePageView(rootPage, navigationBehavior);
|
||||
|
||||
var searchBar = new SearchBar () {
|
||||
var searchBar = new SearchBar()
|
||||
{
|
||||
AutomationId = "SearchBar"
|
||||
};
|
||||
|
||||
var testCasesButton = new Button {
|
||||
var testCasesButton = new Button
|
||||
{
|
||||
Text = "Go to Test Cases",
|
||||
AutomationId = "GoToTestButton",
|
||||
Command = new Command (async () => {
|
||||
if (!string.IsNullOrEmpty (searchBar.Text))
|
||||
await corePageView.PushPage (searchBar.Text);
|
||||
Command = new Command(async () =>
|
||||
{
|
||||
if (!string.IsNullOrEmpty(searchBar.Text))
|
||||
await corePageView.PushPage(searchBar.Text);
|
||||
else
|
||||
await Navigation.PushModalAsync (TestCases.GetTestCases ());
|
||||
await Navigation.PushModalAsync(TestCases.GetTestCases());
|
||||
})
|
||||
};
|
||||
|
||||
var stackLayout = new StackLayout () {
|
||||
var stackLayout = new StackLayout()
|
||||
{
|
||||
Children = {
|
||||
testCasesButton,
|
||||
searchBar,
|
||||
new Button {
|
||||
Text = "Click to Force GC",
|
||||
Text = "Click to Force GC",
|
||||
Command = new Command(() => {
|
||||
GC.Collect ();
|
||||
GC.WaitForPendingFinalizers ();
|
||||
|
@ -451,7 +484,8 @@ namespace Xamarin.Forms.Controls
|
|||
}
|
||||
};
|
||||
|
||||
Content = new AbsoluteLayout {
|
||||
Content = new AbsoluteLayout
|
||||
{
|
||||
Children = {
|
||||
{ new CoreRootView (), new Rectangle(0, 0.0, 1, 0.35), AbsoluteLayoutFlags.All },
|
||||
{ stackLayout, new Rectangle(0, 0.5, 1, 0.30), AbsoluteLayoutFlags.All },
|
||||
|
@ -468,9 +502,9 @@ namespace Xamarin.Forms.Controls
|
|||
[Preserve(AllMembers = true)]
|
||||
public static class CoreGallery
|
||||
{
|
||||
public static Page GetMainPage ()
|
||||
public static Page GetMainPage()
|
||||
{
|
||||
return new CoreNavigationPage ();
|
||||
return new CoreNavigationPage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
namespace Xamarin.Forms.PlatformConfiguration.AndroidSpecific
|
||||
{
|
||||
using System;
|
||||
using FormsElement = Forms.TabbedPage;
|
||||
|
||||
public static class TabbedPage
|
||||
|
@ -65,5 +66,102 @@
|
|||
SetOffscreenPageLimit(config.Element, value);
|
||||
return config;
|
||||
}
|
||||
|
||||
public static readonly BindableProperty ToolbarPlacementProperty =
|
||||
BindableProperty.Create("ToolbarPlacement", typeof(ToolbarPlacement),
|
||||
typeof(TabbedPage), ToolbarPlacement.Top);
|
||||
|
||||
|
||||
public static ToolbarPlacement GetToolbarPlacement(BindableObject element)
|
||||
{
|
||||
return (ToolbarPlacement)element.GetValue(ToolbarPlacementProperty);
|
||||
}
|
||||
|
||||
public static void SetToolbarPlacement(BindableObject element, ToolbarPlacement value)
|
||||
{
|
||||
if (element.IsSet(ToolbarPlacementProperty) && GetToolbarPlacement(element) != value)
|
||||
{
|
||||
throw new InvalidOperationException("Changing the tabs placement after it's been set is not supported.");
|
||||
}
|
||||
|
||||
element.SetValue(ToolbarPlacementProperty, value);
|
||||
}
|
||||
|
||||
public static ToolbarPlacement GetToolbarPlacement(this IPlatformElementConfiguration<Android, FormsElement> config)
|
||||
{
|
||||
return GetToolbarPlacement(config.Element);
|
||||
}
|
||||
|
||||
public static IPlatformElementConfiguration<Android, FormsElement> SetToolbarPlacement(this IPlatformElementConfiguration<Android, FormsElement> config, ToolbarPlacement value)
|
||||
{
|
||||
SetToolbarPlacement(config.Element, value);
|
||||
return config;
|
||||
}
|
||||
|
||||
public static int GetMaxItemCount(BindableObject element)
|
||||
{
|
||||
if (GetToolbarPlacement(element) == ToolbarPlacement.Bottom)
|
||||
{
|
||||
return 5;
|
||||
}
|
||||
|
||||
return int.MaxValue;
|
||||
}
|
||||
|
||||
public static int GetMaxItemCount(this IPlatformElementConfiguration<Android, FormsElement> config)
|
||||
{
|
||||
return GetMaxItemCount(config.Element);
|
||||
}
|
||||
|
||||
public static readonly BindableProperty BarItemColorProperty =
|
||||
BindableProperty.Create("BarItemColor", typeof(Color),
|
||||
typeof(TabbedPage), Color.Default);
|
||||
|
||||
|
||||
public static Color GetBarItemColor(BindableObject element)
|
||||
{
|
||||
return (Color)element.GetValue(BarItemColorProperty);
|
||||
}
|
||||
|
||||
public static void SetBarItemColor(BindableObject element, Color value)
|
||||
{
|
||||
element.SetValue(BarItemColorProperty, value);
|
||||
}
|
||||
|
||||
public static Color GetBarItemColor(this IPlatformElementConfiguration<Android, FormsElement> config)
|
||||
{
|
||||
return GetBarItemColor(config.Element);
|
||||
}
|
||||
|
||||
public static IPlatformElementConfiguration<Android, FormsElement> SetBarItemColor(this IPlatformElementConfiguration<Android, FormsElement> config, Color value)
|
||||
{
|
||||
SetBarItemColor(config.Element, value);
|
||||
return config;
|
||||
}
|
||||
|
||||
public static readonly BindableProperty BarSelectedItemColorProperty =
|
||||
BindableProperty.Create("BarSelectedItemColor", typeof(Color),
|
||||
typeof(TabbedPage), Color.Default);
|
||||
|
||||
|
||||
public static Color GetBarSelectedItemColor(BindableObject element)
|
||||
{
|
||||
return (Color)element.GetValue(BarSelectedItemColorProperty);
|
||||
}
|
||||
|
||||
public static void SetBarSelectedItemColor(BindableObject element, Color value)
|
||||
{
|
||||
element.SetValue(BarSelectedItemColorProperty, value);
|
||||
}
|
||||
public static IPlatformElementConfiguration<Android, FormsElement> SetBarSelectedItemColor(this IPlatformElementConfiguration<Android, FormsElement> config, Color value)
|
||||
{
|
||||
SetBarSelectedItemColor(config.Element, value);
|
||||
return config;
|
||||
}
|
||||
|
||||
public static Color GetBarSelectedItemColor(this IPlatformElementConfiguration<Android, FormsElement> config)
|
||||
{
|
||||
return GetBarSelectedItemColor(config.Element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
namespace Xamarin.Forms.PlatformConfiguration.AndroidSpecific
|
||||
{
|
||||
public enum ToolbarPlacement
|
||||
{
|
||||
Default,
|
||||
Top,
|
||||
Bottom
|
||||
}
|
||||
}
|
|
@ -14,26 +14,14 @@ namespace Xamarin.Forms
|
|||
|
||||
public Color BarBackgroundColor
|
||||
{
|
||||
get
|
||||
{
|
||||
return (Color)GetValue(BarBackgroundColorProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
SetValue(BarBackgroundColorProperty, value);
|
||||
}
|
||||
get => (Color)GetValue(BarBackgroundColorProperty);
|
||||
set => SetValue(BarBackgroundColorProperty, value);
|
||||
}
|
||||
|
||||
public Color BarTextColor
|
||||
{
|
||||
get
|
||||
{
|
||||
return (Color)GetValue(BarTextColorProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
SetValue(BarTextColorProperty, value);
|
||||
}
|
||||
get => (Color)GetValue(BarTextColorProperty);
|
||||
set => SetValue(BarTextColorProperty, value);
|
||||
}
|
||||
|
||||
protected override Page CreateDefault(object item)
|
||||
|
|
|
@ -10,22 +10,40 @@ using Android.Runtime;
|
|||
using Android.Support.Design.Widget;
|
||||
using Android.Support.V4.App;
|
||||
using Android.Support.V4.View;
|
||||
using AWidget = Android.Widget;
|
||||
using Android.Views;
|
||||
using Xamarin.Forms.Internals;
|
||||
using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
|
||||
using ADrawableCompat = Android.Support.V4.Graphics.Drawable.DrawableCompat;
|
||||
using AView = Android.Views.View;
|
||||
using AMenu = Android.Views.Menu;
|
||||
using AColor = Android.Graphics.Color;
|
||||
|
||||
namespace Xamarin.Forms.Platform.Android.AppCompat
|
||||
{
|
||||
public class TabbedPageRenderer : VisualElementRenderer<TabbedPage>, TabLayout.IOnTabSelectedListener, ViewPager.IOnPageChangeListener, IManageFragments
|
||||
public class TabbedPageRenderer : VisualElementRenderer<TabbedPage>, TabLayout.IOnTabSelectedListener, ViewPager.IOnPageChangeListener, IManageFragments, BottomNavigationView.IOnNavigationItemSelectedListener
|
||||
{
|
||||
Drawable _backgroundDrawable;
|
||||
int? _defaultColor;
|
||||
Drawable _wrappedBackgroundDrawable;
|
||||
ColorStateList _originalTabTextColors;
|
||||
ColorStateList _orignalTabIconColors;
|
||||
|
||||
ColorStateList _newTabTextColors;
|
||||
ColorStateList _newTabIconColors;
|
||||
|
||||
bool _disposed;
|
||||
FragmentManager _fragmentManager;
|
||||
TabLayout _tabLayout;
|
||||
BottomNavigationView _bottomNavigationView;
|
||||
AWidget.RelativeLayout _relativeLayout;
|
||||
bool _useAnimations = true;
|
||||
FormsViewPager _viewPager;
|
||||
Page _previousPage;
|
||||
int[] _checkedStateSet = null;
|
||||
int[] _selectedStateSet = null;
|
||||
int[] _emptyStateSet = null;
|
||||
int _defaultARGBColor = Color.Default.ToAndroid().ToArgb();
|
||||
AColor _defaultAndroidColor = Color.Default.ToAndroid();
|
||||
|
||||
public TabbedPageRenderer(Context context) : base(context)
|
||||
{
|
||||
|
@ -39,6 +57,9 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
|
|||
}
|
||||
|
||||
FragmentManager FragmentManager => _fragmentManager ?? (_fragmentManager = ((FormsAppCompatActivity)Context).SupportFragmentManager);
|
||||
bool IsBottomTabPlacement => (Element != null) ? Element.OnThisPlatform().GetToolbarPlacement() == ToolbarPlacement.Bottom : false;
|
||||
public Color BarItemColor => (Element != null) ? Element.OnThisPlatform().GetBarItemColor() : Color.Default;
|
||||
public Color BarSelectedItemColor => (Element != null) ? Element.OnThisPlatform().GetBarSelectedItemColor() : Color.Default;
|
||||
|
||||
internal bool UseAnimations
|
||||
{
|
||||
|
@ -63,7 +84,8 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
|
|||
|
||||
void ViewPager.IOnPageChangeListener.OnPageScrolled(int position, float positionOffset, int positionOffsetPixels)
|
||||
{
|
||||
UpdateTabBarTranslation(position, positionOffset);
|
||||
if (!IsBottomTabPlacement)
|
||||
UpdateTabBarTranslation(position, positionOffset);
|
||||
}
|
||||
|
||||
void ViewPager.IOnPageChangeListener.OnPageScrollStateChanged(int state)
|
||||
|
@ -72,13 +94,16 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
|
|||
|
||||
void ViewPager.IOnPageChangeListener.OnPageSelected(int position)
|
||||
{
|
||||
if(_previousPage != Element.CurrentPage)
|
||||
if (_previousPage != Element.CurrentPage)
|
||||
{
|
||||
_previousPage?.SendDisappearing();
|
||||
_previousPage = Element.CurrentPage;
|
||||
}
|
||||
Element.CurrentPage = Element.Children[position];
|
||||
Element.CurrentPage.SendAppearing();
|
||||
|
||||
if (IsBottomTabPlacement)
|
||||
_bottomNavigationView.SelectedItemId = position;
|
||||
}
|
||||
|
||||
void TabLayout.IOnTabSelectedListener.OnTabReselected(TabLayout.Tab tab)
|
||||
|
@ -93,10 +118,13 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
|
|||
int selectedIndex = tab.Position;
|
||||
if (Element.Children.Count > selectedIndex && selectedIndex >= 0)
|
||||
Element.CurrentPage = Element.Children[selectedIndex];
|
||||
|
||||
SetIconColorFilter(tab, true);
|
||||
}
|
||||
|
||||
void TabLayout.IOnTabSelectedListener.OnTabUnselected(TabLayout.Tab tab)
|
||||
{
|
||||
SetIconColorFilter(tab, false);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
|
@ -131,6 +159,19 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
|
|||
_tabLayout = null;
|
||||
}
|
||||
|
||||
if (_bottomNavigationView != null)
|
||||
{
|
||||
_bottomNavigationView.SetOnNavigationItemSelectedListener(null);
|
||||
_bottomNavigationView.Dispose();
|
||||
_bottomNavigationView = null;
|
||||
}
|
||||
|
||||
if (_relativeLayout != null)
|
||||
{
|
||||
_relativeLayout.Dispose();
|
||||
_relativeLayout = null;
|
||||
}
|
||||
|
||||
if (Element != null)
|
||||
PageController.InternalChildren.CollectionChanged -= OnChildrenCollectionChanged;
|
||||
|
||||
|
@ -163,32 +204,68 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
|
|||
|
||||
if (e.NewElement != null)
|
||||
{
|
||||
if (_tabLayout == null)
|
||||
if (IsBottomTabPlacement)
|
||||
{
|
||||
TabLayout tabs;
|
||||
if (FormsAppCompatActivity.TabLayoutResource > 0)
|
||||
if (_relativeLayout == null)
|
||||
{
|
||||
tabs = _tabLayout = activity.LayoutInflater.Inflate(FormsAppCompatActivity.TabLayoutResource, null).JavaCast<TabLayout>();
|
||||
}
|
||||
else
|
||||
tabs = _tabLayout = new TabLayout(activity) { TabMode = TabLayout.ModeFixed, TabGravity = TabLayout.GravityFill };
|
||||
FormsViewPager pager =
|
||||
_viewPager =
|
||||
new FormsViewPager(activity)
|
||||
_relativeLayout = new AWidget.RelativeLayout(Context)
|
||||
{
|
||||
OverScrollMode = OverScrollMode.Never,
|
||||
EnableGesture = UseAnimations,
|
||||
LayoutParameters = new LayoutParams(LayoutParams.MatchParent, LayoutParams.MatchParent),
|
||||
Adapter = new FormsFragmentPagerAdapter<Page>(e.NewElement, FragmentManager) { CountOverride = e.NewElement.Children.Count }
|
||||
};
|
||||
pager.Id = Platform.GenerateViewId();
|
||||
pager.AddOnPageChangeListener(this);
|
||||
|
||||
AddView(pager);
|
||||
AddView(tabs);
|
||||
if (_bottomNavigationView != null)
|
||||
{
|
||||
_relativeLayout.RemoveView(_bottomNavigationView);
|
||||
_bottomNavigationView.SetOnNavigationItemSelectedListener(null);
|
||||
}
|
||||
|
||||
OnChildrenCollectionChanged(null, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
|
||||
var bottomNavigationViewLayoutParams = new AWidget.RelativeLayout.LayoutParams(
|
||||
LayoutParams.MatchParent,
|
||||
LayoutParams.WrapContent);
|
||||
|
||||
bottomNavigationViewLayoutParams.AddRule(AWidget.LayoutRules.AlignParentBottom);
|
||||
|
||||
_bottomNavigationView = new BottomNavigationView(Context)
|
||||
{
|
||||
LayoutParameters = bottomNavigationViewLayoutParams,
|
||||
Id = Platform.GenerateViewId()
|
||||
};
|
||||
|
||||
var viewPagerParams = new AWidget.RelativeLayout.LayoutParams(LayoutParams.MatchParent, LayoutParams.MatchParent);
|
||||
viewPagerParams.AddRule(AWidget.LayoutRules.Above, _bottomNavigationView.Id);
|
||||
|
||||
FormsViewPager pager = _viewPager = CreateFormsViewPager(activity, e.NewElement);
|
||||
|
||||
pager.Id = Platform.GenerateViewId();
|
||||
pager.AddOnPageChangeListener(this);
|
||||
|
||||
_relativeLayout.AddView(pager, viewPagerParams);
|
||||
_relativeLayout.AddView(_bottomNavigationView, bottomNavigationViewLayoutParams);
|
||||
|
||||
AddView(_relativeLayout);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_tabLayout == null)
|
||||
{
|
||||
TabLayout tabs;
|
||||
if (FormsAppCompatActivity.TabLayoutResource > 0)
|
||||
tabs = _tabLayout = activity.LayoutInflater.Inflate(FormsAppCompatActivity.TabLayoutResource, null).JavaCast<TabLayout>();
|
||||
else
|
||||
tabs = _tabLayout = new TabLayout(activity) { TabMode = TabLayout.ModeFixed, TabGravity = TabLayout.GravityFill };
|
||||
|
||||
FormsViewPager pager = _viewPager = CreateFormsViewPager(activity, e.NewElement);
|
||||
|
||||
pager.Id = Platform.GenerateViewId();
|
||||
pager.AddOnPageChangeListener(this);
|
||||
|
||||
AddView(pager);
|
||||
AddView(tabs);
|
||||
}
|
||||
}
|
||||
|
||||
OnChildrenCollectionChanged(null, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
|
||||
|
||||
TabbedPage tabbedPage = e.NewElement;
|
||||
if (tabbedPage.CurrentPage != null)
|
||||
|
@ -199,6 +276,7 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
|
|||
((IPageController)tabbedPage).InternalChildren.CollectionChanged += OnChildrenCollectionChanged;
|
||||
UpdateBarBackgroundColor();
|
||||
UpdateBarTextColor();
|
||||
UpdateItemIconColor();
|
||||
UpdateSwipePaging();
|
||||
UpdateOffscreenPageLimit();
|
||||
}
|
||||
|
@ -215,55 +293,90 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
|
|||
}
|
||||
else if (e.PropertyName == NavigationPage.BarBackgroundColorProperty.PropertyName)
|
||||
UpdateBarBackgroundColor();
|
||||
else if (e.PropertyName == NavigationPage.BarTextColorProperty.PropertyName)
|
||||
else if (e.PropertyName == NavigationPage.BarTextColorProperty.PropertyName ||
|
||||
e.PropertyName == PlatformConfiguration.AndroidSpecific.TabbedPage.BarItemColorProperty.PropertyName ||
|
||||
e.PropertyName == PlatformConfiguration.AndroidSpecific.TabbedPage.BarSelectedItemColorProperty.PropertyName)
|
||||
{
|
||||
_newTabTextColors = null;
|
||||
_newTabIconColors = null;
|
||||
UpdateBarTextColor();
|
||||
UpdateItemIconColor();
|
||||
}
|
||||
else if (e.PropertyName == PlatformConfiguration.AndroidSpecific.TabbedPage.IsSwipePagingEnabledProperty.PropertyName)
|
||||
UpdateSwipePaging();
|
||||
}
|
||||
|
||||
protected override void OnLayout(bool changed, int l, int t, int r, int b)
|
||||
{
|
||||
TabLayout tabs = _tabLayout;
|
||||
FormsViewPager pager = _viewPager;
|
||||
Context context = Context;
|
||||
int width = r - l;
|
||||
int height = b - t;
|
||||
|
||||
tabs.Measure(MeasureSpecFactory.MakeMeasureSpec(width, MeasureSpecMode.Exactly), MeasureSpecFactory.MakeMeasureSpec(height, MeasureSpecMode.AtMost));
|
||||
var tabsHeight = 0;
|
||||
var width = r - l;
|
||||
var height = b - t;
|
||||
|
||||
if (tabs.Visibility != ViewStates.Gone)
|
||||
if (IsBottomTabPlacement)
|
||||
{
|
||||
//MinimumHeight is only available on API 16+
|
||||
if ((int)Build.VERSION.SdkInt >= 16)
|
||||
tabsHeight = Math.Min(height, Math.Max(tabs.MeasuredHeight, tabs.MinimumHeight));
|
||||
else
|
||||
tabsHeight = Math.Min(height, tabs.MeasuredHeight);
|
||||
}
|
||||
if (width <= 0 || height <= 0)
|
||||
return;
|
||||
|
||||
pager.Measure(MeasureSpecFactory.MakeMeasureSpec(width, MeasureSpecMode.AtMost), MeasureSpecFactory.MakeMeasureSpec(height, MeasureSpecMode.AtMost));
|
||||
_relativeLayout.Measure(
|
||||
MeasureSpec.MakeMeasureSpec(width, MeasureSpecMode.Exactly),
|
||||
MeasureSpec.MakeMeasureSpec(height, MeasureSpecMode.Exactly));
|
||||
|
||||
if (width > 0 && height > 0)
|
||||
{
|
||||
PageController.ContainerArea = new Rectangle(0, context.FromPixels(tabsHeight), context.FromPixels(width), context.FromPixels(height - tabsHeight));
|
||||
pager.Measure(MeasureSpecFactory.MakeMeasureSpec(width, MeasureSpecMode.AtMost), MeasureSpecFactory.MakeMeasureSpec(height, MeasureSpecMode.AtMost));
|
||||
|
||||
for (var i = 0; i < PageController.InternalChildren.Count; i++)
|
||||
if (width > 0 && height > 0)
|
||||
{
|
||||
var child = PageController.InternalChildren[i] as VisualElement;
|
||||
if (child == null)
|
||||
continue;
|
||||
IVisualElementRenderer renderer = Android.Platform.GetRenderer(child);
|
||||
var navigationRenderer = renderer as NavigationPageRenderer;
|
||||
if (navigationRenderer != null)
|
||||
navigationRenderer.ContainerPadding = tabsHeight;
|
||||
PageController.ContainerArea = new Rectangle(0, 0, context.FromPixels(width), context.FromPixels(height - _bottomNavigationView.Height));
|
||||
|
||||
pager.Layout(0, 0, width, b);
|
||||
// We need to measure again to ensure that the tabs show up
|
||||
_relativeLayout.Measure(
|
||||
MeasureSpec.MakeMeasureSpec(width, MeasureSpecMode.Exactly),
|
||||
MeasureSpec.MakeMeasureSpec(height, MeasureSpecMode.Exactly));
|
||||
_relativeLayout.Layout(0, 0, _relativeLayout.MeasuredWidth, _relativeLayout.MeasuredHeight);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TabLayout tabs = _tabLayout;
|
||||
|
||||
tabs.Measure(MeasureSpecFactory.MakeMeasureSpec(width, MeasureSpecMode.Exactly), MeasureSpecFactory.MakeMeasureSpec(height, MeasureSpecMode.AtMost));
|
||||
var tabsHeight = 0;
|
||||
|
||||
if (tabs.Visibility != ViewStates.Gone)
|
||||
{
|
||||
//MinimumHeight is only available on API 16+
|
||||
if ((int)Build.VERSION.SdkInt >= 16)
|
||||
tabsHeight = Math.Min(height, Math.Max(tabs.MeasuredHeight, tabs.MinimumHeight));
|
||||
else
|
||||
tabsHeight = Math.Min(height, tabs.MeasuredHeight);
|
||||
}
|
||||
|
||||
pager.Layout(0, 0, width, b);
|
||||
// We need to measure again to ensure that the tabs show up
|
||||
tabs.Measure(MeasureSpecFactory.MakeMeasureSpec(width, MeasureSpecMode.Exactly), MeasureSpecFactory.MakeMeasureSpec(tabsHeight, MeasureSpecMode.Exactly));
|
||||
tabs.Layout(0, 0, width, tabsHeight);
|
||||
pager.Measure(MeasureSpecFactory.MakeMeasureSpec(width, MeasureSpecMode.AtMost), MeasureSpecFactory.MakeMeasureSpec(height, MeasureSpecMode.AtMost));
|
||||
|
||||
UpdateTabBarTranslation(pager.CurrentItem, 0);
|
||||
if (width > 0 && height > 0)
|
||||
{
|
||||
PageController.ContainerArea = new Rectangle(0, context.FromPixels(tabsHeight), context.FromPixels(width), context.FromPixels(height - tabsHeight));
|
||||
|
||||
for (var i = 0; i < PageController.InternalChildren.Count; i++)
|
||||
{
|
||||
var child = PageController.InternalChildren[i] as VisualElement;
|
||||
if (child == null)
|
||||
continue;
|
||||
IVisualElementRenderer renderer = Android.Platform.GetRenderer(child);
|
||||
var navigationRenderer = renderer as NavigationPageRenderer;
|
||||
if (navigationRenderer != null)
|
||||
navigationRenderer.ContainerPadding = tabsHeight;
|
||||
}
|
||||
|
||||
pager.Layout(0, 0, width, b);
|
||||
// We need to measure again to ensure that the tabs show up
|
||||
tabs.Measure(MeasureSpecFactory.MakeMeasureSpec(width, MeasureSpecMode.Exactly), MeasureSpecFactory.MakeMeasureSpec(tabsHeight, MeasureSpecMode.Exactly));
|
||||
tabs.Layout(0, 0, width, tabsHeight);
|
||||
|
||||
UpdateTabBarTranslation(pager.CurrentItem, 0);
|
||||
}
|
||||
}
|
||||
|
||||
base.OnLayout(changed, l, t, r, b);
|
||||
|
@ -273,26 +386,60 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
|
|||
{
|
||||
e.Apply((o, i, c) => SetupPage((Page)o), (o, i) => TeardownPage((Page)o), Reset);
|
||||
|
||||
FormsViewPager pager = _viewPager;
|
||||
TabLayout tabs = _tabLayout;
|
||||
|
||||
((FormsFragmentPagerAdapter<Page>)pager.Adapter).CountOverride = Element.Children.Count;
|
||||
|
||||
pager.Adapter.NotifyDataSetChanged();
|
||||
|
||||
if (Element.Children.Count == 0)
|
||||
if (IsBottomTabPlacement)
|
||||
{
|
||||
tabs.RemoveAllTabs();
|
||||
tabs.SetupWithViewPager(null);
|
||||
FormsViewPager pager = _viewPager;
|
||||
BottomNavigationView bottomNavigationView = _bottomNavigationView;
|
||||
|
||||
((FormsFragmentPagerAdapter<Page>)pager.Adapter).CountOverride = Element.Children.Count;
|
||||
|
||||
pager.Adapter.NotifyDataSetChanged();
|
||||
|
||||
if (Element.Children.Count == 0)
|
||||
{
|
||||
bottomNavigationView.Menu.Clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
SetupBottomNavigationView(e);
|
||||
UpdateBottomNavigationViewIcons();
|
||||
bottomNavigationView.SetOnNavigationItemSelectedListener(this);
|
||||
}
|
||||
|
||||
UpdateIgnoreContainerAreas();
|
||||
}
|
||||
else
|
||||
{
|
||||
tabs.SetupWithViewPager(pager);
|
||||
UpdateTabIcons();
|
||||
tabs.AddOnTabSelectedListener(this);
|
||||
}
|
||||
FormsViewPager pager = _viewPager;
|
||||
TabLayout tabs = _tabLayout;
|
||||
|
||||
UpdateIgnoreContainerAreas();
|
||||
((FormsFragmentPagerAdapter<Page>)pager.Adapter).CountOverride = Element.Children.Count;
|
||||
pager.Adapter.NotifyDataSetChanged();
|
||||
if (Element.Children.Count == 0)
|
||||
{
|
||||
tabs.RemoveAllTabs();
|
||||
tabs.SetupWithViewPager(null);
|
||||
}
|
||||
else
|
||||
{
|
||||
tabs.SetupWithViewPager(pager);
|
||||
UpdateTabIcons();
|
||||
tabs.AddOnTabSelectedListener(this);
|
||||
}
|
||||
|
||||
UpdateIgnoreContainerAreas();
|
||||
}
|
||||
}
|
||||
|
||||
FormsViewPager CreateFormsViewPager(Context context, TabbedPage tabbedPage)
|
||||
{
|
||||
return new FormsViewPager(context)
|
||||
{
|
||||
OverScrollMode = OverScrollMode.Never,
|
||||
EnableGesture = UseAnimations,
|
||||
LayoutParameters = new LayoutParams(LayoutParams.MatchParent, LayoutParams.MatchParent),
|
||||
Adapter = new FormsFragmentPagerAdapter<Page>(tabbedPage, FragmentManager) { CountOverride = tabbedPage.Children.Count }
|
||||
};
|
||||
}
|
||||
|
||||
void TeardownPage(Page page)
|
||||
|
@ -317,8 +464,17 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
|
|||
{
|
||||
var page = (Page)sender;
|
||||
var index = Element.Children.IndexOf(page);
|
||||
TabLayout.Tab tab = _tabLayout.GetTabAt(index);
|
||||
tab.SetText(page.Title);
|
||||
|
||||
if (IsBottomTabPlacement)
|
||||
{
|
||||
IMenuItem tab = _bottomNavigationView.Menu.GetItem(index);
|
||||
tab.SetTitle(page.Title);
|
||||
}
|
||||
else
|
||||
{
|
||||
TabLayout.Tab tab = _tabLayout.GetTabAt(index);
|
||||
tab.SetText(page.Title);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -347,6 +503,9 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
|
|||
|
||||
void UpdateTabBarTranslation(int position, float offset)
|
||||
{
|
||||
if (IsDisposed)
|
||||
return;
|
||||
|
||||
TabLayout tabs = _tabLayout;
|
||||
|
||||
if (position >= PageController.InternalChildren.Count)
|
||||
|
@ -385,8 +544,62 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
|
|||
}
|
||||
}
|
||||
|
||||
void SetupBottomNavigationView(NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
if (IsDisposed)
|
||||
return;
|
||||
|
||||
BottomNavigationView bottomNavigationView = _bottomNavigationView;
|
||||
|
||||
int startingIndex = 0;
|
||||
|
||||
if (e.Action == NotifyCollectionChangedAction.Add && e.NewStartingIndex == bottomNavigationView.Menu.Size())
|
||||
startingIndex = e.NewStartingIndex;
|
||||
else if (e.Action == NotifyCollectionChangedAction.Remove && (e.OldStartingIndex + 1) == bottomNavigationView.Menu.Size())
|
||||
{
|
||||
startingIndex = Element.Children.Count;
|
||||
bottomNavigationView.Menu.RemoveItem(e.OldStartingIndex);
|
||||
}
|
||||
else
|
||||
bottomNavigationView.Menu.Clear();
|
||||
|
||||
|
||||
for (var i = startingIndex; i < Element.Children.Count; i++)
|
||||
{
|
||||
Page child = Element.Children[i];
|
||||
var menuItem = bottomNavigationView.Menu.Add(AMenu.None, i, i, child.Title);
|
||||
if (Element.CurrentPage == child)
|
||||
bottomNavigationView.SelectedItemId = menuItem.ItemId;
|
||||
}
|
||||
|
||||
if (Element.CurrentPage == null && Element.Children.Count > 0)
|
||||
Element.CurrentPage = Element.Children[0];
|
||||
}
|
||||
|
||||
void UpdateBottomNavigationViewIcons()
|
||||
{
|
||||
if (IsDisposed)
|
||||
return;
|
||||
|
||||
BottomNavigationView bottomNavigationView = _bottomNavigationView;
|
||||
|
||||
for (var i = 0; i < Element.Children.Count; i++)
|
||||
{
|
||||
Page child = Element.Children[i];
|
||||
FileImageSource icon = child.Icon;
|
||||
if (string.IsNullOrEmpty(icon))
|
||||
continue;
|
||||
|
||||
var menuItem = bottomNavigationView.Menu.GetItem(i);
|
||||
menuItem.SetIcon(ResourceManager.IdFromTitle(icon, ResourceManager.DrawableClass));
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateTabIcons()
|
||||
{
|
||||
if (IsDisposed)
|
||||
return;
|
||||
|
||||
TabLayout tabs = _tabLayout;
|
||||
|
||||
if (tabs.TabCount != Element.Children.Count)
|
||||
|
@ -407,55 +620,290 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
|
|||
protected virtual void SetTabIcon(TabLayout.Tab tab, FileImageSource icon)
|
||||
{
|
||||
tab.SetIcon(ResourceManager.IdFromTitle(icon, ResourceManager.DrawableClass));
|
||||
this.SetIconColorFilter(tab);
|
||||
}
|
||||
|
||||
void UpdateBarBackgroundColor()
|
||||
{
|
||||
if (_disposed || _tabLayout == null)
|
||||
if (IsDisposed)
|
||||
return;
|
||||
|
||||
Color tintColor = Element.BarBackgroundColor;
|
||||
|
||||
if (Forms.IsLollipopOrNewer)
|
||||
if (IsBottomTabPlacement)
|
||||
{
|
||||
Color tintColor = Element.BarBackgroundColor;
|
||||
|
||||
if (tintColor.IsDefault)
|
||||
_tabLayout.BackgroundTintMode = null;
|
||||
else
|
||||
{
|
||||
_tabLayout.BackgroundTintMode = PorterDuff.Mode.Src;
|
||||
_tabLayout.BackgroundTintList = ColorStateList.ValueOf(tintColor.ToAndroid());
|
||||
}
|
||||
_bottomNavigationView.SetBackground(null);
|
||||
else if (!tintColor.IsDefault)
|
||||
_bottomNavigationView.SetBackgroundColor(tintColor.ToAndroid());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (tintColor.IsDefault && _backgroundDrawable != null)
|
||||
_tabLayout.SetBackground(_backgroundDrawable);
|
||||
else if (!tintColor.IsDefault)
|
||||
Color tintColor = Element.BarBackgroundColor;
|
||||
|
||||
if (Forms.IsLollipopOrNewer)
|
||||
{
|
||||
if (_backgroundDrawable == null)
|
||||
_backgroundDrawable = _tabLayout.Background;
|
||||
_tabLayout.SetBackgroundColor(tintColor.ToAndroid());
|
||||
if (tintColor.IsDefault)
|
||||
_tabLayout.BackgroundTintMode = null;
|
||||
else
|
||||
{
|
||||
_tabLayout.BackgroundTintMode = PorterDuff.Mode.Src;
|
||||
_tabLayout.BackgroundTintList = ColorStateList.ValueOf(tintColor.ToAndroid());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (tintColor.IsDefault && _backgroundDrawable != null)
|
||||
_tabLayout.SetBackground(_backgroundDrawable);
|
||||
else if (!tintColor.IsDefault)
|
||||
{
|
||||
// if you don't create a new drawable then SetBackgroundColor
|
||||
// just sets the color on the background drawable that's saved
|
||||
// it doesn't create a new one
|
||||
if (_backgroundDrawable == null && _tabLayout.Background != null)
|
||||
{
|
||||
_backgroundDrawable = _tabLayout.Background;
|
||||
_wrappedBackgroundDrawable = ADrawableCompat.Wrap(_tabLayout.Background).Mutate();
|
||||
}
|
||||
|
||||
if (_wrappedBackgroundDrawable != null)
|
||||
_tabLayout.Background = _wrappedBackgroundDrawable;
|
||||
|
||||
_tabLayout.SetBackgroundColor(tintColor.ToAndroid());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual ColorStateList GetItemTextColorStates()
|
||||
{
|
||||
if (IsDisposed)
|
||||
return null;
|
||||
|
||||
if (_originalTabTextColors == null)
|
||||
_originalTabTextColors = (IsBottomTabPlacement) ? _bottomNavigationView.ItemTextColor : _tabLayout.TabTextColors;
|
||||
|
||||
Color barItemColor = BarItemColor;
|
||||
Color barTextColor = Element.BarTextColor;
|
||||
Color barSelectedItemColor = BarSelectedItemColor;
|
||||
|
||||
if (barItemColor.IsDefault && barTextColor.IsDefault && barSelectedItemColor.IsDefault)
|
||||
return _originalTabTextColors;
|
||||
|
||||
if (_newTabTextColors != null)
|
||||
return _newTabTextColors;
|
||||
|
||||
int checkedColor;
|
||||
int defaultColor;
|
||||
|
||||
if (!barTextColor.IsDefault)
|
||||
{
|
||||
checkedColor = barTextColor.ToAndroid().ToArgb();
|
||||
defaultColor = checkedColor;
|
||||
}
|
||||
else
|
||||
{
|
||||
defaultColor = barItemColor.ToAndroid().ToArgb();
|
||||
|
||||
if (barItemColor.IsDefault && _originalTabTextColors != null)
|
||||
defaultColor = _originalTabTextColors.DefaultColor;
|
||||
|
||||
checkedColor = defaultColor;
|
||||
|
||||
if (!barSelectedItemColor.IsDefault)
|
||||
checkedColor = barSelectedItemColor.ToAndroid().ToArgb();
|
||||
}
|
||||
|
||||
_newTabTextColors = GetColorStateList(defaultColor, checkedColor);
|
||||
return _newTabTextColors;
|
||||
}
|
||||
|
||||
protected virtual ColorStateList GetItemIconTintColorState()
|
||||
{
|
||||
if (IsDisposed)
|
||||
return null;
|
||||
|
||||
if (IsBottomTabPlacement)
|
||||
{
|
||||
if (_orignalTabIconColors == null)
|
||||
_orignalTabIconColors = _bottomNavigationView.ItemIconTintList;
|
||||
}
|
||||
// this ensures that existing behavior doesn't change
|
||||
else if (!IsBottomTabPlacement && BarSelectedItemColor.IsDefault && BarItemColor.IsDefault)
|
||||
return null;
|
||||
|
||||
Color barItemColor = BarItemColor;
|
||||
Color barSelectedItemColor = BarSelectedItemColor;
|
||||
|
||||
if (barItemColor.IsDefault && barSelectedItemColor.IsDefault)
|
||||
return _orignalTabIconColors;
|
||||
|
||||
if (_newTabIconColors != null)
|
||||
return _newTabIconColors;
|
||||
|
||||
int defaultColor = barItemColor.ToAndroid().ToArgb();
|
||||
|
||||
if (barItemColor.IsDefault && _orignalTabIconColors != null)
|
||||
defaultColor = _orignalTabIconColors.DefaultColor;
|
||||
|
||||
int checkedColor = defaultColor;
|
||||
|
||||
if (!barSelectedItemColor.IsDefault)
|
||||
checkedColor = barSelectedItemColor.ToAndroid().ToArgb();
|
||||
|
||||
_newTabIconColors = GetColorStateList(defaultColor, checkedColor);
|
||||
return _newTabIconColors;
|
||||
}
|
||||
|
||||
public bool OnNavigationItemSelected(IMenuItem item)
|
||||
{
|
||||
if (Element == null || IsDisposed)
|
||||
return false;
|
||||
|
||||
int selectedIndex = item.Order;
|
||||
if (_bottomNavigationView.SelectedItemId != item.ItemId && Element.Children.Count > selectedIndex && selectedIndex >= 0)
|
||||
Element.CurrentPage = Element.Children[selectedIndex];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsDisposed
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsBottomTabPlacement)
|
||||
{
|
||||
if (_disposed || _relativeLayout == null || _bottomNavigationView == null)
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_disposed || _tabLayout == null)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateItemIconColor()
|
||||
{
|
||||
if (IsDisposed)
|
||||
return;
|
||||
|
||||
if (IsBottomTabPlacement)
|
||||
_bottomNavigationView.ItemIconTintList = GetItemIconTintColorState() ?? _orignalTabIconColors;
|
||||
else
|
||||
{
|
||||
var colors = GetItemIconTintColorState() ?? _orignalTabIconColors;
|
||||
for (int i = 0; i < _tabLayout.TabCount; i++)
|
||||
{
|
||||
TabLayout.Tab tab = _tabLayout.GetTabAt(i);
|
||||
this.SetIconColorFilter(tab);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateBarTextColor()
|
||||
{
|
||||
if (_disposed || _tabLayout == null)
|
||||
if (IsDisposed)
|
||||
return;
|
||||
|
||||
int currentColor = _tabLayout.TabTextColors.DefaultColor;
|
||||
var colors = GetItemTextColorStates() ?? _originalTabTextColors;
|
||||
if (IsBottomTabPlacement)
|
||||
_bottomNavigationView.ItemTextColor = colors;
|
||||
else
|
||||
_tabLayout.TabTextColors = colors;
|
||||
}
|
||||
|
||||
if (!_defaultColor.HasValue)
|
||||
_defaultColor = currentColor;
|
||||
void SetIconColorFilter(TabLayout.Tab tab)
|
||||
{
|
||||
SetIconColorFilter(tab, _tabLayout.GetTabAt(_tabLayout.SelectedTabPosition) == tab);
|
||||
}
|
||||
|
||||
Color newTextColor = Element.BarTextColor;
|
||||
int newTextColorArgb = newTextColor.ToAndroid().ToArgb();
|
||||
void SetIconColorFilter(TabLayout.Tab tab, bool selected)
|
||||
{
|
||||
var icon = tab.Icon;
|
||||
if (icon == null)
|
||||
return;
|
||||
|
||||
if (!newTextColor.IsDefault && currentColor != newTextColorArgb)
|
||||
_tabLayout.SetTabTextColors(newTextColorArgb, newTextColorArgb);
|
||||
else if (newTextColor.IsDefault && _defaultColor.HasValue && currentColor != _defaultColor)
|
||||
_tabLayout.SetTabTextColors(_defaultColor.Value, _defaultColor.Value);
|
||||
var colors = GetItemIconTintColorState();
|
||||
if (colors == null)
|
||||
ADrawableCompat.SetTintList(icon, null);
|
||||
else
|
||||
{
|
||||
int[] _stateSet = null;
|
||||
|
||||
if (selected)
|
||||
_stateSet = GetSelectedStateSet();
|
||||
else
|
||||
_stateSet = GetEmptyStateSet();
|
||||
|
||||
if (colors.GetColorForState(_stateSet, _defaultAndroidColor) == _defaultARGBColor)
|
||||
ADrawableCompat.SetTintList(icon, null);
|
||||
else
|
||||
{
|
||||
var wrappedIcon = ADrawableCompat.Wrap(icon);
|
||||
if (wrappedIcon != icon)
|
||||
{
|
||||
icon = wrappedIcon;
|
||||
tab.SetIcon(wrappedIcon);
|
||||
}
|
||||
|
||||
icon.Mutate();
|
||||
icon.SetState(_stateSet);
|
||||
ADrawableCompat.SetTintList(icon, colors);
|
||||
}
|
||||
}
|
||||
icon.InvalidateSelf();
|
||||
}
|
||||
|
||||
int[] GetSelectedStateSet()
|
||||
{
|
||||
if (IsBottomTabPlacement)
|
||||
{
|
||||
if (_checkedStateSet == null)
|
||||
_checkedStateSet = new int[] { global::Android.Resource.Attribute.StateChecked };
|
||||
|
||||
return _checkedStateSet;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_selectedStateSet == null)
|
||||
_selectedStateSet = GetStateSet(AView.SelectedStateSet);
|
||||
|
||||
return _selectedStateSet;
|
||||
}
|
||||
}
|
||||
|
||||
int[] GetEmptyStateSet()
|
||||
{
|
||||
if (_emptyStateSet == null)
|
||||
_emptyStateSet = GetStateSet(AView.EmptyStateSet);
|
||||
|
||||
return _emptyStateSet;
|
||||
}
|
||||
|
||||
int[] GetStateSet(System.Collections.Generic.IList<int> stateSet)
|
||||
{
|
||||
var results = new int[stateSet.Count];
|
||||
for (int i = 0; i < results.Length; i++)
|
||||
results[i] = stateSet[i];
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
ColorStateList GetColorStateList(int defaultColor, int checkedColor)
|
||||
{
|
||||
int[][] states = new int[2][];
|
||||
int[] colors = new int[2];
|
||||
|
||||
states[0] = GetSelectedStateSet();
|
||||
colors[0] = checkedColor;
|
||||
states[1] = GetEmptyStateSet();
|
||||
colors[1] = defaultColor;
|
||||
|
||||
return new ColorStateList(states, colors);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
using System;
|
||||
using System.ComponentModel;
|
||||
using Android.Content;
|
||||
using Android.Views;
|
||||
|
||||
|
@ -23,6 +25,8 @@ namespace Xamarin.Forms.Platform.Android
|
|||
|
||||
RemoveAllViews();
|
||||
|
||||
UnsubscribeChildLayoutChanges();
|
||||
|
||||
_childView = value;
|
||||
|
||||
if (_childView == null)
|
||||
|
@ -36,6 +40,29 @@ namespace Xamarin.Forms.Platform.Android
|
|||
renderer.View.RemoveFromParent();
|
||||
|
||||
AddView(renderer.View);
|
||||
|
||||
if (_childView is Layout layout)
|
||||
{
|
||||
layout.LayoutChanged += OnChildLayoutChanged;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnChildLayoutChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (IsInLayout)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RequestLayout();
|
||||
}
|
||||
|
||||
void UnsubscribeChildLayoutChanges()
|
||||
{
|
||||
if (_childView is Layout layout)
|
||||
{
|
||||
layout.LayoutChanged -= OnChildLayoutChanged;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -45,6 +72,8 @@ namespace Xamarin.Forms.Platform.Android
|
|||
|
||||
if (disposing)
|
||||
{
|
||||
UnsubscribeChildLayoutChanges();
|
||||
|
||||
if (ChildCount > 0)
|
||||
GetChildAt(0).Dispose();
|
||||
RemoveAllViews();
|
||||
|
|
|
@ -260,7 +260,7 @@ namespace Xamarin.Forms
|
|||
{
|
||||
NSUrl url;
|
||||
|
||||
if (uri.Scheme == "tel")
|
||||
if (uri.Scheme == "tel" || uri.Scheme == "mailto")
|
||||
url = new NSUrl(uri.AbsoluteUri);
|
||||
else
|
||||
url = NSUrl.FromString(uri.OriginalString) ?? new NSUrl(uri.Scheme, uri.Host, uri.PathAndQuery);
|
||||
|
|
Загрузка…
Ссылка в новой задаче