2017-08-22 57 views
0

enter image description here按鈕不會獲​​得任何點擊 - Xamarin形成

大家好,我不得不創建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"); 
     } 
    } 
} 
+0

這將是非常有益的,如果您改爲創建[mcve],您可以重現該問題。 –

+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的命令來做任何你想做的事情。

+0

真的很感謝你的解決方案,一定會試一次,我會用自定義渲染器完成:) –