FindViewById на подстранице Android (с использованием Xamarin.Forms)

Я разрабатываю кроссплатформенное приложение с использованием Xamarin.Forms. Поскольку я хочу установить для фона моего TabLayouts градиент, который изначально не поддерживается в XF, я написал специальный рендерер для моих TabbedPages:

using Android.App;
using Android.Graphics;
using Android.Support.Design.Widget;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
using Xamarin.Forms.Platform.Android.AppCompat;
using MyApp.Droid.Renderer;

[assembly: ExportRenderer(typeof(TabbedPage), typeof(CustomTabbedPageRenderer))]
namespace MyApp.Droid.Renderer
{
    public class CustomTabbedPageRenderer : TabbedPageRenderer
    {
        private Activity _activity;

        protected override void OnElementChanged(ElementChangedEventArgs<TabbedPage> e)
        {
            base.OnElementChanged(e);

            _activity = this.Context as FormsAppCompatActivity;
        }

        protected override void DispatchDraw(Canvas canvas)
        {
            base.DispatchDraw(canvas);

            TabLayout tabs = _activity.FindViewById<TabLayout>(Resource.Id.sliding_tabs);

            var gradient = new MyGradient();

            tabs.SetBackground(gradient);
        }
    }
}

Теперь, как и предполагалось, средство визуализации запускается каждый раз, когда приложение загружает TabbedPage. Тем не мение, _activity.FindViewById<TabLayout>(Resource.Id.sliding_tabs) всегда просто возвращает TabLayout моей MainPage (также правильно устанавливая MyGradient в качестве фона), и я не могу понять, как получить TabLayout на одной из моих подстраниц, чтобы изменить его.

Не уверен, если это проблема с Xamarin или Android...

Надеюсь, вы, ребята, можете мне помочь.

Спасибо!

январь

РЕДАКТИРОВАТЬ: вот файл styles.xml (надеюсь, это то, на что ссылался @Code-Apprentice):

<resources>
  <style name="MainTheme" parent="MainTheme.Base">
  </style>
  <!-- Base theme applied no matter what API -->
  <style name="MainTheme.Base" parent="Theme.AppCompat.Light.DarkActionBar">
    <!--If you are using revision 22.1 please use just windowNoTitle. Without android:-->
    <item name="windowNoTitle">true</item>
    <!--We will be using the toolbar so no need to show ActionBar-->
    <item name="windowActionBar">false</item>
    <!-- Set theme colors from http://www.google.com/design/spec/style/color.html#color-color-palette -->
    <!-- colorPrimary is used for the default action bar background -->
    <item name="colorPrimary">#2196F3</item>
    <!-- colorPrimaryDark is used for the status bar -->
    <!--<item name="colorPrimaryDark">#1976D2</item>-->
    <item name="colorPrimaryDark">#FF8630</item>
    <!--<item name="android:windowTranslucentStatus">true</item>-->
    <!-- colorAccent is used as the default value for colorControlActivated
     which is used to tint widgets -->
    <item name="colorAccent">#FF4081</item>
    <!-- You can also set colorControlNormal, colorControlActivated
     colorControlHighlight and colorSwitchThumbNormal. -->
    <item name="windowActionModeOverlay">true</item>

    <item name="android:datePickerDialogTheme">@style/AppCompatDialogStyle</item>
  </style>

  <style name="AppCompatDialogStyle" parent="Theme.AppCompat.Light.Dialog">
    <item name="colorAccent">#FF4081</item>
  </style>
</resources>

Также скриншот верхней части главной страницы: https://i.imgur.com/VyX3YX7.png

И это подстраница ( MainPage.Navigation.PushAsync(новая SubPage ());): https://i.imgur.com/pRmecjE.png

2 ответа

Решение

Для всех, кто интересуется, вот как я могу получить результат, которого я хочу сейчас (хотя я думаю, что это не самый элегантный способ сделать это):

using Android.Runtime;
using Android.Support.Design.Widget;
using Android.Views;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
using Xamarin.Forms.Platform.Android.AppCompat;
using MyApp.Droid.Renderer;

[assembly: ExportRenderer(typeof(TabbedPage), typeof(CustomTabbedPageRenderer))]
namespace MyApp.Droid.Renderer
{
    public class CustomTabbedPageRenderer : TabbedPageRenderer
    {
        protected override void OnVisibilityChanged(Android.Views.View changedView, [GeneratedEnum] ViewStates visibility)
        {
            base.OnVisibilityChanged(changedView, visibility);

            if (visibility == ViewStates.Visible)
            {
                var tabs = changedView.FindViewById<TabLayout>(Resource.Id.sliding_tabs);
                var gradient = new MyGradient();
                tabs.SetBackground(gradient);
            }
        }
    }
}

Я получаю оба TabbedPages в моем приложении просто отлично (через рендерер), но мне нужен TabLayout (панель сверху, которая содержит вкладки на Android).

Если я правильно понимаю ваш вопрос на этот раз, вы хотите настроить макет вкладки в TabbedPage для каждой подстраницы.

Тогда вам нужно будет переопределить SetTabIcon метод в TabbedPageRenderer, Например:

[assembly: ExportRenderer(typeof(MyTabbedPage), typeof(MyTabbedPageRenderer))]

namespace YourNameSpace.Droid
{
    public class MyTabbedPageRenderer : TabbedPageRenderer
    {
        protected override void SetTabIcon(TabLayout.Tab tab, FileImageSource icon)
        {
            base.SetTabIcon(tab, icon);

            //set your custom layout for tab. The layout resource "mytablayout" is placed in the layout folder of android project.
            tab.SetCustomView(Resource.Layout.mytablayout);          
        }
    }
}

Вы также можете проверить мой ответ на этот вопрос, там я разместил Button на вкладке, чтобы удалить соответствующую подстраницу.

Другие вопросы по тегам