如何在 xamarin 表单映射中扩展 customPinWinod [英] how to expand customPinWinod in xamarin forms maps

查看:32
本文介绍了如何在 xamarin 表单映射中扩展 customPinWinod的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有这个用于 iOS 的自定义渲染器和我使用的 xamarin 表单映射:

I have this custom renderer for iOS and Im uisng xamarin forms maps:

public class CustomMapRenderer : MapRenderer
{
UIView customPinView;
ObservableCollection<CustomPin> customPins;

protected override void OnElementChanged(ElementChangedEventArgs<View> e)
{
    base.OnElementChanged(e);

    if (e.OldElement != null)
    {
        var nativeMap = Control as MKMapView;
        nativeMap.GetViewForAnnotation = null;
        nativeMap.CalloutAccessoryControlTapped -= OnCalloutAccessoryControlTapped;
        nativeMap.DidSelectAnnotationView -= OnDidSelectAnnotationView;
        nativeMap.DidDeselectAnnotationView -= OnDidDeselectAnnotationView;
    }

    if (e.NewElement != null)
    {
        var formsMap = (CustomMap)e.NewElement;
        var nativeMap = Control as MKMapView;
        customPins = formsMap.CustomPins;

        nativeMap.GetViewForAnnotation = GetViewForAnnotation;
        nativeMap.CalloutAccessoryControlTapped += OnCalloutAccessoryControlTapped;
        nativeMap.DidSelectAnnotationView += OnDidSelectAnnotationView;
        nativeMap.DidDeselectAnnotationView += OnDidDeselectAnnotationView;
    }
}

protected override MKAnnotationView GetViewForAnnotation(MKMapView mapView, IMKAnnotation annotation)
{
    MKAnnotationView annotationView = null;

    if (annotation is MKUserLocation)
        return null;

    var customPin = GetCustomPin(annotation as MKPointAnnotation);
    if (customPin == null)
    {
        throw new Exception("Custom pin not found");
    }

    annotationView = mapView.DequeueReusableAnnotation(customPin.Label);
    if (annotationView == null)
    {
        annotationView = new CustomMKAnnotationView(annotation, customPin.Label);
        annotationView.Image = UIImage.FromFile("pin.png");
        annotationView.CalloutOffset = new CGPoint(0, 0);
        annotationView.LeftCalloutAccessoryView = new UIImageView(UIImage.FromFile("monkey.png"));
        annotationView.RightCalloutAccessoryView = UIButton.FromType(UIButtonType.DetailDisclosure);
        ((CustomMKAnnotationView)annotationView).Name = customPin.Label;

    }
    annotationView.CanShowCallout = true;

    return annotationView;
}

void OnCalloutAccessoryControlTapped(object sender, MKMapViewAccessoryTappedEventArgs e)
{
    CustomMKAnnotationView customView = e.View as CustomMKAnnotationView;
    if (!string.IsNullOrWhiteSpace(customView.Url))
    {
        UIApplication.SharedApplication.OpenUrl(new Foundation.NSUrl(customView.Url));
    }
}

void OnDidSelectAnnotationView(object sender, MKAnnotationViewEventArgs e)
{
    CustomMKAnnotationView customView = e.View as CustomMKAnnotationView;
    customPinView = new UIView();

    var label = new UILabel();
    label.Text = "Tutorial";
    label.Font.WithSize(36);
    customPinView.AddSubview(label);

    customPinView.Frame = new CGRect(0, 0, 200, 84);
    var image = new UIImageView(new CGRect(0, 0, 200, 84));
    image.Image = UIImage.FromFile("xamarin.png");
    customPinView.AddSubview(image);
    customPinView.Center = new CGPoint(0, -(e.View.Frame.Height + 75));
    e.View.AddSubview(customPinView);
}

void OnDidDeselectAnnotationView(object sender, MKAnnotationViewEventArgs e)
{
    if (!e.View.Selected)
    {
        customPinView.RemoveFromSuperview();
        customPinView.Dispose();
        customPinView = null;
    }
}

CustomPin GetCustomPin(MKPointAnnotation annotation)
{
    var position = new Position(annotation.Coordinate.Latitude, annotation.Coordinate.Longitude);
    foreach (var pin in customPins)
    {
        if (pin.Position == position)
        {
            return pin;
        }
    }
    return null;
}
}

而且我想在下面添加更多内容,但我不知道为什么它不调整此 pin 窗口的大小?结果如下:

And I want to add some more things below, and I dont know why it doesnt resize this pin window? Here is the outcome:

更新:这是运行良好的Android渲染器.从我的 CUstomPinModel,我需要动态创建标签:

UPDATE: Here is Android renderer which works fine. From my CUstomPinModel, I need dynamically create labels:

public class CustomMapRenderer : MapRenderer, GoogleMap.IInfoWindowAdapter
{
    private LatLngBounds.Builder _builder;
    private GoogleMap _map;
    ObservableCollection<CustomPin> customPins { get; set; }
    Context context;
    public CustomMapRenderer(Context context) : base(context)
    {
        this.context = context;
        customPins = new ObservableCollection<CustomPin>();
        _builder = new LatLngBounds.Builder();
    }


    protected override void OnElementChanged(Xamarin.Forms.Platform.Android.ElementChangedEventArgs<Map> e)
    {
        base.OnElementChanged(e);

        if (e.OldElement != null)
        {
            NativeMap.InfoWindowClick -= OnInfoWindowClick;
        }

        if (e.NewElement != null)
        {
            var formsMap = (CustomMap)e.NewElement;
            customPins = formsMap.CustomPins;
        }
    }

    protected override void OnMapReady(GoogleMap map)
    {
        base.OnMapReady(map);

        NativeMap.InfoWindowClick += OnInfoWindowClick;
        NativeMap.SetInfoWindowAdapter(this);
        if (_map == null)
        {
            _map = map;
        }
    }

    protected override MarkerOptions CreateMarker(Pin pin)
    {
        CustomPin customPin = (CustomPin)pin;
        var marker = new MarkerOptions();
        LatLng position = new LatLng(pin.Position.Latitude, pin.Position.Longitude);
        marker.SetPosition(new LatLng(pin.Position.Latitude, pin.Position.Longitude));
        marker.SetTitle(pin.Label);
        marker.SetSnippet(pin.Address);
        marker.SetIcon(BitmapDescriptorFactory.FromResource(Resource.Drawable.pin));

        _builder.Include(position);
        LatLngBounds bounds = _builder.Build();

        CameraUpdate cu = CameraUpdateFactory.NewLatLngBounds(bounds, 20);

        _map.MoveCamera(cu);

        return marker;
    }

    void OnInfoWindowClick(object sender, GoogleMap.InfoWindowClickEventArgs e)
    {
        var customPin = GetCustomPin(e.Marker);
        if (customPin == null)
        {
            throw new Exception("Custom pin not found");
        }
    }

    public Android.Views.View GetInfoContents(Marker marker)
    {
        var inflater = Android.App.Application.Context.GetSystemService(Context.LayoutInflaterService) as Android.Views.LayoutInflater;
        if (inflater != null)
        {
            Android.Views.View view;


            var customPin = GetCustomPin(marker);
            if (customPin == null)
            {
                throw new Exception("Custom pin not found");
            }
                
            view = inflater.Inflate(Resource.Layout.MapInfoWindow, null);
            LinearLayout linearLayout = (LinearLayout)view.FindViewById(Resource.Id.InfoWindowProps);

            if(customPin != null && customPin.InfoBox != null && customPin.InfoBox.DetailsObjectInfos.Count > 0)
            {
                for (int i = 0; i < customPin.InfoBox.DetailsObjectInfos.Count; i++)
                {
                    TextView t1 = new TextView(context);
                    t1.Text = customPin.InfoBox.DetailsObjectInfos[i].BoldLabelTitle + customPin.InfoBox.DetailsObjectInfos[i].LabelValue;
                    linearLayout.AddView(t1);
                }
            }

            return view;
        }
        return null;
    }

    public Android.Views.View GetInfoWindow(Marker marker)
    {
        return null;
    }

    CustomPin GetCustomPin(Marker annotation)
    {
        var position = new Position(annotation.Position.Latitude, annotation.Position.Longitude);
        foreach (var pin in customPins)
        {
            if (pin.Position == position)
            {
                return pin;
            }
        }
        return null;
    }
}

此外,我在布局中设置了正确的命名,以便能够通过 id 找到资源:

Also, I set in my layout correct naming in order to be able to find resource by id:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="horizontal">
    <ImageView
        android:id="@+id/InfoWindowImage"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:adjustViewBounds="true"
        android:src="@drawable/monkey" />
    <LinearLayout
        android:id="@+id/InfoWindowProps"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_margin="10dp"
        android:layout_marginRight="261.5dp" >

    </LinearLayout>
</LinearLayout>

更新 #2:我的 CustomPin 模型:

UPDATE #2: My model for CustomPin:

public class CustomPin : Pin, INotifyPropertyChanged
{
    public string PinIcon { get; set; }
    public Color Color { get; set; }
    public InfoBoxMapModel InfoBox { get; set; } = new InfoBoxMapModel();
    public int? Id { get; set; }
    public int? ClassId { get; set; }
    public string FavoriteLabel { get; set; }

    public bool? _isFavorite { get; set; }

    public bool? IsFavorite
    {
        get { return _isFavorite; }
        set { _isFavorite = value; OnPropertyChanged(); }
    }

}

和包含我的字符串标签的 InfoBoxModel:

and InfoBoxModel which is containing my string labels:

    public class InfoBoxMapModel
    {
        //base64
        public string ImageString { get; set; }
        public ImageSource PinImageSource { get; set; }
        public List<DetailsObjectInfo> DetailsObjectInfos { get; set; } = new List<DetailsObjectInfo>();
        public int CountDetailsItemsRows { get; set; }
    }

    public class DetailsObjectInfo
    {
        public string BoldLabelTitle { get; set; }
        public string LabelValue { get; set; }
    }

更新 #3: 以下是它在 android 中的工作方式示例:所有这些字符串行都是 DetailsObjectInfo => 的串联.BoldLabelTitle + ": "+ 标签值

UPDATE #3: Here is the example how it works in android: All these rows of strings are concatenation of DetailsObjectInfo => BoldLabelTitle + ": " + LabelValue

所以,我想在白色标注图钉云中呈现 DetailsObjectyInfos 列表.

So, I want to render DetailsObjectyInfos List in white callout pin cloud.

推荐答案

如果需要动态添加子视图,一种方法,你需要计算每个子视图的Frame控件(Label).如下:

If need to add subviews dynamically , the one way that you need to calculate the Frame of each Control (Label).Such as follow:

for (int i = 0; i < 3; i++)
{
    var label = new UILabel();
    label.Frame = new CGRect(50*i, 0, 45, 84);
    label.Text = "Tutorial:"+i;
    label.Font.WithSize(36);
    customPinView.AddSubview(label);
}

另一种方式是使用 UIStackView 作为 RootView 如下:

The another way is using UIStackView as RootView as follow:

void OnDidSelectAnnotationView(object sender, MKAnnotationViewEventArgs e)
{
    CustomMKAnnotationView customView = e.View as CustomMKAnnotationView;
    //customPinView = new UIView();
    UIStackView customPinView = new UIStackView();


    if (customView.Name.Equals("Xamarin"))
    {

        //var label = new UILabel(new CGRect(-50, 0, 50, 84));
            

        for (int i = 0; i < 3; i++)
        {
            var label = new UILabel();
            label.Text = "Tutorial:"+i;
            label.Font.WithSize(36);
            customPinView.AddArrangedSubview(label);
        }

        customPinView.Frame = new CGRect(0, 0, 300, 84);
        customPinView.Axis = UILayoutConstraintAxis.Horizontal;
        customPinView.Distribution = UIStackViewDistribution.EqualSpacing;
        customPinView.Spacing = 10;
        customPinView.Alignment = UIStackViewAlignment.Fill;
        customPinView.Center = new CGPoint(0, -(e.View.Frame.Height + 75));
        //customPinView.BackgroundColor = UIColor.Yellow;
        e.View.AddSubview(customPinView);
    }
}

效果:

==============================更新#1================================

=============================Update #1===============================

MainPage声明PinLable文本:

public partial class MapPage : ContentPage
{
    public MapPage()
    {
        InitializeComponent();

        CustomPin pin = new CustomPin
        {
            Type = PinType.Place,
            Position = new Position(37.79752, -122.40183),
            Label = "Xamarin San Francisco Office",
            Address = "394 Pacific Ave, San Francisco CA",
            Name = "Xamarin",
            Url = "http://xamarin.com/about/"
        };
        customMap.CustomPins = new List<CustomPin> { pin };
        customMap.Pins.Add(pin);
        customMap.MoveToRegion(MapSpan.FromCenterAndRadius(new Position(37.79752, -122.40183), Distance.FromMiles(1.0)));
    }
}

==============================更新#2#3================================

=============================Update #2#3===============================

你的想法是对的.我找到了用我的自定义 Labels 替换 地址字符串 的解决方案.

Your idea is right . I have found the solution that replace the adress string wtih my custom Labels .

有一个 MKAnnotationViewDetailCalloutAccessoryView ,如果我们可以为它使用custome View,它就会显示想要的.

There is a DetailCalloutAccessoryView of MKAnnotationView , if we can use custome View for it , it will show the wants.

GetViewForAnnotation方法中修改:

protected override MKAnnotationView GetViewForAnnotation(MKMapView mapView, IMKAnnotation annotation)
{
    MKAnnotationView annotationView = null;

    if (annotation is MKUserLocation)
        return null;

    var customPin = GetCustomPin(annotation as MKPointAnnotation);
    if (customPin == null)
    {
        throw new Exception("Custom pin not found");
    }

    annotationView = mapView.DequeueReusableAnnotation(customPin.Name);
    if (annotationView == null)
    {
        annotationView = new CustomMKAnnotationView(annotation, customPin.Name);
        annotationView.Image = UIImage.FromFile("pin.png");
        annotationView.CalloutOffset = new CGPoint(0, 0);
        //annotationView.LeftCalloutAccessoryView = new UIImageView(UIImage.FromFile("monkey.png"));
        UIImageView uIImageView = new UIImageView(UIImage.FromFile("monkey.png"));
        uIImageView.Frame = new CGRect(0, 0, 75, 100);
        annotationView.LeftCalloutAccessoryView = uIImageView;
        annotationView.RightCalloutAccessoryView = UIButton.FromType(UIButtonType.DetailDisclosure);
        ((CustomMKAnnotationView)annotationView).Name = customPin.Name;
        ((CustomMKAnnotationView)annotationView).Url = customPin.Url;

        customPinView = new UIStackView();
        for (int i = 0; i < 3; i++)
        {
            var label = new UILabel();
            label.Text = "Tutorial: " + i;
            label.BackgroundColor = UIColor.White;
            label.Font.WithSize(36);
            customPinView.AddArrangedSubview(label);
        }
        customPinView.Frame = new CGRect(0, 0, 300, 84);
        customPinView.Axis = UILayoutConstraintAxis.Vertical;
        customPinView.Distribution = UIStackViewDistribution.EqualSpacing;
        customPinView.Spacing = 1;
        customPinView.Alignment = UIStackViewAlignment.Fill;
        annotationView.DetailCalloutAccessoryView = customPinView;

    }
    annotationView.CanShowCallout = true;

    return annotationView;
}

这是完整的渲染器代码:

This is the full renderer code :

public class CustomMapRenderer : MapRenderer
{
    UIStackView customPinView;
    List<CustomPin> customPins;

    protected override void OnElementChanged(ElementChangedEventArgs<View> e)
    {
        base.OnElementChanged(e);

        if (e.OldElement != null)
        {
            var nativeMap = Control as MKMapView;
            nativeMap.GetViewForAnnotation = null;
            nativeMap.CalloutAccessoryControlTapped -= OnCalloutAccessoryControlTapped;
            nativeMap.DidSelectAnnotationView -= OnDidSelectAnnotationView;
            nativeMap.DidDeselectAnnotationView -= OnDidDeselectAnnotationView;
        }

        if (e.NewElement != null)
        {
            var formsMap = (CustomMap)e.NewElement;
            var nativeMap = Control as MKMapView;
            customPins = formsMap.CustomPins;

            nativeMap.GetViewForAnnotation = GetViewForAnnotation;
            nativeMap.CalloutAccessoryControlTapped += OnCalloutAccessoryControlTapped;
            nativeMap.DidSelectAnnotationView += OnDidSelectAnnotationView;
            nativeMap.DidDeselectAnnotationView += OnDidDeselectAnnotationView;
        }
    }

    protected override MKAnnotationView GetViewForAnnotation(MKMapView mapView, IMKAnnotation annotation)
    {
        MKAnnotationView annotationView = null;

        if (annotation is MKUserLocation)
            return null;

        var customPin = GetCustomPin(annotation as MKPointAnnotation);
        if (customPin == null)
        {
            throw new Exception("Custom pin not found");
        }

        annotationView = mapView.DequeueReusableAnnotation(customPin.Name);
        if (annotationView == null)
        {
            annotationView = new CustomMKAnnotationView(annotation, customPin.Name);
            annotationView.Image = UIImage.FromFile("pin.png");
            annotationView.CalloutOffset = new CGPoint(0, 0);
            //annotationView.LeftCalloutAccessoryView = new UIImageView(UIImage.FromFile("monkey.png"));
            UIImageView uIImageView = new UIImageView(UIImage.FromFile("monkey.png"));
            uIImageView.Frame = new CGRect(0, 0, 75, 100);
            annotationView.LeftCalloutAccessoryView = uIImageView;
            annotationView.RightCalloutAccessoryView = UIButton.FromType(UIButtonType.DetailDisclosure);
            ((CustomMKAnnotationView)annotationView).Name = customPin.Name;
            ((CustomMKAnnotationView)annotationView).Url = customPin.Url;

            customPinView = new UIStackView();
            for (int i = 0; i < 3; i++)
            {
                var label = new UILabel();
                label.Text = "Tutorial: " + i;
                label.BackgroundColor = UIColor.White;
                label.Font.WithSize(36);
                customPinView.AddArrangedSubview(label);
            }
            customPinView.Frame = new CGRect(0, 0, 300, 84);
            customPinView.Axis = UILayoutConstraintAxis.Vertical;
            customPinView.Distribution = UIStackViewDistribution.EqualSpacing;
            customPinView.Spacing = 1;
            customPinView.Alignment = UIStackViewAlignment.Fill;
            annotationView.DetailCalloutAccessoryView = customPinView;

        }
        annotationView.CanShowCallout = true;

        return annotationView;
    }

    void OnCalloutAccessoryControlTapped(object sender, MKMapViewAccessoryTappedEventArgs e)
    {
        CustomMKAnnotationView customView = e.View as CustomMKAnnotationView;
        if (!string.IsNullOrWhiteSpace(customView.Url))
        {
            UIApplication.SharedApplication.OpenUrl(new Foundation.NSUrl(customView.Url));
        }
    }

    void OnDidSelectAnnotationView(object sender, MKAnnotationViewEventArgs e)
    {
        CustomMKAnnotationView customView = e.View as CustomMKAnnotationView;
        //customPinView = new UIView();


        if (customView.Name.Equals("Xamarin"))
        {                

            //customPinView.Frame = new CGRect(0, 0, 200, 84);
            //var image = new UIImageView(new CGRect(0, 0, 200, 84));
            //image.Image = UIImage.FromFile("xamarin.png");
            //customPinView.AddSubview(image);
            //customPinView.Center = new CGPoint(0, -(e.View.Frame.Height + 75));
            //e.View.AddSubview(customPinView);
        }
    }

    void OnDidDeselectAnnotationView(object sender, MKAnnotationViewEventArgs e)
    {
        if (!e.View.Selected)
        {
            customPinView.RemoveFromSuperview();
            customPinView.Dispose();
            customPinView = null;
        }
    }

    CustomPin GetCustomPin(MKPointAnnotation annotation)
    {
        var position = new Position(annotation.Coordinate.Latitude, annotation.Coordinate.Longitude);
        foreach (var pin in customPins)
        {
            if (pin.Position == position)
            {
                return pin;
            }
        }
        return null;
    }
}

效果:

这篇关于如何在 xamarin 表单映射中扩展 customPinWinod的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆