feature: Android renderers
This commit is contained in:
parent
a4caf325b0
commit
f6dbec2fda
@ -34,14 +34,15 @@
|
|||||||
<AndroidLinkMode>None</AndroidLinkMode>
|
<AndroidLinkMode>None</AndroidLinkMode>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<DebugType></DebugType>
|
||||||
<Optimize>true</Optimize>
|
<Optimize>true</Optimize>
|
||||||
<OutputPath>bin\Release</OutputPath>
|
<OutputPath>bin\Release</OutputPath>
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<WarningLevel>4</WarningLevel>
|
<WarningLevel>4</WarningLevel>
|
||||||
<AndroidManagedSymbols>true</AndroidManagedSymbols>
|
<AndroidManagedSymbols>true</AndroidManagedSymbols>
|
||||||
<AndroidUseSharedRuntime>false</AndroidUseSharedRuntime>
|
<AndroidUseSharedRuntime>false</AndroidUseSharedRuntime>
|
||||||
<AndroidCreatePackagePerAbi>true</AndroidCreatePackagePerAbi>
|
<AndroidCreatePackagePerAbi>true</AndroidCreatePackagePerAbi>
|
||||||
<AndroidSupportedAbis>arm64-v8a</AndroidSupportedAbis>
|
<AndroidSupportedAbis>arm64-v8a</AndroidSupportedAbis>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="Mono.Android" />
|
<Reference Include="Mono.Android" />
|
||||||
@ -70,6 +71,14 @@
|
|||||||
<Compile Include="Renderers\CardViewRenderer.cs" />
|
<Compile Include="Renderers\CardViewRenderer.cs" />
|
||||||
<Compile Include="Renderers\BlurryPanelRenderer.cs" />
|
<Compile Include="Renderers\BlurryPanelRenderer.cs" />
|
||||||
<Compile Include="Renderers\SegmentedControlRenderer.cs" />
|
<Compile Include="Renderers\SegmentedControlRenderer.cs" />
|
||||||
|
<Compile Include="Renderers\OptionEntryRenderer.cs" />
|
||||||
|
<Compile Include="Renderers\RoundLabelRenderer.cs" />
|
||||||
|
<Compile Include="Renderers\AppShellRenderer.cs" />
|
||||||
|
<Compile Include="Renderers\AppShellSection\AppShellBottomNavViewAppearanceTracker.cs" />
|
||||||
|
<Compile Include="Renderers\AppShellSection\AppColorChangeRevealDrawable.cs" />
|
||||||
|
<Compile Include="Renderers\SearchBarRenderer.cs" />
|
||||||
|
<Compile Include="SplashActivity.cs" />
|
||||||
|
<Compile Include="Renderers\RoundImageRenderer.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="Resources\AboutResources.txt" />
|
<None Include="Resources\AboutResources.txt" />
|
||||||
@ -181,6 +190,22 @@
|
|||||||
<SubType></SubType>
|
<SubType></SubType>
|
||||||
<Generator></Generator>
|
<Generator></Generator>
|
||||||
</AndroidResource>
|
</AndroidResource>
|
||||||
|
<AndroidResource Include="Resources\drawable\splash_logo.png">
|
||||||
|
<SubType></SubType>
|
||||||
|
<Generator></Generator>
|
||||||
|
</AndroidResource>
|
||||||
|
<AndroidResource Include="Resources\drawable\splash_screen.xml">
|
||||||
|
<SubType></SubType>
|
||||||
|
<Generator></Generator>
|
||||||
|
</AndroidResource>
|
||||||
|
<AndroidResource Include="Resources\drawable-night\ic_search.xml">
|
||||||
|
<SubType></SubType>
|
||||||
|
<Generator></Generator>
|
||||||
|
</AndroidResource>
|
||||||
|
<AndroidResource Include="Resources\drawable\ic_search.xml">
|
||||||
|
<SubType></SubType>
|
||||||
|
<Generator></Generator>
|
||||||
|
</AndroidResource>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Folder Include="Resources\drawable\" />
|
<Folder Include="Resources\drawable\" />
|
||||||
@ -193,6 +218,8 @@
|
|||||||
<Folder Include="Resources\mipmap-xxxhdpi\" />
|
<Folder Include="Resources\mipmap-xxxhdpi\" />
|
||||||
<Folder Include="Renderers\" />
|
<Folder Include="Renderers\" />
|
||||||
<Folder Include="Resources\color\" />
|
<Folder Include="Resources\color\" />
|
||||||
|
<Folder Include="Renderers\AppShellSection\" />
|
||||||
|
<Folder Include="Resources\drawable-night\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<AndroidAsset Include="Assets\fa-light-300.ttf" />
|
<AndroidAsset Include="Assets\fa-light-300.ttf" />
|
||||||
|
23
Pixiview.Android/Renderers/AppShellRenderer.cs
Normal file
23
Pixiview.Android/Renderers/AppShellRenderer.cs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#if TODO
|
||||||
|
using Android.Content;
|
||||||
|
using Pixiview.Droid.Renderers;
|
||||||
|
using Pixiview.Droid.Renderers.AppShellSection;
|
||||||
|
using Xamarin.Forms;
|
||||||
|
using Xamarin.Forms.Platform.Android;
|
||||||
|
|
||||||
|
[assembly: ExportRenderer(typeof(Shell), typeof(AppShellRenderer))]
|
||||||
|
namespace Pixiview.Droid.Renderers
|
||||||
|
{
|
||||||
|
public class AppShellRenderer : ShellRenderer
|
||||||
|
{
|
||||||
|
public AppShellRenderer(Context context) : base(context)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override IShellBottomNavViewAppearanceTracker CreateBottomNavViewAppearanceTracker(ShellItem shellItem)
|
||||||
|
{
|
||||||
|
return new AppShellBottomNavViewAppearanceTracker(this, shellItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
@ -0,0 +1,98 @@
|
|||||||
|
using Android.Animation;
|
||||||
|
using Android.Graphics;
|
||||||
|
using Android.Graphics.Drawables;
|
||||||
|
using System;
|
||||||
|
using AColor = Android.Graphics.Color;
|
||||||
|
|
||||||
|
namespace Pixiview.Droid.Renderers.AppShellSection
|
||||||
|
{
|
||||||
|
public class AppColorChangeRevealDrawable : AnimationDrawable
|
||||||
|
{
|
||||||
|
readonly Point _center;
|
||||||
|
float _progress;
|
||||||
|
bool _disposed;
|
||||||
|
ValueAnimator _animator;
|
||||||
|
|
||||||
|
internal AColor StartColor { get; }
|
||||||
|
internal AColor EndColor { get; }
|
||||||
|
|
||||||
|
public AppColorChangeRevealDrawable(AColor startColor, AColor endColor, Point center) : base()
|
||||||
|
{
|
||||||
|
StartColor = startColor;
|
||||||
|
EndColor = endColor;
|
||||||
|
|
||||||
|
if (StartColor != EndColor)
|
||||||
|
{
|
||||||
|
_animator = ValueAnimator.OfFloat(0, 1);
|
||||||
|
_animator.SetInterpolator(new Android.Views.Animations.DecelerateInterpolator());
|
||||||
|
_animator.SetDuration(500);
|
||||||
|
_animator.Update += OnUpdate;
|
||||||
|
_animator.Start();
|
||||||
|
_center = center;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_progress = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Draw(Canvas canvas)
|
||||||
|
{
|
||||||
|
if (_disposed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_progress == 1)
|
||||||
|
{
|
||||||
|
canvas.DrawColor(EndColor);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas.DrawColor(StartColor);
|
||||||
|
var bounds = Bounds;
|
||||||
|
float centerX = _center.X;
|
||||||
|
float centerY = _center.Y;
|
||||||
|
|
||||||
|
float width = bounds.Width();
|
||||||
|
float distanceFromCenter = Math.Abs(width / 2 - _center.X);
|
||||||
|
float radius = (width / 2 + distanceFromCenter) * 1.1f;
|
||||||
|
|
||||||
|
var paint = new Paint
|
||||||
|
{
|
||||||
|
Color = EndColor
|
||||||
|
};
|
||||||
|
|
||||||
|
canvas.DrawCircle(centerX, centerY, radius * _progress, paint);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnUpdate(object sender, ValueAnimator.AnimatorUpdateEventArgs e)
|
||||||
|
{
|
||||||
|
_progress = (float)e.Animation.AnimatedValue;
|
||||||
|
|
||||||
|
InvalidateSelf();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (_disposed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_disposed = true;
|
||||||
|
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
if (_animator != null)
|
||||||
|
{
|
||||||
|
_animator.Update -= OnUpdate;
|
||||||
|
|
||||||
|
_animator.Cancel();
|
||||||
|
|
||||||
|
_animator.Dispose();
|
||||||
|
|
||||||
|
_animator = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
base.Dispose(disposing);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,170 @@
|
|||||||
|
using Android.Content.Res;
|
||||||
|
using Android.Graphics.Drawables;
|
||||||
|
#if __ANDROID_29__
|
||||||
|
using AndroidX.Core.Widget;
|
||||||
|
using Google.Android.Material.BottomNavigation;
|
||||||
|
#else
|
||||||
|
using Android.Support.Design.Internal;
|
||||||
|
using Android.Support.Design.Widget;
|
||||||
|
#endif
|
||||||
|
using System;
|
||||||
|
using Xamarin.Forms;
|
||||||
|
using Xamarin.Forms.Platform.Android;
|
||||||
|
using AColor = Android.Graphics.Color;
|
||||||
|
using R = Android.Resource;
|
||||||
|
|
||||||
|
namespace Pixiview.Droid.Renderers.AppShellSection
|
||||||
|
{
|
||||||
|
public class AppShellBottomNavViewAppearanceTracker : IShellBottomNavViewAppearanceTracker
|
||||||
|
{
|
||||||
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0052:Remove unread private members", Justification = "<Pending>")]
|
||||||
|
IShellContext _shellContext;
|
||||||
|
ShellItem _shellItem;
|
||||||
|
ColorStateList _defaultList;
|
||||||
|
bool _disposed;
|
||||||
|
ColorStateList _colorStateList;
|
||||||
|
|
||||||
|
public AppShellBottomNavViewAppearanceTracker(IShellContext shellContext, ShellItem shellItem)
|
||||||
|
{
|
||||||
|
_shellItem = shellItem;
|
||||||
|
_shellContext = shellContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void ResetAppearance(BottomNavigationView bottomView)
|
||||||
|
{
|
||||||
|
if (_defaultList != null)
|
||||||
|
{
|
||||||
|
bottomView.ItemTextColor = _defaultList;
|
||||||
|
bottomView.ItemIconTintList = _defaultList;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetBackgroundColor(bottomView, Color.White);
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void SetAppearance(BottomNavigationView bottomView, IShellAppearanceElement appearance)
|
||||||
|
{
|
||||||
|
IShellAppearanceElement controller = appearance;
|
||||||
|
var backgroundColor = controller.EffectiveTabBarBackgroundColor;
|
||||||
|
var foregroundColor = controller.EffectiveTabBarForegroundColor;
|
||||||
|
var disabledColor = controller.EffectiveTabBarDisabledColor;
|
||||||
|
var unselectedColor = controller.EffectiveTabBarUnselectedColor; // currently unused
|
||||||
|
var titleColor = controller.EffectiveTabBarTitleColor;
|
||||||
|
|
||||||
|
if (_defaultList == null)
|
||||||
|
{
|
||||||
|
#if __ANDROID_28__
|
||||||
|
_defaultList = bottomView.ItemTextColor ?? bottomView.ItemIconTintList
|
||||||
|
?? MakeColorStateList(titleColor.ToAndroid().ToArgb(), disabledColor.ToAndroid().ToArgb(), foregroundColor.ToAndroid().ToArgb());
|
||||||
|
#else
|
||||||
|
_defaultList = bottomView.ItemTextColor ?? bottomView.ItemIconTintList;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
_colorStateList = MakeColorStateList(titleColor, disabledColor, foregroundColor);
|
||||||
|
bottomView.ItemTextColor = _colorStateList;
|
||||||
|
bottomView.ItemIconTintList = _colorStateList;
|
||||||
|
|
||||||
|
SetBackgroundColor(bottomView, backgroundColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void SetBackgroundColor(BottomNavigationView bottomView, Color color)
|
||||||
|
{
|
||||||
|
var oldBackground = bottomView.Background;
|
||||||
|
var colorDrawable = oldBackground as ColorDrawable;
|
||||||
|
var colorChangeRevealDrawable = oldBackground as AppColorChangeRevealDrawable;
|
||||||
|
AColor lastColor = colorChangeRevealDrawable?.EndColor ?? colorDrawable?.Color ?? Color.Default.ToAndroid();
|
||||||
|
AColor newColor;
|
||||||
|
|
||||||
|
if (color == Color.Default)
|
||||||
|
newColor = Color.White.ToAndroid();
|
||||||
|
else
|
||||||
|
newColor = color.ToAndroid();
|
||||||
|
|
||||||
|
if (!(bottomView.GetChildAt(0) is BottomNavigationMenuView menuView))
|
||||||
|
{
|
||||||
|
if (colorDrawable != null && lastColor == newColor)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (lastColor != newColor || colorDrawable == null)
|
||||||
|
{
|
||||||
|
bottomView.SetBackground(new ColorDrawable(newColor));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (colorChangeRevealDrawable != null && lastColor == newColor)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var index = ((IShellItemController)_shellItem).GetItems().IndexOf(_shellItem.CurrentItem);
|
||||||
|
var menu = bottomView.Menu;
|
||||||
|
index = Math.Min(index, menu.Size() - 1);
|
||||||
|
|
||||||
|
var child = menuView.GetChildAt(index);
|
||||||
|
if (child == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var touchPoint = new Android.Graphics.Point(child.Left + (child.Right - child.Left) / 2, child.Top + (child.Bottom - child.Top) / 2);
|
||||||
|
|
||||||
|
bottomView.SetBackground(new AppColorChangeRevealDrawable(lastColor, newColor, touchPoint));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ColorStateList MakeColorStateList(Color titleColor, Color disabledColor, Color unselectedColor)
|
||||||
|
{
|
||||||
|
var disabledInt = disabledColor.IsDefault ?
|
||||||
|
_defaultList.GetColorForState(new[] { -R.Attribute.StateEnabled }, AColor.Gray) :
|
||||||
|
disabledColor.ToAndroid().ToArgb();
|
||||||
|
|
||||||
|
var checkedInt = titleColor.IsDefault ?
|
||||||
|
_defaultList.GetColorForState(new[] { R.Attribute.StateChecked }, AColor.Black) :
|
||||||
|
titleColor.ToAndroid().ToArgb();
|
||||||
|
|
||||||
|
var defaultColor = unselectedColor.IsDefault ?
|
||||||
|
_defaultList.DefaultColor :
|
||||||
|
unselectedColor.ToAndroid().ToArgb();
|
||||||
|
|
||||||
|
return MakeColorStateList(checkedInt, disabledInt, defaultColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
ColorStateList MakeColorStateList(int titleColorInt, int disabledColorInt, int defaultColor)
|
||||||
|
{
|
||||||
|
var states = new int[][] {
|
||||||
|
new int[] { -R.Attribute.StateEnabled },
|
||||||
|
new int[] {R.Attribute.StateChecked },
|
||||||
|
new int[] { }
|
||||||
|
};
|
||||||
|
|
||||||
|
var colors = new[] { disabledColorInt, titleColorInt, defaultColor };
|
||||||
|
|
||||||
|
return new ColorStateList(states, colors);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region IDisposable
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (_disposed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_disposed = true;
|
||||||
|
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
_defaultList?.Dispose();
|
||||||
|
_colorStateList?.Dispose();
|
||||||
|
|
||||||
|
_shellItem = null;
|
||||||
|
_shellContext = null;
|
||||||
|
_defaultList = null;
|
||||||
|
_colorStateList = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion IDisposable
|
||||||
|
}
|
||||||
|
}
|
@ -17,7 +17,14 @@ namespace Pixiview.Droid.Renderers
|
|||||||
{
|
{
|
||||||
base.OnElementChanged(e);
|
base.OnElementChanged(e);
|
||||||
|
|
||||||
SetBackgroundColor(Color.Black.MultiplyAlpha(.92).ToAndroid());
|
if (e.NewElement != null)
|
||||||
|
{
|
||||||
|
var color = e.NewElement.BackgroundColor;
|
||||||
|
if (!color.IsDefault)
|
||||||
|
{
|
||||||
|
SetBackgroundColor(color.MultiplyAlpha(.94).ToAndroid());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
using Android.Content;
|
using Android.Content;
|
||||||
using Android.Graphics;
|
using Android.Graphics;
|
||||||
using Android.Views;
|
|
||||||
using Pixiview.Droid.Renderers;
|
using Pixiview.Droid.Renderers;
|
||||||
using Pixiview.UI;
|
using Pixiview.UI;
|
||||||
using Xamarin.Forms;
|
using Xamarin.Forms;
|
||||||
@ -11,8 +10,6 @@ namespace Pixiview.Droid.Renderers
|
|||||||
{
|
{
|
||||||
public class CardViewRenderer : VisualElementRenderer<CardView>
|
public class CardViewRenderer : VisualElementRenderer<CardView>
|
||||||
{
|
{
|
||||||
ViewOutlineProvider original;
|
|
||||||
|
|
||||||
public CardViewRenderer(Context context) : base(context)
|
public CardViewRenderer(Context context) : base(context)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -27,39 +24,19 @@ namespace Pixiview.Droid.Renderers
|
|||||||
var radius = element.CornerRadius;
|
var radius = element.CornerRadius;
|
||||||
if (radius > 0)
|
if (radius > 0)
|
||||||
{
|
{
|
||||||
original = OutlineProvider;
|
//var scale = Resources.DisplayMetrics.Density;
|
||||||
OutlineProvider = new CornerRadiusOutlineProvider(element, radius);
|
//OutlineProvider = new CornerRadiusOutlineProvider(element, radius, scale);
|
||||||
ClipToOutline = true;
|
//ClipToOutline = true;
|
||||||
|
|
||||||
|
var density = Resources.DisplayMetrics.Density;
|
||||||
|
|
||||||
|
Elevation = (float)(element.ShadowOffset.Height + 2) * density;
|
||||||
|
|
||||||
|
var drawable = new RoundCornerDrawable(radius * density);
|
||||||
|
drawable.SetColorFilter(element.BackgroundColor.ToAndroid(), PorterDuff.Mode.Src);
|
||||||
|
((Android.Views.View)this).SetBackground(drawable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDetachedFromWindow()
|
|
||||||
{
|
|
||||||
OutlineProvider = original;
|
|
||||||
base.OnDetachedFromWindow();
|
|
||||||
}
|
|
||||||
|
|
||||||
private class CornerRadiusOutlineProvider : ViewOutlineProvider
|
|
||||||
{
|
|
||||||
private readonly Element element;
|
|
||||||
private readonly float radius;
|
|
||||||
|
|
||||||
public CornerRadiusOutlineProvider(Element from, float r)
|
|
||||||
{
|
|
||||||
element = from;
|
|
||||||
radius = r;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void GetOutline(Android.Views.View view, Outline outline)
|
|
||||||
{
|
|
||||||
var scale = view.Resources.DisplayMetrics.Density;
|
|
||||||
var width = (double)element.GetValue(VisualElement.WidthProperty) * scale;
|
|
||||||
var height = (double)element.GetValue(VisualElement.HeightProperty) * scale;
|
|
||||||
|
|
||||||
var rect = new Rect(0, 0, (int)width, (int)height);
|
|
||||||
outline.SetRoundRect(rect, radius * scale);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
28
Pixiview.Android/Renderers/OptionEntryRenderer.cs
Normal file
28
Pixiview.Android/Renderers/OptionEntryRenderer.cs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
using Android.Content;
|
||||||
|
using Android.Graphics.Drawables;
|
||||||
|
using Pixiview.Droid.Renderers;
|
||||||
|
using Pixiview.UI;
|
||||||
|
using Xamarin.Forms;
|
||||||
|
using Xamarin.Forms.Platform.Android;
|
||||||
|
|
||||||
|
[assembly: ExportRenderer(typeof(OptionEntry), typeof(OptionEntryRenderer))]
|
||||||
|
namespace Pixiview.Droid.Renderers
|
||||||
|
{
|
||||||
|
public class OptionEntryRenderer : EntryRenderer
|
||||||
|
{
|
||||||
|
public OptionEntryRenderer(Context context) : base(context)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
|
||||||
|
{
|
||||||
|
base.OnElementChanged(e);
|
||||||
|
|
||||||
|
if (e.NewElement != null)
|
||||||
|
{
|
||||||
|
var drawable = new ColorDrawable(e.NewElement.BackgroundColor.ToAndroid());
|
||||||
|
Control.SetBackground(drawable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
60
Pixiview.Android/Renderers/RoundImageRenderer.cs
Normal file
60
Pixiview.Android/Renderers/RoundImageRenderer.cs
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
using Android.Content;
|
||||||
|
using Android.Graphics;
|
||||||
|
using Pixiview.Droid.Renderers;
|
||||||
|
using Pixiview.UI;
|
||||||
|
using Xamarin.Forms;
|
||||||
|
|
||||||
|
[assembly: ExportRenderer(typeof(RoundImage), typeof(RoundImageRenderer))]
|
||||||
|
namespace Pixiview.Droid.Renderers
|
||||||
|
{
|
||||||
|
public class RoundImageRenderer : Xamarin.Forms.Platform.Android.FastRenderers.ImageRenderer
|
||||||
|
{
|
||||||
|
public RoundImageRenderer(Context context) : base(context)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetBackgroundColor(Android.Graphics.Color color)
|
||||||
|
{
|
||||||
|
// nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnDraw(Canvas canvas)
|
||||||
|
{
|
||||||
|
if (Element is RoundImage image)
|
||||||
|
{
|
||||||
|
var radius = image.CornerRadius;
|
||||||
|
var mask = image.CornerMasks;
|
||||||
|
if (radius > 0 && mask != CornerMask.None)
|
||||||
|
{
|
||||||
|
var r = Resources.DisplayMetrics.Density * radius;
|
||||||
|
|
||||||
|
var radii = new float[8];
|
||||||
|
if ((mask & CornerMask.LeftTop) == CornerMask.LeftTop)
|
||||||
|
{
|
||||||
|
radii[0] = radii[1] = r;
|
||||||
|
}
|
||||||
|
if ((mask & CornerMask.RightTop) == CornerMask.RightTop)
|
||||||
|
{
|
||||||
|
radii[2] = radii[3] = r;
|
||||||
|
}
|
||||||
|
if ((mask & CornerMask.RightBottom) == CornerMask.RightBottom)
|
||||||
|
{
|
||||||
|
radii[4] = radii[5] = r;
|
||||||
|
}
|
||||||
|
if ((mask & CornerMask.LeftBottom) == CornerMask.LeftBottom)
|
||||||
|
{
|
||||||
|
radii[6] = radii[7] = r;
|
||||||
|
}
|
||||||
|
|
||||||
|
var path = new Path();
|
||||||
|
int width = Width;
|
||||||
|
int height = Height;
|
||||||
|
path.AddRoundRect(new RectF(0, 0, width, height), radii, Path.Direction.Cw);
|
||||||
|
canvas.ClipPath(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
base.OnDraw(canvas);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
70
Pixiview.Android/Renderers/RoundLabelRenderer.cs
Normal file
70
Pixiview.Android/Renderers/RoundLabelRenderer.cs
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
using Android.Content;
|
||||||
|
using Android.Graphics;
|
||||||
|
using Android.Graphics.Drawables;
|
||||||
|
using Pixiview.Droid.Renderers;
|
||||||
|
using Pixiview.UI;
|
||||||
|
using Xamarin.Forms;
|
||||||
|
using Xamarin.Forms.Platform.Android;
|
||||||
|
|
||||||
|
[assembly: ExportRenderer(typeof(RoundLabel), typeof(RoundLabelRenderer))]
|
||||||
|
namespace Pixiview.Droid.Renderers
|
||||||
|
{
|
||||||
|
public class RoundLabelRenderer : Xamarin.Forms.Platform.Android.FastRenderers.LabelRenderer
|
||||||
|
{
|
||||||
|
public RoundLabelRenderer(Context context) : base(context)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
|
||||||
|
{
|
||||||
|
base.OnElementChanged(e);
|
||||||
|
|
||||||
|
if (e.NewElement is RoundLabel label)
|
||||||
|
{
|
||||||
|
var density = Resources.DisplayMetrics.Density;
|
||||||
|
var drawable = new RoundCornerDrawable(label.CornerRadius * density);
|
||||||
|
drawable.SetColorFilter(label.BackgroundColor.ToAndroid(), PorterDuff.Mode.Src);
|
||||||
|
Control.SetBackground(drawable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class RoundCornerDrawable : Drawable
|
||||||
|
{
|
||||||
|
private readonly Paint paint;
|
||||||
|
private readonly float radius;
|
||||||
|
private RectF rect;
|
||||||
|
|
||||||
|
public override int Opacity => (int)Format.Translucent;
|
||||||
|
|
||||||
|
public RoundCornerDrawable(float radius)
|
||||||
|
{
|
||||||
|
paint = new Paint
|
||||||
|
{
|
||||||
|
AntiAlias = true
|
||||||
|
};
|
||||||
|
this.radius = radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetBounds(int left, int top, int right, int bottom)
|
||||||
|
{
|
||||||
|
base.SetBounds(left, top, right, bottom);
|
||||||
|
rect = new RectF(left, top, right, bottom);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Draw(Canvas canvas)
|
||||||
|
{
|
||||||
|
canvas.DrawRoundRect(rect, radius, radius, paint);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetAlpha(int alpha)
|
||||||
|
{
|
||||||
|
paint.Alpha = alpha;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetColorFilter(ColorFilter colorFilter)
|
||||||
|
{
|
||||||
|
paint.SetColorFilter(colorFilter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
30
Pixiview.Android/Renderers/SearchBarRenderer.cs
Normal file
30
Pixiview.Android/Renderers/SearchBarRenderer.cs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
using Android.Content;
|
||||||
|
using Android.Widget;
|
||||||
|
using Xamarin.Forms;
|
||||||
|
using Xamarin.Forms.Platform.Android;
|
||||||
|
|
||||||
|
[assembly: ExportRenderer(typeof(SearchBar), typeof(Pixiview.Droid.Renderers.SearchBarRenderer))]
|
||||||
|
namespace Pixiview.Droid.Renderers
|
||||||
|
{
|
||||||
|
public class SearchBarRenderer : Xamarin.Forms.Platform.Android.SearchBarRenderer
|
||||||
|
{
|
||||||
|
public SearchBarRenderer(Context context) : base(context)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnElementChanged(ElementChangedEventArgs<SearchBar> e)
|
||||||
|
{
|
||||||
|
base.OnElementChanged(e);
|
||||||
|
|
||||||
|
if (e.NewElement != null && Control is SearchView searchView)
|
||||||
|
{
|
||||||
|
searchView.Iconified = true;
|
||||||
|
searchView.SetIconifiedByDefault(false);
|
||||||
|
// (Resource.Id.search_mag_icon); is wrong / Xammie bug
|
||||||
|
int searchIconId = Context.Resources.GetIdentifier("android:id/search_mag_icon", null, null);
|
||||||
|
var icon = searchView.FindViewById(searchIconId);
|
||||||
|
(icon as ImageView).SetImageResource(Resource.Drawable.ic_search);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -160,15 +160,19 @@ namespace Pixiview.Droid.Renderers
|
|||||||
|
|
||||||
void ConfigureRadioButton(int i, RadioButton rb)
|
void ConfigureRadioButton(int i, RadioButton rb)
|
||||||
{
|
{
|
||||||
|
var textColor = Element.SelectedTextColor;
|
||||||
if (i == Element.SelectedSegmentIndex)
|
if (i == Element.SelectedSegmentIndex)
|
||||||
{
|
{
|
||||||
rb.SetTextColor(Element.SelectedTextColor.ToAndroid());
|
rb.SetTextColor(textColor.ToAndroid());
|
||||||
|
rb.Paint.FakeBoldText = true;
|
||||||
_rb = rb;
|
_rb = rb;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var textColor = Element.IsEnabled ? Element.TintColor.ToAndroid() : Element.DisabledColor.ToAndroid();
|
var tColor = Element.IsEnabled ?
|
||||||
rb.SetTextColor(textColor);
|
textColor.IsDefault ? Element.TintColor.ToAndroid() : textColor.MultiplyAlpha(.6).ToAndroid() :
|
||||||
|
Element.DisabledColor.ToAndroid();
|
||||||
|
rb.SetTextColor(tColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
GradientDrawable selectedShape;
|
GradientDrawable selectedShape;
|
||||||
@ -202,9 +206,17 @@ namespace Pixiview.Droid.Renderers
|
|||||||
|
|
||||||
var rb = (RadioButton)rg.GetChildAt(radioId);
|
var rb = (RadioButton)rg.GetChildAt(radioId);
|
||||||
|
|
||||||
var color = Element.IsEnabled ? Element.TintColor.ToAndroid() : Element.DisabledColor.ToAndroid();
|
var textColor = Element.SelectedTextColor;
|
||||||
_rb?.SetTextColor(color);
|
var color = Element.IsEnabled ?
|
||||||
|
textColor.IsDefault ? Element.TintColor.ToAndroid() : textColor.MultiplyAlpha(.6).ToAndroid() :
|
||||||
|
Element.DisabledColor.ToAndroid();
|
||||||
|
if (_rb != null)
|
||||||
|
{
|
||||||
|
_rb.SetTextColor(color);
|
||||||
|
_rb.Paint.FakeBoldText = false;
|
||||||
|
}
|
||||||
rb.SetTextColor(Element.SelectedTextColor.ToAndroid());
|
rb.SetTextColor(Element.SelectedTextColor.ToAndroid());
|
||||||
|
rb.Paint.FakeBoldText = true;
|
||||||
_rb = rb;
|
_rb = rb;
|
||||||
|
|
||||||
Element.SelectedSegmentIndex = radioId;
|
Element.SelectedSegmentIndex = radioId;
|
||||||
|
6
Pixiview.Android/Resources/drawable-night/ic_search.xml
Normal file
6
Pixiview.Android/Resources/drawable-night/ic_search.xml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<vector android:height="24dp" android:tint="#DDDDDD"
|
||||||
|
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="#FF000000" android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z"/>
|
||||||
|
</vector>
|
6
Pixiview.Android/Resources/drawable/ic_search.xml
Normal file
6
Pixiview.Android/Resources/drawable/ic_search.xml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<vector android:height="24dp" android:tint="#333333"
|
||||||
|
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="#FF000000" android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z"/>
|
||||||
|
</vector>
|
@ -10,7 +10,7 @@
|
|||||||
BackgroundColor="{DynamicResource NavColor}"
|
BackgroundColor="{DynamicResource NavColor}"
|
||||||
ForegroundColor="{DynamicResource TintColor}"
|
ForegroundColor="{DynamicResource TintColor}"
|
||||||
TitleColor="{DynamicResource TextColor}"
|
TitleColor="{DynamicResource TextColor}"
|
||||||
UnselectedColor="{DynamicResource SubTextColor}"
|
UnselectedColor="{DynamicResource TintColor}"
|
||||||
FlyoutBackgroundColor="{DynamicResource WindowColor}">
|
FlyoutBackgroundColor="{DynamicResource WindowColor}">
|
||||||
<Shell.FlyoutHeaderTemplate>
|
<Shell.FlyoutHeaderTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user