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

时间:2018-03-13 18:56:28

标签: c# xamarin.forms

我想获取列表视图中所选项目相对于屏幕的坐标(矩形边界:x,y,宽度和高度)(假设列表视图填满整个屏幕),这样我就可以创建一个对象该位置和动画显示我的Xamarin.Forms应用程序中所选项目的一些细节。

xaml中的

listview:

<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>
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 = ...

    ...
}

最终我想在带有listview的Xamarin.Forms中创建这样的东西(listview中的对象数量各不相同):

sample listview animation

3 个答案:

答案 0 :(得分:2)

我创建了一个依赖项,可以用来获取VisualElement在iOS和Android中的绝对位置。我将其用于类似目的。我们使用它来确定在列表视图中轻击时要显示的弹出窗口的位置。完美运行:

依赖性:

public interface ILocationFetcher
{
    System.Drawing.PointF GetCoordinates(global::Xamarin.Forms.VisualElement view);
}

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实现:

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);
    }
}

用法示例:

var locationFetcher = DependencyService.Get<ILocationFetcher>();
var location = locationFetcher.GetCoordinates(myVisualElement);

请确保使用依赖项属性在android和ios中正确正确注册依赖项(请参阅https://docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/dependency-service/)。否则,DependencyService.Get将返回null。

答案 1 :(得分:1)

一个简单的想法:

拥有一个以单身形式运行的视图助手服务:

interface IViewHelper
{
   Rect GetScreenCoordinates(View view);
}

在ListView项目模板中的AbsoluteLayout上以及tap事件处理程序调用中添加了一个点击手势:

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

服务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)

请参阅 https://forums.xamarin.com/discussion/86941/get-x-y-co-ordinates-in-tap-gesture-inside-listview

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

另见:https://michaelridland.com/xamarin/creating-native-view-xamarin-forms-viewpage/

我没有完整的代码,但我希望这可以帮到你。

我认为最后,在实现了动画并显示视图之后,你可以将实现重构为一个可以附加到任何视图的好行为,如果它在list-view里面也没关系,它会工作。

答案 2 :(得分:1)

PaulVrugt的答案非常适用于IOS和Android。为了将实施扩展到任何人,还需要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));
        }