I want to get the coordinates (rectangle bounds: x, y, width and height) of the selected item in the listview relative to the screen (assume the listview fills the whole screen), so that I can create an object at that location and animate it to display some details of the selected item in my Xamarin.Forms app.
listview in xaml:
<ListView ItemTapped="ItemTapped"
AbsoluteLayout.LayoutFlags="All"
AbsoluteLayout.LayoutBounds="0.5, 0.5, 1.0, 1.0">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell Height="50">
<AbsoluteLayout>
<Label Text="{Binding Info}"
AbsoluteLayout.LayoutFlags="All"
AbsoluteLayout.LayoutBounds="0.1, 0.5, 0.7, 0.5"/>
</AbsoluteLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
c# code for ItemTapped event:
void ItemTapped(object sender, EventArgs args)
{
var listView = (ListView)sender; // the listview
var selectedItem = args.Item; // the selected item
// need to get selected item coordinates for the animation
var selectedItemBounds = ...
...
}
Eventually I want to create somehting like this in Xamarin.Forms with a listview (the number of objects in the listview varies):
I've created a dependency you can use to get the absolute position of a VisualElement in iOS and Android. I use it for a similar purpose. We use it to determine the position of a popup to show when tapping in the listview. Works perfectly:
Dependency:
public interface ILocationFetcher
{
System.Drawing.PointF GetCoordinates(global::Xamarin.Forms.VisualElement view);
}
iOS Implementation:
class LocationFetcher : ILocationFetcher
{
public System.Drawing.PointF GetCoordinates(global::Xamarin.Forms.VisualElement element)
{
var renderer = Platform.GetRenderer(element);
var nativeView = renderer.NativeView;
var rect = nativeView.Superview.ConvertPointToView(nativeView.Frame.Location, null);
return new System.Drawing.PointF((int)Math.Round(rect.X), (int)Math.Round(rect.Y));
}
}
Android Implementation:
class LocationFetcher : ILocationFetcher
{
public System.Drawing.PointF GetCoordinates(global::Xamarin.Forms.VisualElement element)
{
var renderer = Platform.GetRenderer(element);
var nativeView = renderer.View;
var location = new int[2];
var density = nativeView.Context.Resources.DisplayMetrics.Density;
nativeView.GetLocationOnScreen(location);
return new System.Drawing.PointF(location[0] / density, location[1] / density);
}
}
Thanks to @Emil we also have an UWP implementation:
public System.Drawing.PointF GetCoordinates(global::Xamarin.Forms.VisualElement element)
{
var renderer = Xamarin.Forms.Platform.UWP.Platform.GetRenderer(element);
var nativeView = renderer.GetNativeElement();
var element_Visual_Relative = nativeView.TransformToVisual(Window.Current.Content);
Point point = element_Visual_Relative.TransformPoint(new Point(0, 0));
return new System.Drawing.PointF((int)Math.Round(point.X), (int)Math.Round(point.Y));
}
usage example:
var locationFetcher = DependencyService.Get<ILocationFetcher>();
var location = locationFetcher.GetCoordinates(myVisualElement);
Be sure to properly register the dependency correctly (see https://docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/dependency-service/ ) in the android and ios using the dependency attribute. Otherwise the DependencyService.Get will return null.
A quick idea:
Have a view helper service which runs as a singleton:
interface IViewHelper
{
Rect GetScreenCoordinates(View view);
}
Have a tap gesture added on the AbsoluteLayout you have in the ListView item template, and in the tap event handler call:
IViewHelper viewHelper = CrossViewHelper.Instance;
Rect rcItem = viewHelper.GetScreenCoordinates((View)sender);
The native implementation of the service GetScreenCoordinates
does two things:
// Get the native view from the Xamarin Forms view
var nativeView = Platform.GetRenderer(view);
// Call native functions to get screen coordinates
Android: nativeView.GetLocationOnScreen(coords)
iOS: Use nativeView.ConvertPoint(coords, null)
See https://forums.xamarin.com/discussion/86941/get-xy-co-ordinates-in-tap-gesture-inside-listview
Also see: https://michaelridland.com/xamarin/creating-native-view-xamarin-forms-viewpage/
I don't have a complete code, but I hope this can help you.
I think in the end, after you implement animating and showing the view, you can refactor the implementation into a nice Behavior you can attach to any view, it won't matter if it's inside list-view or not, it will just work.
PaulVrugt's answer perfectly works for IOS and Android. Just to extend his implementation for anyone requires also UWP.
public System.Drawing.PointF GetCoordinates(global::Xamarin.Forms.VisualElement element)
{
var renderer = Xamarin.Forms.Platform.UWP.Platform.GetRenderer(element);
var nativeView = renderer.GetNativeElement();
var element_Visual_Relative = nativeView.TransformToVisual(Window.Current.Content);
Point point = element_Visual_Relative.TransformPoint(new Point(0, 0));
return new System.Drawing.PointF((int)Math.Round(point.X), (int)Math.Round(point.Y));
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.