как расширить customPinWinod в картах форм xamarin - PullRequest
0 голосов
/ 03 августа 2020

У меня есть это настраиваемое средство визуализации для iOS, и я использую карты форм xamarin:

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

И я хочу добавить еще кое-что ниже, и я не знаю, почему он не изменяет размер этого окна вывода? Вот результат: enter image description here

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 customPins { get; set; }
    Context context;
    public CustomMapRenderer(Context context) : base(context)
    {
        this.context = context;
        customPins = new ObservableCollection();
        _builder = new LatLngBounds.Builder();
    }


    protected override void OnElementChanged(Xamarin.Forms.Platform.Android.ElementChangedEventArgs
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; } }

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"?>
   

ОБНОВЛЕНИЕ # 2: Моя модель для 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, которая содержит мои строковые метки:

    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 + ": " + LabelValue

Итак, я хочу отобразить список DetailsObjectyInfos в белом облаке контактов выноски.

1 Ответ

1 голос
/ 04 августа 2020

Если необходимо динамически добавлять подпредставления, односторонний , который вам нужен для вычисления Frame каждого Control (Label). Например:

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, как показано ниже :

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

Эффект:

enter image description here

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

MainPage declare the Lable text of Pin:

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 { pin };
        customMap.Pins.Add(pin);
        customMap.MoveToRegion(MapSpan.FromCenterAndRadius(new Position(37.79752, -122.40183), Distance.FromMiles(1.0)));
    }
}

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

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

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

Modify it inside the GetViewForAnnotation method :

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 customPins;

    protected override void OnElementChanged(ElementChangedEventArgs 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;
    }
}

The effect:

введите описание изображения здесь

...