{
base.OnElementChanged(e);
- var activity = (FormsAppCompatActivity)Context;
+ var activity = (FormsAppCompatActivity)Context.GetActivity();
if (e.OldElement != null)
((IPageController)e.OldElement).InternalChildren.CollectionChanged -= OnChildrenCollectionChanged;
public bool MarkedForDispose { get; internal set; } = false;
- FragmentManager FragmentManager => _fragmentManager ?? (_fragmentManager = ((FormsAppCompatActivity)Context).SupportFragmentManager);
+ FragmentManager FragmentManager => _fragmentManager ?? (_fragmentManager = Context.GetFragmentManager());
protected override void OnLayout(bool changed, int l, int t, int r, int b)
{
{
if (_platform == null)
{
- if (Context is FormsAppCompatActivity activity)
+ if (Context.GetActivity() is FormsAppCompatActivity activity)
{
_platform = activity.Platform;
}
}
}
- FragmentManager FragmentManager => _fragmentManager ?? (_fragmentManager = ((FormsAppCompatActivity)Context).SupportFragmentManager);
+ FragmentManager FragmentManager => _fragmentManager ?? (_fragmentManager = Context.GetFragmentManager());
IPageController PageController => Element;
void SetupToolbar()
{
Context context = Context;
- var activity = (FormsAppCompatActivity)context;
+ var activity = context.GetActivity();
AToolbar bar;
if (FormsAppCompatActivity.ToolbarResource != 0)
return;
Context context = Context;
- var activity = (FormsAppCompatActivity)context;
AToolbar bar = _toolbar;
ActionBarDrawerToggle toggle = _drawerToggle;
toggle.SyncState();
}
- if (NavigationPage.GetHasBackButton(currentPage))
+ if (NavigationPage.GetHasBackButton(currentPage) && !Context.IsDesignerContext())
{
+ var activity = (global::Android.Support.V7.App.AppCompatActivity)context.GetActivity();
var icon = new DrawerArrowDrawable(activity.SupportActionBar.ThemedContext);
icon.Progress = 1;
bar.NavigationIcon = icon;
void LayoutRootPage(Page page, int width, int height)
{
- var activity = (FormsAppCompatActivity)_context;
- page.Layout(new Rectangle(0, 0, activity.FromPixels(width), activity.FromPixels(height)));
+ page.Layout(new Rectangle(0, 0, _context.FromPixels(width), _context.FromPixels(height)));
}
Task PresentModal(Page modal, bool animated)
{
if (changed)
{
- var activity = (FormsAppCompatActivity)Context;
-
- _modal.Layout(new Rectangle(0, 0, activity.FromPixels(r - l), activity.FromPixels(b - t)));
+ _modal.Layout(new Rectangle(0, 0, Context.FromPixels(r - l), Context.FromPixels(b - t)));
_backgroundView.Layout(0, 0, r - l, b - t);
}
}
}
- FragmentManager FragmentManager => _fragmentManager ?? (_fragmentManager = ((FormsAppCompatActivity)Context).SupportFragmentManager);
+ FragmentManager FragmentManager => _fragmentManager ?? (_fragmentManager = Context.GetFragmentManager());
bool IsBottomTabPlacement => (Element != null) ? Element.OnThisPlatform().GetToolbarPlacement() == ToolbarPlacement.Bottom : false;
public Color BarItemColor
{
base.OnElementChanged(e);
- var activity = (FormsAppCompatActivity)Context;
+ var activity = Context.GetActivity();
if (e.OldElement != null)
((IPageController)e.OldElement).InternalChildren.CollectionChanged -= OnChildrenCollectionChanged;
using Android.Views.InputMethods;
using AApplicationInfoFlags = Android.Content.PM.ApplicationInfoFlags;
using AActivity = Android.App.Activity;
+using AFragmentManager = Android.Support.V4.App.FragmentManager;
namespace Xamarin.Forms.Platform.Android
{
return null;
}
+
+ internal static Context GetThemedContext(this Context context)
+ {
+ if (context == null)
+ return null;
+
+ if (context.IsDesignerContext())
+ return context;
+
+ if (context is global::Android.Support.V7.App.AppCompatActivity activity)
+ return activity.SupportActionBar.ThemedContext;
+
+ if (context is ContextWrapper contextWrapper)
+ return contextWrapper.BaseContext.GetThemedContext();
+
+ return null;
+ }
+
+ internal static bool IsDesignerContext(this Context context)
+ {
+ if (context == null)
+ return false;
+
+ if ($"{context.ToString()}".Contains("com.android.layoutlib.bridge.android.BridgeContext"))
+ return true;
+
+ if (context is ContextWrapper contextWrapper)
+ return contextWrapper.BaseContext.IsDesignerContext();
+
+ return false;
+ }
+
+ public static AFragmentManager GetFragmentManager(this Context context)
+ {
+ if (context == null)
+ return null;
+
+ var activity = context.GetActivity();
+
+ if (activity is global::Android.Support.V4.App.FragmentActivity fa)
+ return fa.SupportFragmentManager;
+
+ return null;
+ }
}
}
if (disposing)
{
- _renderer.Dispose();
+ _renderer?.Dispose();
_renderer = null;
_view = null;
_context = null;
protected virtual void LoadView(IShellContext shellContext)
{
var context = shellContext.AndroidContext;
- var coordinator = LayoutInflater.FromContext(context).Inflate(Resource.Layout.FlyoutContent, null);
- var recycler = coordinator.FindViewById<RecyclerView>(Resource.Id.flyoutcontent_recycler);
- var appBar = coordinator.FindViewById<AppBarLayout>(Resource.Id.flyoutcontent_appbar);
+ var coordinator = (ViewGroup)LayoutInflater.FromContext(context).Inflate(Resource.Layout.FlyoutContent, null);
+ var recycler = coordinator.FindViewById<RecyclerView>(Resource.Id.flyoutcontent_recycler);
+ var appBar = coordinator.FindViewById<ViewGroup>(Resource.Id.flyoutcontent_appbar);
- _rootView = coordinator;
+ _rootView = coordinator;
- appBar.AddOnOffsetChangedListener(this);
+ if((recycler == null || appBar == null) && !context.IsDesignerContext())
+ {
+ if (recycler == null)
+ throw new ArgumentNullException("flyoutcontent_recycler", "Unable to find layout for flyoutcontent_recycler");
+
+ // PREVIEWER HACK for some reason previewer pulls this out as a FrameLayout and ignores the internal resources
+ if (appBar == null)
+ throw new ArgumentNullException("flyoutcontent_appbar", "Unable to find layout for flyoutcontent_recycler");
+
+ }
+
+
+ try
+ {
+ // PREVIEWER HACK for some reason previewer can't find the resources for the recycler or the appBar
+ if (recycler == null)
+ recycler = (RecyclerView)coordinator.GetChildAt(1);
+ if (appBar == null)
+ appBar = (AppBarLayout)coordinator.GetChildAt(0);
+ }
+ catch
+ {
+ // PReviewer hack.
+ // appcompat and non appcompat initialize this whole thing differently so the above are for appcompat the below are for non
+ }
+
+ // PREVIEWER HACK for some reason previewer can't find the resources for the recycler or the appBar
+ if (recycler == null)
+ recycler = coordinator.FindViewById<RecyclerView>(context.Resources.GetIdentifier("flyoutcontent_recycler", "id", context.PackageName));
+
+ // PREVIEWER HACK for some reason previewer pulls this out as a FrameLayout and ignores the internal resources
+ if (appBar == null)
+ appBar = coordinator.FindViewById<ViewGroup>(context.Resources.GetIdentifier("flyoutcontent_appbar", "id", context.PackageName));
+
+
+ (appBar as AppBarLayout)?.AddOnOffsetChangedListener(this);
int actionBarHeight = (int)context.ToPixels(56);
var metrics = context.Resources.DisplayMetrics;
var width = Math.Min(metrics.WidthPixels, metrics.HeightPixels);
- TypedValue tv = new TypedValue();
- if (context.Theme.ResolveAttribute(global::Android.Resource.Attribute.ActionBarSize, tv, true))
- {
- actionBarHeight = TypedValue.ComplexToDimensionPixelSize(tv.Data, metrics);
- }
+ using (TypedValue tv = new TypedValue())
+ {
+ if (context.Theme.ResolveAttribute(global::Android.Resource.Attribute.ActionBarSize, tv, true))
+ {
+ actionBarHeight = TypedValue.ComplexToDimensionPixelSize(tv.Data, metrics);
+ }
+ }
+
width -= actionBarHeight;
coordinator.LayoutParameters = new LP(width, LP.MatchParent);
VisualElementTracker IVisualElementRenderer.Tracker => null;
AView IVisualElementRenderer.View => _flyoutRenderer.AndroidView;
- ViewGroup IVisualElementRenderer.ViewGroup => _flyoutRenderer.AndroidView as ViewGroup;
+
+ // Used by Previewer
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public ViewGroup ViewGroup => _flyoutRenderer.AndroidView as ViewGroup;
SizeRequest IVisualElementRenderer.GetDesiredSize(int widthConstraint, int heightConstraint)
{
{
}
- void IVisualElementRenderer.UpdateLayout()
+ // Used by Previewer
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void UpdateLayout()
{
var width = (int)AndroidContext.ToPixels(Element.Width);
var height = (int)AndroidContext.ToPixels(Element.Height);
protected Context AndroidContext { get; }
protected Shell Element { get; private set; }
- private FragmentManager FragmentManager => ((FormsAppCompatActivity)AndroidContext).SupportFragmentManager;
+ FragmentManager FragmentManager => AndroidContext.GetFragmentManager();
protected virtual IShellObservableFragment CreateFragmentForPage(Page page)
{
protected virtual void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == Shell.CurrentItemProperty.PropertyName)
- {
SwitchFragment(FragmentManager, _frameLayout, Element.CurrentItem);
- }
_elementPropertyChanged?.Invoke(sender, e);
}
((IShellController)shell).AddAppearanceObserver(this, shell);
- SwitchFragment(FragmentManager, _frameLayout, shell.CurrentItem, false);
+ // Previewer Hack
+ if(AndroidContext.GetActivity() != null)
+ SwitchFragment(FragmentManager, _frameLayout, shell.CurrentItem, false);
}
IShellItemRenderer _currentRenderer;
protected virtual void SwitchFragment(FragmentManager manager, AView targetView, ShellItem newItem, bool animate = true)
{
+ if (AndroidContext.IsDesignerContext())
+ return;
+
var previousRenderer = _currentRenderer;
_currentRenderer = CreateShellItemRenderer(newItem);
_currentRenderer.ShellItem = newItem;
void UpdateStatusBarColor(ShellAppearance appearance)
{
- var activity = ((FormsAppCompatActivity)AndroidContext);
- var window = activity.Window;
- var decorView = window.DecorView;
- var resources = activity.Resources;
+ var activity = AndroidContext.GetActivity();
+ var window = activity?.Window;
+ var decorView = window?.DecorView;
+ var resources = AndroidContext.Resources;
int statusBarHeight = 0;
int resourceId = resources.GetIdentifier("status_bar_height", "dimen", "android");
navigationBarHeight = resources.GetDimensionPixelSize(resourceId);
}
- // we are using the split drawable here to avoid GPU overdraw.
- // All it really is is a drawable that only draws under the statusbar/bottom bar to make sure
- // we dont draw over areas we dont need to. This has very limited benefits considering its
- // only saving us a flat color fill BUT it helps people not freak out about overdraw.
- if (appearance != null)
- {
- var color = appearance.BackgroundColor.ToAndroid(Color.FromHex("#03A9F4"));
- decorView.SetBackground(new SplitDrawable(color, statusBarHeight, navigationBarHeight));
- }
- else
+ // TODO Previewer Hack
+ if (decorView != null)
{
- var color = Color.FromHex("#03A9F4").ToAndroid();
- decorView.SetBackground(new SplitDrawable(color, statusBarHeight, navigationBarHeight));
+ // we are using the split drawable here to avoid GPU overdraw.
+ // All it really is is a drawable that only draws under the statusbar/bottom bar to make sure
+ // we dont draw over areas we dont need to. This has very limited benefits considering its
+ // only saving us a flat color fill BUT it helps people not freak out about overdraw.
+ if (appearance != null)
+ {
+ var color = appearance.BackgroundColor.ToAndroid(Color.FromHex("#03A9F4"));
+ decorView.SetBackground(new SplitDrawable(color, statusBarHeight, navigationBarHeight));
+ }
+ else
+ {
+ var color = Color.FromHex("#03A9F4").ToAndroid();
+ decorView.SetBackground(new SplitDrawable(color, statusBarHeight, navigationBarHeight));
+ }
}
}
var backButtonHandler = Shell.GetBackButtonBehavior(page);
toolbar.SetNavigationOnClickListener(this);
- var activity = (FormsAppCompatActivity)context;
-
if (backButtonHandler != null)
{
- await UpdateDrawerArrowFromBackButtonBehavior(context, toolbar, drawerLayout, backButtonHandler, activity);
+ await UpdateDrawerArrowFromBackButtonBehavior(context, toolbar, drawerLayout, backButtonHandler);
}
else
{
- await UpdateDrawerArrow(context, toolbar, drawerLayout, activity);
+ await UpdateDrawerArrow(context, toolbar, drawerLayout);
}
}
- protected virtual async Task UpdateDrawerArrow(Context context, Toolbar toolbar, DrawerLayout drawerLayout, FormsAppCompatActivity activity)
+ protected virtual async Task UpdateDrawerArrow(Context context, Toolbar toolbar, DrawerLayout drawerLayout)
{
- if (_drawerToggle == null)
+ if (_drawerToggle == null && !context.IsDesignerContext())
{
- _drawerToggle = new ActionBarDrawerToggle((Activity)context, drawerLayout, toolbar,
+ _drawerToggle = new ActionBarDrawerToggle(context.GetActivity(), drawerLayout, toolbar,
R.String.Ok, R.String.Ok)
{
ToolbarNavigationClickListener = this,
if (CanNavigateBack)
{
_drawerToggle.DrawerIndicatorEnabled = false;
- using (var icon = new DrawerArrowDrawable(activity.SupportActionBar.ThemedContext))
+ using (var icon = new DrawerArrowDrawable(context.GetThemedContext()))
{
icon.SetColorFilter(TintColor.ToAndroid(Color.White), PorterDuff.Mode.SrcAtop);
icon.Progress = 1;
_drawerToggle.SyncState();
}
- protected virtual async Task UpdateDrawerArrowFromBackButtonBehavior(Context context, Toolbar toolbar, DrawerLayout drawerLayout, BackButtonBehavior backButtonHandler, FormsAppCompatActivity activity)
+ protected virtual async Task UpdateDrawerArrowFromBackButtonBehavior(Context context, Toolbar toolbar, DrawerLayout drawerLayout, BackButtonBehavior backButtonHandler)
{
var behavior = backButtonHandler;
var command = behavior.Command;
if (CanNavigateBack && icon == null)
{
- icon = new DrawerArrowDrawable(activity.SupportActionBar.ThemedContext);
+ icon = new DrawerArrowDrawable(context.GetThemedContext());
(icon as DrawerArrowDrawable).Progress = 1;
}
>
<android.support.design.widget.AppBarLayout
- android:id="@+id/flyoutcontent.appbar"
+ android:id="@+id/flyoutcontent_appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
<android.support.v7.widget.RecyclerView
- android:id="@+id/flyoutcontent.recycler"
+ android:id="@+id/flyoutcontent_recycler"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
--- /dev/null
+<?xml version="1.0" encoding="utf-8" ?>
+<Shell xmlns="http://xamarin.com/schemas/2014/forms"
+ xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
+ x:Class="Xamarin.Forms.Sandbox.ShellPage">
+
+ <ShellContent Title="test">
+ <ContentPage></ContentPage>
+ </ShellContent>
+</Shell>
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using Xamarin.Forms;
+using Xamarin.Forms.Xaml;
+
+namespace Xamarin.Forms.Sandbox
+{
+ [XamlCompilation(XamlCompilationOptions.Compile)]
+ public partial class ShellPage : Shell
+ {
+ public ShellPage()
+ {
+ InitializeComponent();
+ }
+ }
+}
\ No newline at end of file
<DebugType>pdbonly</DebugType>
<DebugSymbols>true</DebugSymbols>
</PropertyGroup>
+
+ <ItemGroup>
+ <None Include="ShellPage.xaml">
+ <Generator>MSBuild:Compile</Generator>
+ </None>
+ </ItemGroup>
<ItemGroup>
<!-- A reference to the entire .NET Framework is automatically included -->