infowindow里面的按钮没有被点击 - Xamarin形式

时间:2017-08-22 07:20:04

标签: xamarin xamarin.forms

enter image description here

大家好,我必须在xamarin表单中创建自定义信息窗口,如上面的屏幕截图所示。我为此创建了一个自定义渲染器,但我现在遇到的问题是按钮没有被点击。 Xamarin将整个信息窗口视为可点击的视图。请指导我做错了什么,或者是否可以在Xamarin表单中实现按钮点击。提前谢谢。

以下是自定义渲染器的代码:

using System;
using System.Collections.Generic;
using Android.Content;
using Android.Gms.Maps;
using Android.Gms.Maps.Model;
using Xamarin.Forms;
using Xamarin.Forms.Maps;
using Xamarin.Forms.Maps.Android;
using SalesApp.Droid.CustomRenderer;
using Android.Widget;
using SalesApp.CustomControls;
using SalesApp.Droid.Listeners;

[assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer))]
namespace SalesApp.Droid.CustomRenderer
{
    public class CustomMapRenderer : MapRenderer, GoogleMap.IInfoWindowAdapter, IOnMapReadyCallback
    {
        GoogleMap map;
        List<CustomPin> customPins;
        bool isDrawn;

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

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

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

        public void OnMapReady(GoogleMap googleMap)
        {
            map = googleMap;
            map.InfoWindowClick += OnInfoWindowClick;
            map.SetInfoWindowAdapter(this);
        }

        protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            base.OnElementPropertyChanged(sender, e);
            if (e.PropertyName.Equals("VisibleRegion") && !isDrawn)
            {
                map.Clear();

                if (customPins != null)
                {
                    foreach (var pin in customPins)
                    {
                        var marker = new MarkerOptions();
                        marker.SetPosition(new LatLng(pin.Pin.Position.Latitude, pin.Pin.Position.Longitude));
                        marker.SetTitle(pin.Pin.Label);
                        marker.SetSnippet(pin.Pin.Address);
                        marker.SetIcon(BitmapDescriptorFactory.FromResource((int)typeof(Resource.Drawable).GetField(pin.Image).GetValue(null)));

                        map.AddMarker(marker);
                    }
                    isDrawn = true;
                }
            }
        }

        protected override void OnLayout(bool changed, int l, int t, int r, int b)
        {
            base.OnLayout(changed, l, t, r, b);

            if (changed)
            {
                isDrawn = false;
            }
        }

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

            //if (!string.IsNullOrWhiteSpace(customPin.Url))
            //{
            //    var url = Android.Net.Uri.Parse(customPin.Url);
            //    var intent = new Intent(Intent.ActionView, url);
            //    intent.AddFlags(ActivityFlags.NewTask);
            //    Android.App.Application.Context.StartActivity(intent);
            //}

            Android.App.Application.Context.StartActivity(new Intent(Android.App.Application.Context, typeof(DialogActivity)));

        }

        void IOnMapReadyCallback.OnMapReady(GoogleMap googleMap)
        {
            InvokeOnMapReadyBaseClassHack(googleMap);
            map = googleMap;
            map.SetInfoWindowAdapter(this);
            map.InfoWindowClick += OnInfoWindowClick;
        }

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

                if (customPin.Id == "Xamarin")
                {
                    view = inflater.Inflate(Resource.Layout.XamarinMapInfoWindow, null);
                }
                else
                {
                    view = inflater.Inflate(Resource.Layout.MapInfoWindow, null);
                }

                var infoTitle = view.FindViewById<TextView>(Resource.Id.InfoWindowTitle);
                var address = view.FindViewById<TextView>(Resource.Id.Address);
                var contactPerson = view.FindViewById<TextView>(Resource.Id.ContactPerson);
                var phone = view.FindViewById<TextView>(Resource.Id.Phone);
                var zip = view.FindViewById<TextView>(Resource.Id.Zip);
                var email = view.FindViewById<TextView>(Resource.Id.Email);
                var cvr = view.FindViewById<TextView>(Resource.Id.CVR);
                var turnover = view.FindViewById<TextView>(Resource.Id.Turnover);
                var noOfEmp = view.FindViewById<TextView>(Resource.Id.NoOfEmp);
                var leadStatus = view.FindViewById<TextView>(Resource.Id.LeadStatus);
                var category = view.FindViewById<TextView>(Resource.Id.Cat);

                if (infoTitle != null)
                {
                    infoTitle.Text = customPin.LeedsAndCustomersData.FullName;
                }
                if (address != null)
                {
                    address.Text = customPin.LeedsAndCustomersData.Address + " " + customPin.LeedsAndCustomersData.CityName;
                }
                if (contactPerson != null)
                {
                    contactPerson.Text = customPin.LeedsAndCustomersData.FirstName;
                }
                if (phone != null)
                {
                    phone.Text = customPin.LeedsAndCustomersData.Phone;
                }
                if (zip != null)
                {
                    zip.Text = customPin.LeedsAndCustomersData.ZipCode;
                }
                if (email != null)
                {
                    email.Text = customPin.LeedsAndCustomersData.Email;
                }
                if (cvr != null)
                {
                    cvr.Text = customPin.LeedsAndCustomersData.CVR;
                }
                if (turnover != null)
                {
                    turnover.Text = customPin.LeedsAndCustomersData.Turnover;
                }
                if (noOfEmp != null)
                {
                    noOfEmp.Text = customPin.LeedsAndCustomersData.NoOfEmployees.ToString();
                }
                if (leadStatus != null)
                {
                    leadStatus.Text = customPin.LeedsAndCustomersData.LeadStatus;
                }
                if (category != null)
                {
                    category.Text = customPin.LeedsAndCustomersData.BusinessType;
                }

                //add listeners
                OnTouchPhoneListener callButtonListener = new OnTouchPhoneListener();
                phone.SetOnTouchListener(callButtonListener);

                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.Pin.Position == position)
                {
                    return pin;
                }
            }
            return null;
        }

        void InvokeOnMapReadyBaseClassHack(GoogleMap googleMap)
        {
            System.Reflection.MethodInfo onMapReadyMethodInfo = null;

            Type baseType = typeof(MapRenderer);
            foreach (var currentMethod in baseType.GetMethods(System.Reflection.BindingFlags.NonPublic |
                                                             System.Reflection.BindingFlags.Instance |
                                                              System.Reflection.BindingFlags.DeclaredOnly))
            {
                if (currentMethod.IsFinal && currentMethod.IsPrivate)
                {
                    if (string.Equals(currentMethod.Name, "OnMapReady", StringComparison.Ordinal))
                    {
                        onMapReadyMethodInfo = currentMethod;
                        break;
                    }

                    if (currentMethod.Name.EndsWith(".OnMapReady", StringComparison.Ordinal))
                    {
                        onMapReadyMethodInfo = currentMethod;
                        break;
                    }
                }
            }

            if (onMapReadyMethodInfo != null)
            {
                onMapReadyMethodInfo.Invoke(this, new[] { googleMap });
            }
        }
    }
}

OnInfoWindowElemTouchListener:

using Android.OS;
using Android.Views;
using Android.Widget;
using System.Threading.Tasks;
using Android.Gms.Maps.Model;
using Android.Graphics.Drawables;
using Java.Lang;

namespace SalesApp.Droid.Listeners
{
    public abstract class OnInfoWindowElemTouchListener : Java.Lang.Object, View.IOnTouchListener
    {
        private View view;

        private Drawable bgDrawableNormal;
        private Drawable bgDrawablePressed;
        private Handler handler = new Handler();
        private Marker marker;
        private static bool endPressStatus = false;
        private bool pressed = false;


        //public OnInfoWindowElemTouchListener(View view, Drawable bgDrawableNormal, Drawable bgDrawablePressed)
        //{
        //  this.view = this.view;
        //  this.bgDrawableNormal = this.bgDrawableNormal;
        //  this.bgDrawablePressed = this.bgDrawablePressed;
        //}

        public OnInfoWindowElemTouchListener(View view)
        {
            this.view = this.view;
        }

        public OnInfoWindowElemTouchListener(Button button)
        {

        }
        public OnInfoWindowElemTouchListener()
        {

        }

        public void setMarker(Marker marker)
        {
            this.marker = this.marker;
        }

        /*public bool OnTouch(View v, MotionEvent e)
        {
            if (e.Action == MotionEventActions.Down)
            {
                // do stuff
                return true;
            }
            if (e.Action == MotionEventActions.Up)
            {
                // do other stuff
                return true;
            }

            return false;
        }*/


        public bool OnTouch(View vv, MotionEvent e)
        {
            if (0 <= e.GetX() && e.GetX() <= vv.Width && 0 <= e.GetY() && e.GetY() <= vv.Height)
            {
                switch (e.ActionMasked)
                {
                    case MotionEventActions.Down:
                        startPress();
                        break;

                    // We need to delay releasing of the view a little so it shows the
                    // pressed state on the screen
                    case MotionEventActions.Up:
                        //handler.PostDelayed(ConfirmClickRunnable, 150);
                        //Task.Factory.StartNew(() =>onClickConfirmed(view, marker));
                        Task.Factory.StartNew(() => onClickConfirmed());
                        Task.Delay(150);
                        break;

                    case MotionEventActions.Cancel:
                        endPress();
                        break;
                    default:
                        break;
                }
            }
            else
            {
                // If the touch goes outside of the view's area
                // (like when moving finger out of the pressed button)
                // just release the press
                endPress();
            }

            return false;
        }


        private void startPress()
        {
            if (!pressed)
            {
                pressed = true;
                //handler.RemoveCallbacks(ConfirmClickRunnable);

                if ((marker != null))
                {
                    marker.ShowInfoWindow();
                }

            }

        }

        public bool endPress()
        {
            if (pressed)
            {
                this.pressed = false;
                //handler.RemoveCallbacks(ConfirmClickRunnable);
                view.SetBackgroundColor(Android.Graphics.Color.Green);


                if ((marker != null))
                {
                    marker.ShowInfoWindow();
                }
                endPressStatus = true;
                return true;
            }
            else
            {
                endPressStatus = false;
                return false;
            }

        }

        //private Runnable confirmClickRunnable = new RunnableAnonymousInnerClassHelper(this);
        private Runnable ConfirmClickRunnable = new Java.Lang.Runnable(() =>
        {
            if (endPressStatus)
            {

                //onClickConfirmed(view, marker);
            }
        });




        /*private  class RunnableAnonymousInnerClassHelper : Java.Lang.Object, Java.Lang.IRunnable
        {
            private readonly Context outerInstance;     

            public RunnableAnonymousInnerClassHelper(Context outerInstance)
            {
                this.outerInstance = outerInstance;         
            }

            public void Run()
            {
                if (endPressStatus)
                {
                    onClickConfirmed();
                }
            }
        }*/


        //public abstract void onClickConfirmed(View v, Marker marker);
        public abstract void onClickConfirmed();

    }
}

OnTouchPhoneListener:

using Android.Widget;
using System;

namespace SalesApp.Droid.Listeners
{
    public class OnTouchPhoneListener : OnInfoWindowElemTouchListener
    //public class OnTouchPhoneListener 
    {
        Button button;
        public OnTouchPhoneListener(Button button)
        {

        }

        public OnTouchPhoneListener()
        {

        }
        public override void onClickConfirmed() { 
            Console.WriteLine("call Button Clicked");
        }
    }
}

1 个答案:

答案 0 :(得分:0)

为什么在自定义渲染器中实现了信息窗口?这使得类CustomMapRenderer做(至少)做两件事,违反了SRP并使代码更难理解。

相反,我只使用自定义渲染器作为地图。然后在Xamarin.Forms中,您可以使用Xamarin实现叠加.Forms意味着(例如,绝对或相对布局中的地图视图以及相同布局中的叠加但缩小的尺寸)。请参阅以下 -XAML

<ContentPage [...]>
  <AbsoluteLayout>
    <local:MapView x:Name="MapView" AbsoluteLayout.LayoutFlags="All" AbsoluteLayout.LayoutBounds="0,0,1,1" />
    <local:MapOverlay AbsoluteLayout.LayoutFlags="All" AbsoluteLayout.LayoutBounds=".5, .5, .5, .5" />
  </AbsoluteLayout>
</ContentPage>

然后,您可以引入PinInfoViewModel公开的视图模型MapView.SelectedPinInfo,并将其设置为MapOverlay.BindingContext

<local:MapOverlay AbsoluteLayout.LayoutFlags="All" AbsoluteLayout.LayoutBounds=".5, .5, .5, .5" BindingContext="{Binding Source={x:Reference MapView}, Path=SelectedPinInfo}" /> 

MapOverlay - 反过来 - 绑定到PinInfoViewModel的所有属性。我们要做的最后一件事是,如果没有选择引脚,则覆盖不可见。为此,我们公开MapView.IsPinSelected并将MapOverlay.IsVisible绑定到它

<local:MapOverlay AbsoluteLayout.LayoutFlags="All" AbsoluteLayout.LayoutBounds=".5, .5, .5, .5" BindingContext="{Binding Source={x:Reference MapView}, Path=SelectedPinInfo}" IsVisible="{Binding Source=MapView, Path=IsPinSelected}" /> 

虽然到目前为止我们还没有做任何事情来解决您的问题,但您现在可以更简单地实现覆盖方式,例如使用StackLayout。你可以绑定Button命令来做任何你想做的事。