【问题标题】:Xamarin, Android and Google Maps: I can't move the map up and down (only left and right)Xamarin、Android 和谷歌地图:我不能上下移动地图(只能左右移动)
【发布时间】:2017-10-10 07:23:12
【问题描述】:

在一个页面中,我有一个 ScrollView 和一些标签,中间有一个 Google Maps。在 Android 中,当我尝试向上或向下移动地图时,除了地图之外的所有页面都会移动。要显示我正在使用的地图Xamarin.Forms.GoogleMaps。我创建了自己的custommap 来绘制路线。该组件运行良好,我可以在iOSAndroid 中看到地图并且可以移动地图。

我在 Stackoverflow 和 this post 上阅读了一些帖子,但这些人总是 Activity 并且项目是原生的。

我创造了:

TouchableMapFragment

public class TouchableMapFragment : MapFragment
{
  public event EventHandler TouchDown;
  public event EventHandler TouchUp;

  public override View OnCreateView(LayoutInflater inflater, 
                                    ViewGroup container, Bundle savedInstanceState)
  {
    var root = base.OnCreateView(inflater, container, savedInstanceState);
    var wrapper = new TouchableWrapper(Activity);
    wrapper.SetBackgroundColor(Resources.GetColor(Android.Resource.Color.Transparent));
    ((ViewGroup) root).AddView(wrapper,
      new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MatchParent, 
      ViewGroup.LayoutParams.MatchParent));

    wrapper.TouchUp = () =>
    {
      if (TouchUp != null)
        TouchUp(this, EventArgs.Empty);
    };
    wrapper.TouchDown = () =>
    {
      if (TouchDown != null)
        TouchDown(this, EventArgs.Empty);
    };

    return root;
  }

  class TouchableWrapper : FrameLayout
  {
    public Action TouchDown;
    public Action TouchUp;

    #region ctors
    protected TouchableWrapper(IntPtr javaReference, JniHandleOwnership transfer) 
      : base(javaReference, transfer) {}
    public TouchableWrapper(Context context) 
      : this(context, null) {}
    public TouchableWrapper(Context context, IAttributeSet attrs) 
      : this(context, attrs, 0) {}
    public TouchableWrapper(Context context, IAttributeSet attrs, int defStyle) 
      : base(context, attrs, defStyle) { }
    #endregion

    public override bool DispatchTouchEvent(MotionEvent e)
    {
      switch (e.Action)
      {
        case MotionEventActions.Down:
          if (TouchDown != null)
            TouchDown();
          break;
        case MotionEventActions.Cancel:
        case MotionEventActions.Up:
          if (TouchUp != null)
            TouchUp();
          break;
      }

      return base.DispatchTouchEvent(e);
    }
  }
}

view.xaml

<?xml version="1.0" encoding="utf-8"?>
<HorizontalScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/scroll">
    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="wrap_content"
        android:layout_height="match_parent">
        <fragment
            android:id="@+id/map"
            android:layout_width="600dp"
            android:layout_height="match_parent"
            android:name="my.awesome.namespace.TouchableMapFragment" />
    </LinearLayout>
</HorizontalScrollView>

Activity.cs

public class MyActivity : Activity
{
  private GoogleMap _map;
  private HorizontalScrollView _hsv;

  protected override void OnCreate(Bundle bundle)
  {
    base.OnCreate(bundle);
    SetContentView(Resource.Layout.rtc);

    _hsv = FindViewById<HorizontalScrollView>(Resource.Id.scroll);
    SetupMapIfNeeded();
  }

  private void SetupMapIfNeeded()
  {
    if (null != _map) return;

    var frag = FragmentManager.FindFragmentById<TouchableMapFragment>(Resource.Id.map);
    if (frag != null)
    {
      frag.TouchUp += (sender, args) => _hsv.RequestDisallowInterceptTouchEvent(false);
      frag.TouchDown += (sender, args) => _hsv.RequestDisallowInterceptTouchEvent(true);

      _map = frag.Map;
      if (_map == null) return; // will probably not happen

      // do stuff to _map here, such as adding overlays etc.
    }
  }
}

有几个错误:

  • 如何解决 Android 无法正确移动地图的问题?
  • SetContentView(Resource.Layout.rtc);什么是 rtc?
  • Resource.Id.map 不存在

就我而言,我有一个适用于 iOS 和 Android 项目的 PCL 解决方案。在 iOS 中一切都很好。唯一的问题是Android。我该如何解决这个问题?

有什么建议吗?谢谢。

【问题讨论】:

  • 很难分辨什么是“rtc”,但基本上Resource.Layout.xxxx xxxx“是布局文件的名称,即xxxx.xml和layout.xml里面的任何组件都可以有一个“id”属性,例如,如果我们有一个 那么按钮的 id 是“something”,我们可以通过调用 Button btn = (Button ) Resource.id.something;
  • 谢谢@GaneshCauda 我明白了。我的问题与我找到的代码有关。我无法理解如何在Xamarin.Forms中使用它
  • 查看您的代码,最好的可能是将“rtc”更改为“view”,反之亦然(“view.axml”更改为“rtc.axml”
  • 尝试用 rtc.axml 改变 view.axml
  • 试过了。没有改变。我的项目中没有Activity,因为所有内容都在PCL 项目中,带有ViewModelsViews。在这种情况下,MyActivity : Activity 是什么?

标签: android google-maps xamarin xamarin.forms


【解决方案1】:

我的问题与我找到的代码有关。我不明白如何在 Xamarin.Forms 中使用它

在XF框架中,我们只有一个Activity,意思是默认的MainAcitivty,所有视图都基于这个MainAcitivty显示,如果你想在PCL中显示来自客户端Android项目的自定义视图,通常我们使用Custom Renderer创建一个视图渲染器,你的view.axml是客户端Android项目中的布局资源,那么你应该在渲染器中实现这个视图的逻辑代码。

首先在 PCL 中创建一个View 的子类,这样它就可以像普通的 XF 控件一样使用:

public class ScrollViewWithMap:View
{
}

然后在 Android 客户端项目中将 view.axml 放在 Resources/layout 文件夹下,并一起创建它的渲染器:

[assembly: ExportRenderer(typeof(ScrollViewWithMap), typeof(ScrollViewWithMapRenderer))]

namespace YOURNAMESPACE.Droid
{
    public class ScrollViewWithMapRenderer : ViewRenderer
    {
        protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.View> e)
        {
            base.OnElementChanged(e);
            if (Control == null)
            {
                var context = Xamarin.Forms.Forms.Context;
                LayoutInflater minflater = context.GetSystemService(Context.LayoutInflaterService) as LayoutInflater;
                var view = minflater.Inflate(Resource.Layout.view, this, false);
                SetNativeControl(view);
            }
        }
    }
}

然后您可以将逻辑代码从您的MyActivity 移动到这个ScrollViewWithMapRenderer,例如:

public class ScrollViewWithMapRenderer : ViewRenderer
{
    private GoogleMap _map;
    private HorizontalScrollView _hsv;
    private Context context = Xamarin.Forms.Forms.Context;

    protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.View> e)
    {
        base.OnElementChanged(e);
        if (Control == null)
        {
            LayoutInflater minflater = context.GetSystemService(Context.LayoutInflaterService) as LayoutInflater;
            var view = minflater.Inflate(Resource.Layout.view, this, false);
            _hsv = view.FindViewById<HorizontalScrollView>(Resource.Id.scroll);
            SetNativeControl(view);

            SetupMapIfNeeded();
        }
    }

    private void SetupMapIfNeeded()
    {
        if (null != _map) return;
        var frag = ((Activity)context).FragmentManager.FindFragmentById<TouchableMapFragment>(Resource.Id.map);
        if (frag != null)
        {
            frag.TouchUp += (sender, args) => _hsv.RequestDisallowInterceptTouchEvent(false);
            frag.TouchDown += (sender, args) => _hsv.RequestDisallowInterceptTouchEvent(true);

            _map = frag.Map;
            if (_map == null) return; // will probably not happen

            // do stuff to _map here, such as adding overlays etc.
        }
    }
}

我在您的TouchableMapFragment 中找不到属性Map,我认为您的代码不完整,您应该能够解决此问题。顺便说一句,代码TouchableMapFragment也应该放在android客户端项目中。

最后我们可以在 PCL 中使用这个ScrollViewWithMap,例如:

<local:ScrollViewWithMap />

【讨论】:

  • _map = frag.Map; 不存在
【解决方案2】:
  1. 基本上Resource.Layout.xxxx xxxx"是布局文件的名称,即xxxx.xml
  2. layout.xml 中的任何组件都可以有一个“id”属性 例如,如果我们有一个

    <Button id="@+id/something"></Button>
    

    那么按钮的 id 是“something”,我们可以从后面的代码中得到这个视图 通过调用

    Button btn = (Button) v.findViewById(Resource.id.something);
    
  3. 基于您的代码的最佳解决方案,可能将 view.axml 更改为 rtc.axml

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-03-21
    • 2018-08-23
    • 2016-01-23
    • 1970-01-01
    • 1970-01-01
    • 2017-09-21
    • 1970-01-01
    相关资源
    最近更新 更多