简体   繁体   English

如何在 Xamarin.Forms 的列表视图中获取所选项目的坐标?

[英]How to get coordinates of the selected item in a list view in Xamarin.Forms?

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.我想获取列表视图中所选项目相对于屏幕的坐标(矩形边界:x、y、宽度和高度)(假设列表视图填满整个屏幕),以便我可以在该位置创建一个对象并为其设置动画以在我的 Xamarin.Forms 应用程序中显示所选项目的一些详细信息。

listview in xaml: 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: ItemTapped 事件的 c# 代码:

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):最终,我想在 Xamarin.Forms 中使用列表视图创建类似这样的内容(列表视图中的对象数量各不相同):

示例列表视图动画

I've created a dependency you can use to get the absolute position of a VisualElement in iOS and Android.我创建了一个依赖项,您可以使用它来获取 iOS 和 Android 中 VisualElement 的绝对位置。 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: iOS 实现:

 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:感谢@Emil,我们还有一个 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));
}

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.确保使用依赖属性在 android 和 ios 中正确注册依赖项(请参阅https://docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/dependency-service/ )。 Otherwise the DependencyService.Get will return null.否则 DependencyService.Get 将返回 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:在 ListView 项模板和点击事件处理程序调用中的 AbsoluteLayout 添加一个点击手势:

IViewHelper viewHelper = CrossViewHelper.Instance; 
Rect rcItem = viewHelper.GetScreenCoordinates((View)sender);

The native implementation of the service GetScreenCoordinates does two things:服务GetScreenCoordinates本机实现做了两件事:

// 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请参阅https://forums.xamarin.com/discussion/86941/get-xy-co-ordinates-in-tap-gesture-inside-listview

https://github.com/xamarin/Xamarin.Forms/blob/master/Xamarin.Forms.Platform.Android/PlatformRenderer.cs#L53 https://github.com/xamarin/Xamarin.Forms/blob/master/Xamarin.Forms.Platform.Android/PlatformRenderer.cs#L53

Also see: https://michaelridland.com/xamarin/creating-native-view-xamarin-forms-viewpage/另请参阅: 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. PaulVrugt 的回答完全适用于 IOS 和 Android。 Just to extend his implementation for anyone requires also UWP.只是为任何人扩展他的实现也需要 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));
        }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM