0

I have implemented a clickable Frame in Xamarin.Forms 2.3.4 with a custom FrameRenderer that set Clickable (and LongPressable FWIW) to true, subscribed the respective events and set the FrameRenderers foreground

TypedValue typedValue = new TypedValue();
this.Context.Theme.ResolveAttribute(Android.Resource.Attribute.SelectableItemBackground, typedValue, true);
this.Foreground = this.Resources.GetDrawable(typedValue.ResourceId, this.Context.Theme);

to achieve Material motion (ripple touch).

After updating to XF 2.5 (most likely as of 2.3.5, since fast renderers have been introduced with that release) my touch events have ceased to work. My custom renderer is assigned correctly, so are the Clickable and LongPressable properties, but nothing happens. Partially I have been able to work around the issue - at least for the moment - by subscribing to FrameRenderer.Touch and call OnClick from that event handler. This renders the app usable, but unfortunately lacks the visual feedback in form of the ripple touch effect.

Is there any way I can restore the original behavior? Is there any way to implement a clickable frame with ripple touch in XF 2.5?

Paul Kertscher
  • 9,416
  • 5
  • 32
  • 57

1 Answers1

1

With the help of this answer I have figured out a solution. Here's a draft of it:

First of all I store a local reference to my RippleDrawable (see documentation)

private void SetMaterialMotion()
{
    TypedValue typedValue = new TypedValue();
    this.Context.Theme.ResolveAttribute(Android.Resource.Attribute.SelectableItemBackground, typedValue, true);
    this.Foreground = this.Resources.GetDrawable(typedValue.ResourceId, this.Context.Theme);
    this._layerDrawable = this.Foreground as RippleDrawable;
}

then I have to subscribe to the Touch event

private void SubscribeClickEvent()
{
    if (this.ClickableFrame.IsClickable)
    {
        this.Touch += ClickableFrameRenderer_Touch;
    }
}

In my ClickableFrameRenderer_Touch I set the Pressed property and the hotspot of the RippleDrawable

private void ClickableFrameRenderer_Touch(object sender, TouchEventArgs e)
{
    if(e.Event.Action == Android.Views.MotionEventActions.Down)
    {
        this.Pressed = true;
    }

    if(e.Event.Action == Android.Views.MotionEventActions.Up)
    {
        this._layerDrawable.SetHotspot(e.Event.GetX(), e.Event.GetY());
        this.Pressed = false;
    }
}

This will show the ripple touch motion (more or less) as expected. Of course this does not handle long presses, yet, but I'm on a way.

Anyway, this is not a solution I like very much. I still think that there has to be a supported way on making FastRenderers.FrameRenderer clickable. If anyone knows it: Please share your knowledge.

Paul Kertscher
  • 9,416
  • 5
  • 32
  • 57
  • Thank you, this worked for me. I found that setting the hotspot on the Down-event worked better. Did you find any simpler solution to this? – Thomas Sahlin Mar 11 '19 at 10:58