Skip to content

Instantly share code, notes, and snippets.

@TheAlphamerc
Created June 26, 2019 06:38
Show Gist options
  • Save TheAlphamerc/dced46d9ca1c0e6dbf8075f3ebf3a73d to your computer and use it in GitHub Desktop.
Save TheAlphamerc/dced46d9ca1c0e6dbf8075f3ebf3a73d to your computer and use it in GitHub Desktop.
Xamarin form android native card view
using System;
using System.ComponentModel;
using Xamarin.Forms;
namespace Sample.Controls
{
public class Card : View
{
public Card()
{
}
public static readonly BindableProperty ColorProperty =
BindableProperty.Create("Color", typeof(Color), typeof(Card), Color.Default);
public static readonly BindableProperty ElavationProperty =
BindableProperty.Create("Elevation", typeof(int), typeof(Card), 0);
public static readonly BindableProperty CornerRadiusProperty =
BindableProperty.Create("CornerRadius", typeof(int), typeof(Card), 0);
public Color Color
{
set { SetValue(ColorProperty, value); }
get { return (Color)GetValue(ColorProperty); }
}
public int Elevation
{
set { SetValue(ElavationProperty, value); }
get { return (int)GetValue(ElavationProperty); }
}
public int CornerRadius
{
set { SetValue(CornerRadiusProperty, value); }
get { return (int)GetValue(CornerRadiusProperty); }
}
public static readonly BindableProperty ContentViewProperty =
BindableProperty.CreateAttached("Content", typeof(ContentView), typeof(Card), new ContentView());
public static void Content(BindableObject bindable, View Content)
{
bindable.SetValue(ContentViewProperty, Content);
}
public static ContentView GetContent(BindableObject bindable)
{
return (ContentView)bindable.GetValue(ContentViewProperty);
}
internal event EventHandler<TappedEventArgs> Tapped;
internal event EventHandler<SwipedEventArgs> swipped;
public void OnSwiped(View sender, SwipeDirection y)
{
this.swipped?.Invoke(this, new SwipedEventArgs(sender, y));
}
public void OnTapped(double x, double y)
{
this.Tapped?.Invoke(this, new TappedEventArgs(x, y));
this.ValueChangedCommand?.Execute(x);
}
/// <inheritdoc />
/// <summary>
/// Used in <see cref="E:XF.Material.Forms.UI.Internals.MaterialBoxView.Tapped" /> as an event argument.
/// </summary>
internal class TappedEventArgs : EventArgs
{
internal double X { get; }
internal double Y { get; }
internal TappedEventArgs(double x, double y)
{
this.X = x;
this.Y = y;
}
}
public Command<double> ValueChangedCommand
{
get => (Command<double>)this.GetValue(ValueChangedCommandProperty);
set => this.SetValue(ValueChangedCommandProperty, value);
}
public static readonly BindableProperty ValueChangedCommandProperty = BindableProperty.Create(nameof(ValueChangedCommand), typeof(Command<double>), typeof(Card));
}
}
using Android.Content;
using Android.Views;
using Sample.Controls;
using Sample.Droid.Renderer;
using Sample.Droid.Renderer.Utils;
using System.ComponentModel;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
using static Android.Views.View;
[assembly: ExportRenderer(typeof(Card),
typeof(CardViewRenderer))]
namespace Sample.Droid.Renderer
{
public class CardViewRenderer : ViewRenderer<Card, Android.Support.V7.Widget.CardView>, IOnClickListener, IOnTouchListener
{
private double width, height;
private Card card;
public CardViewRenderer(Context context) : base(context)
{
}
public void OnClick(Android.Views.View v)
{
Control.Clickable = true;
}
public bool OnTouch(Android.Views.View v, MotionEvent e)
{
var percentageX = e.GetX() / v.Width;
var percentageY = e.GetY() / v.Height;
var elementX = percentageX * this.Element.Width;
var elementY = percentageY * this.Element.Height;
card.OnTapped(elementX, elementY);
return true;
}
protected override void OnElementChanged(ElementChangedEventArgs<Card> args)
{
base.OnElementChanged(args);
if (Control == null)
{
SetNativeControl(new EllipseDrawableView(Context));
}
if (args?.NewElement == null) return;
card = this.Element as Card;
this.ViewGroup.SetOnTouchListener(null);
this.ViewGroup.SetOnTouchListener(this);
if (args.NewElement != null)
{
SetColor();
SetSize();
}
}
protected override void OnElementPropertyChanged(object sender,
PropertyChangedEventArgs args)
{
base.OnElementPropertyChanged(sender, args);
if (args.PropertyName == VisualElement.WidthProperty.PropertyName)
{
width = Element.Width;
SetSize();
}
else if (args.PropertyName == VisualElement.HeightProperty.PropertyName)
{
height = Element.Height;
SetSize();
}
else if (args.PropertyName == Card.ColorProperty.PropertyName)
{
SetColor();
}
}
private void SetColor()
{
Control.SetBackgroundColor(Element.Color.ToAndroid());
}
private void SetSize()
{
Control.SetMinimumHeight((int)height);
Control.SetMinimumWidth((int)width);
Control.CardElevation = Element.Elevation;
Control.Radius = Element.CornerRadius;
// Control.AddChildrenForAccessibility(Element.get());
// Control.SetBackgroundResource(Context.Resources.c);
}
}
}
using Android.Content;
using Android.Views;
using Android.Graphics.Drawables;
using Android.Graphics.Drawables.Shapes;
using Android.Graphics;
namespace Sample.Droid.Renderer.Utils
{
public class EllipseDrawableView : Android.Support.V7.Widget.CardView
{
ShapeDrawable drawable;
public EllipseDrawableView(Context context) : base(context)
{
drawable = new ShapeDrawable(new RectShape());
}
protected override void OnDraw(Canvas canvas)
{
base.OnDraw(canvas);
drawable.Draw(canvas);
}
public void SetColor(Xamarin.Forms.Color color)
{
drawable.Paint.SetARGB((int)(255 * color.A),
(int)(255 * color.R),
(int)(255 * color.G),
(int)(255 * color.B));
Invalidate();
}
public void SetSize(double width, double height)
{
float pixelsPerDip = Resources.DisplayMetrics.Density;
drawable.SetBounds(0, 0, (int)(width * pixelsPerDip),
(int)(height * pixelsPerDip));
Invalidate();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment