【发布时间】:2020-08-05 17:40:08
【问题描述】:
我有这个适用于 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;
}
}
我想在下面添加更多内容,但我不知道为什么它不调整此 pin 窗口的大小? 结果如下:
更新: 这是运行良好的 Android 渲染器。从我的 CUstomPinModel 中,我需要动态创建标签:
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 找到资源:
<?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 模型:
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 列表。
【问题讨论】:
-
您好,使用的是哪个版本的 Xamarin Forms?共享代码在我的本地站点中使用最新版本的 Xamarin Forms 工作。你可以看看这个官方样本是否有效。docs.microsoft.com/en-us/samples/xamarin/xamarin-forms-samples/…
-
@JuniorJiang-MSFT 我使用的是 XF 4.7.0 版本。我在 iOS 上尝试了这个示例,但我找不到可以动态添加新标签(如堆叠标签)的位置。例如,如果我有字符串列表,我想在弹出窗口中将每个项目显示为单独的标签。我在 Android 上成功了,但 iOS 就是不听我的
-
Okey,能分享一下Android的效果或代码吗?这将有助于正确理解效果。
-
@JuniorJiang-MSFT 你可以找到我更新的代码
-
哦,如果要动态添加子视图,从共享代码是不行的。因为每次都需要计算 Lable 的 frame。如果这样做会显示他们。但是,还有另一种方法可以实现,您可以使用 UIStackView 添加标签。稍后我将更新答案显示解决方案。
标签: ios xamarin xamarin.forms xamarin.ios