Как изменить значок TabbedPage при повторном выборе вкладки в Android?
у меня есть приложение, используя Xamarin Forms
TabbedPage
, который имеет функцию, которая позволит пользователю сделать паузу и сыграть странице. См. код ниже.
Общий Код
public partial class MainPage : TabbedPage
{
public MainPage()
{
InitializeComponent();
var homePage = new NavigationPage(new HomePage())
{
Title = "Home",
Icon = "ionicons_2_0_1_home_outline_25.png"
};
var phrasesPage = new NavigationPage(new PhrasesPage())
{
Title = "Play",
Icon = "ionicons_2_0_1_play_outline_25.png"
};
Children.Add(homePage);
Children.Add(phrasesPage);
}
}
в рендерере iOS:
public class TabbedPageRenderer : TabbedRenderer
{
private MainPage _page;
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
var tabbarController = (UITabBarController)this.ViewController;
if (null != tabbarController)
{
tabbarController.ViewControllerSelected += OnTabBarReselected;
}
}
void OnTabBarReselected(object sender, UITabBarSelectionEventArgs e)
{
var tabs = Element as TabbedPage;
var playTab = tabs.Children[4];
if (TabBar.SelectedItem.Title == "Play") {
if (tabs != null)
{
playTab.Title = "Pause";
playTab.Icon = "ionicons_2_0_1_pause_outline_22.png";
}
App.pauseCard = false;
}
else {
if (tabs != null) {
playTab.Title = "Play";
playTab.Icon = "ionicons_2_0_1_play_outline_25.png";
}
App.pauseCard = true;
}
}
Android Визуализации
public class MyTabbedPageRenderer: TabbedPageRenderer, TabLayout.IOnTabSelectedListener
{
if (e.PropertyName == "Renderer")
{
viewPager = (ViewPager)ViewGroup.GetChildAt(0);
tabLayout = (TabLayout)ViewGroup.GetChildAt(1);
setup = true;
ColorStateList colors = null;
if ((int)Build.VERSION.SdkInt >= 23)
{
colors = Resources.GetColorStateList(Resource.Color.icon_tab, Forms.Context.Theme);
}
else
{
colors = Resources.GetColorStateList(Resource.Color.icon_tab);
}
for (int i = 0; i < tabLayout.TabCount; i++)
{
var tab = tabLayout.GetTabAt(i);
var icon = tab.Icon;
if (icon != null)
{
icon = Android.Support.V4.Graphics.Drawable.DrawableCompat.Wrap(icon);
Android.Support.V4.Graphics.Drawable.DrawableCompat.SetTintList(icon, colors);
}
}
}
void TabLayout.IOnTabSelectedListener.OnTabReselected(TabLayout.Tab tab)
{
var tabs = Element as TabbedPage;
var playTab = tabs.Children[4];
var selectedPosition = tab.Position;
if(selectedPosition == 4)
{
if (playTab.Title == "Play")
{
if (tabs != null)
{
playTab.Title = "Pause";
playTab.Icon = "ionicons_2_0_1_pause_outline_22.png";
}
App.pauseCard = false;
}
else
{
if (tabs != null)
{
playTab.Title = "Play";
playTab.Icon = "ionicons_2_0_1_play_outline_25.png";
}
App.pauseCard = true;
}
}
}
}
это прекрасно работает в iOS
. Но как-то в Android
только Title
изменится, но не Icon
. Кто знает, что им отсутствует или как это сделать? Кроме того, возможно ли это сделать в общем коде вместо повторения почти точно таких же строк в коде на каждой платформе?
5 ответов
вы можете сделать это, используя вкладку, которая является passe к вам в OnTabReselected
параметры TabRenderer
.
вы можете переместить всю свою логику с этим объектом.
Это весь мой файл визуализации (Android):
[assembly: ExportRenderer(typeof(SWTabSelection.MainPage), typeof(SWTabSelection.Droid.MyTabbedPageRenderer))]
namespace SWTabSelection.Droid
{
public class MyTabbedPageRenderer : TabbedPageRenderer, TabLayout.IOnTabSelectedListener
{
private ViewPager viewPager;
private TabLayout tabLayout;
private bool setup;
public MyTabbedPageRenderer() { }
public MyTabbedPageRenderer(Context context) : base(context)
{
//Use this constructor for newest versions of XF saving the context parameter
// in a field so it can be used later replacing the Xamarin.Forms.Forms.Context which is deprecated.
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == "Renderer")
{
viewPager = (ViewPager)ViewGroup.GetChildAt(0);
tabLayout = (TabLayout)ViewGroup.GetChildAt(1);
setup = true;
ColorStateList colors = GetTabColor();
for (int i = 0; i < tabLayout.TabCount; i++)
{
var tab = tabLayout.GetTabAt(i);
SetTintColor(tab, colors);
}
}
}
void TabLayout.IOnTabSelectedListener.OnTabReselected(TabLayout.Tab tab)
{
// To have the logic only on he tab on position 1
if(tab == null || tab.Position != 1)
{
return;
}
if(tab.Text == "Play")
{
tab.SetText("Pause");
tab.SetIcon(Resource.Drawable.ionicons_2_0_1_pause_outline_25);
App.pauseCard = false;
}
else
{
tab.SetText("Play");
tab.SetIcon(Resource.Drawable.ionicons_2_0_1_play_outline_25);
App.pauseCard = true;
}
SetTintColor(tab, GetTabColor());
}
void SetTintColor(TabLayout.Tab tab, ColorStateList colors)
{
var icon = tab?.Icon;
if(icon != null)
{
icon = Android.Support.V4.Graphics.Drawable.DrawableCompat.Wrap(icon);
Android.Support.V4.Graphics.Drawable.DrawableCompat.SetTintList(icon, colors);
}
}
ColorStateList GetTabColor()
{
return ((int)Build.VERSION.SdkInt >= 23)
? Resources.GetColorStateList(Resource.Color.icon_tab, Forms.Context.Theme)
: Resources.GetColorStateList(Resource.Color.icon_tab);
}
}
}
единственное, что у меня было с кодом выше, это то, что значок не принимал цвет оттенка, поэтому создал функцию с той же логикой, которую вы должны были установить оттенок, и я использую ее на вкладке Reselection. Если у вас есть только одна вкладка в приложение вы можете установить глобальный оттенок в теме/стиле xml Android.
надеюсь, что это помогает.
нет способа определить, когда вкладка переизбрана в Xamarin.Формы, поэтому нам придется использовать пользовательские rederers для обнаружения логики.
для Android нам придется обрабатывать два случая: текущая страница вкладки изменена и текущая страница вкладки переизбрана.
мы подпишемся наCurrentPageChanged
и в его EventHandler мы проверим, выбрана ли вкладка PhrasesPage
. Если это так, мы обновим значок / текст.
на OnTabReselected
, мы можем проверить, какая страница в настоящее время выбрано, и если это PhrasesPage
, мы можем обновить PhrasesPage.Icon
и PhrasesPage.Text
.
Образец Приложение
https://github.com/brminnick/ChangeTabbedPageIconSample/tree/master
Пользовательский Рендерер Android
[assembly: ExportRenderer(typeof(MainPage), typeof(TabbedPageRenderer))]
namespace YourNameSpace
{
public class TabbedPageRenderer : TabbedRenderer, TabLayout.IOnTabSelectedListener
{
//Overloaded Constructor required for Xamarin.Forms v2.5+
public TabbedPageRenderer(Android.Content.Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<TabbedPage> e)
{
base.OnElementChanged(e);
Element.CurrentPageChanged += HandleCurrentPageChanged;
}
void HandleCurrentPageChanged(object sender, EventArgs e)
{
var currentNavigationPage = Element.CurrentPage as NavigationPage;
if (!(currentNavigationPage.RootPage is PhrasesPage))
return;
var tabLayout = (TabLayout)ViewGroup.GetChildAt(1);
for (int i = 0; i < tabLayout.TabCount; i++)
{
var currentTab = tabLayout.GetTabAt(i);
var currentTabText = currentTab.Text;
if (currentTabText.Equals("Play") || currentTabText.Equals("Pause"))
{
Device.BeginInvokeOnMainThread(() => UpdateTab(currentTabText, currentTab, currentNavigationPage));
break;
}
}
}
void TabLayout.IOnTabSelectedListener.OnTabReselected(TabLayout.Tab tab)
{
System.Diagnostics.Debug.WriteLine("Tab Reselected");
var mainPage = Application.Current.MainPage as MainPage;
var currentNavigationPage = mainPage.CurrentPage as NavigationPage;
if(currentNavigationPage.RootPage is PhrasesPage)
Device.BeginInvokeOnMainThread(() => UpdateTab(currentNavigationPage.Title, tab, currentNavigationPage));
}
void UpdateTab(string currentTabText, TabLayout.Tab tab, NavigationPage currentNavigationPage)
{
if (currentTabText.Equals("Puzzle"))
{
tab.SetIcon(IdFromTitle("Settings", ResourceManager.DrawableClass));
currentNavigationPage.Title = "Settings";
}
else
{
tab.SetIcon(IdFromTitle("Puzzle", ResourceManager.DrawableClass));
currentNavigationPage.Title = "Puzzle";
}
}
int IdFromTitle(string title, Type type)
{
string name = System.IO.Path.GetFileNameWithoutExtension(title);
int id = GetId(type, name);
return id;
}
int GetId(Type type, string memberName)
{
object value = type.GetFields().FirstOrDefault(p => p.Name == memberName)?.GetValue(type)
?? type.GetProperties().FirstOrDefault(p => p.Name == memberName)?.GetValue(type);
if (value is int)
return (int)value;
return 0;
}
}
}
Custom Renderer
не требуется , вы можете изменить Title
и Icon
непосредственно в общем коде.
просто реализовать CurrentPageChanged
событие TabbedPage
код
public partial class TabbedPage1 : TabbedPage
{
NavigationPage homePage;
NavigationPage phrasesPage;
public TabbedPage1 ()
{
InitializeComponent();
var homePage = new NavigationPage(new Page1())
{
Title = "Home",
Icon = "1.png"
};
var phrasesPage = new NavigationPage (new Page2())
{
Title = "Play",
Icon = "1.png"
};
Children.Add(homePage);
Children.Add(phrasesPage);
this.CurrentPageChanged += (object sender, EventArgs e) => {
var i = this.Children.IndexOf(this.CurrentPage);
if (i == 0)
{
homePage.Title = "HomeChanged";
homePage.Icon = "2.png";
}
else {
phrasesPage.Title = "PlayChanged";
phrasesPage.Icon = "2.png";
}
};
}
}
результат
PS: сделайте доступ к файлам изображений с другой платформы.
iOS -Resources
Android -Resources->drawable
Я думаю, вы используете пользовательский рендер для настройки страницы с вкладками. Для Android вы должны ссылаться на значок из ресурса.Drawable. Пожалуйста, попробуйте С ниже фрагмента кода в Android визуализации.
public class CustomTabRenderer: TabbedRenderer
{
private Activity _act;
protected override void OnModelChanged(VisualElement oldModel, VisualElement newModel)
{
base.OnModelChanged(oldModel, newModel);
_act = this.Context as Activity;
}
// You can do the below function anywhere.
public override void OnWindowFocusChanged(bool hasWindowFocus)
{
ActionBar actionBar = _act.ActionBar;
if (actionBar.TabCount > 0)
{
Android.App.ActionBar.Tab tabOne = actionBar.GetTabAt(0);
tabOne.SetIcon(Resource.Drawable.shell);
}
base.OnWindowFocusChanged(hasWindowFocus);
}
}
см. это также: https://forums.xamarin.com/discussion/17654/tabbedpage-icons-not-visible-android
попробуйте добавить этот код OnElementChanged
на TabbedPageRenderer
if (e.PropertyName == "Renderer")
{
ViewPager pager = (ViewPager)ViewGroup.GetChildAt(0);
TabLayout layout = (TabLayout)ViewGroup.GetChildAt(1);
for (int i = 0; i < layout.TabCount; i++)
{
var tab = layout.GetTabAt(i);
var icon = tab.Icon;
if (icon != null)
{
icon = Android.Support.V4.Graphics.Drawable.DrawableCompat.Wrap(icon);
Android.Support.V4.Graphics.Drawable.DrawableCompat.SetTintList(icon, colors);
}
}
}
подробнее здесь : https://montemagno.com/xamarin-forms-android-selected-and-unselected-tab-colors/