1

我正在尝试在 Mono for Android 中的自定义叠加项目上使用弹出气球。我找到了这个项目https://github.com/jgilfelt/android-mapviewballoons,但是它是用 Java 编写的。我已经开始手动将其转换为 C#,但这有点超出我的想象。我读过您可以将 java 文件导入 Mono,但我不确定此时哪个路径更容易。如果有人有我在 C# 中链接到的投影,那就更好了。谢谢你的帮助!

4

1 回答 1

3

我冒昧地用 c# 为你重写了第一个类,如果你只是清理从 java 到 c# 的差异,这相当容易。

希望您可以以此为基础,根据需要将其他类转换为 c#。

您需要确保使用作者在其 github 示例中使用的布局文件、可绘制对象和选择器。将它们包含在您的项目中并根据需要进行调整。

using System;
using Android.Content;
using Android.GoogleMaps;
using Android.Util;
using Android.Views;
using Android.Widget;

namespace MapViewBalloons
{
    /**
     * A view representing a MapView marker information balloon.
     * 
     * @author Jeff Gilfelt
     *
     */
    public class BalloonOverlayView : FrameLayout
    {
        private LinearLayout _layout;
        private TextView _title;
        private TextView _snippet;

        /**
         * Create a new BalloonOverlayView.
         * 
         * @param context - The activity context.
         * @param balloonBottomOffset - The bottom padding (in pixels) to be applied
         * when rendering this view.
         */
        public BalloonOverlayView(Context context, int balloonBottomOffset)
            : base(context)
        {
            SetPadding(10, 0, 10, balloonBottomOffset);

            _layout = new LimitLinearLayout(context);
            _layout.Visibility = ViewStates.Visible;

            SetupView(context, _layout);

            FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(
                    LayoutParams.WrapContent, LayoutParams.WrapContent);
            layoutParams.Gravity = GravityFlags.NoGravity;

            AddView(_layout, layoutParams);
        }

        /**
         * Inflate and initialize the BalloonOverlayView UI. Override this method
         * to provide a custom view/layout for the balloon. 
         * 
         * @param context - The activity context.
         * @param parent - The root layout into which you must inflate your view.
         */
        protected void SetupView(Context context, ViewGroup parent)
        {

            LayoutInflater inflater = (LayoutInflater)context.GetSystemService(Context.LayoutInflaterService);
            View v = inflater.Inflate(Resource.Layout.balloon_overlay, parent);
            _title = (TextView)v.FindViewById(Resource.Id.balloon_item_title);
            _snippet = (TextView)v.FindViewById(Resource.Id.balloon_item_snippet);

        }

        /**
         * Sets the view data from a given overlay item.
         * 
         * @param item - The overlay item containing the relevant view data. 
         */
        public void setData(OverlayItem item)
        {
            _layout.Visibility = ViewStates.Visible;
            SetBalloonData(item, _layout);
        }

        /**
         * Sets the view data from a given overlay item. Override this method to create
         * your own data/view mappings.
         * 
         * @param item - The overlay item containing the relevant view data.
         * @param parent - The parent layout for this BalloonOverlayView.
         */
        protected void SetBalloonData(OverlayItem item, ViewGroup parent)
        {
            if (!string.IsNullOrEmpty(item.Title))
            {
                _title.Visibility = ViewStates.Visible;
                _title.Text = item.Title;
            }
            else
            {
                _title.Text = "";
                _title.Visibility = ViewStates.Gone;
            }
            if (!string.IsNullOrEmpty(item.Snippet))
            {
                _snippet.Visibility = ViewStates.Visible;
                _snippet.Text = item.Snippet;
            }
            else
            {
                _snippet.Text = "";
                _snippet.Visibility = ViewStates.Gone;
            }
        }

        private class LimitLinearLayout : LinearLayout
        {

            private static int MAX_WIDTH_DP = 280;
            private readonly float SCALE;

            public LimitLinearLayout(Context context)
                : base(context)
            {
                SCALE = context.Resources.DisplayMetrics.Density;
            }

            public LimitLinearLayout(Context context, IAttributeSet attrs)
                : base(context, attrs)
            {
                SCALE = context.Resources.DisplayMetrics.Density;
            }

            protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
            {
                var mode = MeasureSpec.GetMode(widthMeasureSpec);
                int measuredWidth = MeasureSpec.GetSize(widthMeasureSpec);
                int adjustedMaxWidth = (int)(MAX_WIDTH_DP * SCALE + 0.5f);
                int adjustedWidth = Math.Min(measuredWidth, adjustedMaxWidth);
                int adjustedWidthMeasureSpec = MeasureSpec.MakeMeasureSpec(adjustedWidth, mode);
                base.OnMeasure(adjustedWidthMeasureSpec, heightMeasureSpec);
            }
        }
    }
}

更新:添加了另一个类 BalloonItemizedOverlay。我没有测试过这段代码,它只是编译。

using System.Collections.Generic;
using System.Linq;
using Android.GoogleMaps;
using Android.Graphics.Drawables;
using Android.OS;
using Android.Views;
using Java.Lang;

namespace MapViewBalloons
{
    public abstract class BalloonItemizedOverlay : ItemizedOverlay, View.IOnTouchListener, View.IOnClickListener
    {

        private static long BALLOON_INFLATION_TIME = 300;
        private static Handler _handler = new Handler();

        private MapView _mapView;
        private BalloonOverlayView _balloonView;
        private View _clickRegion;
        private View _closeRegion;
        private int _viewOffset;
        private MapController _mc;
        private OverlayItem _currentFocusedItem;
        private int _currentFocusedIndex;

        private float _startX,
            _startY;

        private bool _showClose = true;
        private bool _showDisclosure = false;
        private bool _snapToCenter = true;

        private static bool _isInflating = false;
        private BalloonRunnable _balloonRunnable;

        /**
         * Create a new BalloonItemizedOverlay
         * 
         * @param defaultMarker - A bounded Drawable to be drawn on the map for each item in the overlay.
         * @param mapView - The view upon which the overlay items are to be drawn.
         */
        public BalloonItemizedOverlay(Drawable defaultMarker, MapView mapView)
            : base(defaultMarker)
        {
            this._mapView = mapView;
            _viewOffset = 0;
            _mc = mapView.Controller;

            _balloonRunnable = new BalloonRunnable(this);
        }

        /**
         * Set the horizontal distance between the marker and the bottom of the information
         * balloon. The default is 0 which works well for center bounded markers. If your
         * marker is center-bottom bounded, call this before adding overlay items to ensure
         * the balloon hovers exactly above the marker. 
         * 
         * @param pixels - The padding between the center point and the bottom of the
         * information balloon.
         */
        public int BalloonBottomOffset
        {
            get { return _viewOffset; }
            set { _viewOffset = value; }
        }

        /**
         * Override this method to handle a "tap" on a balloon. By default, does nothing 
         * and returns false.
         * 
         * @param index - The index of the item whose balloon is tapped.
         * @param item - The item whose balloon is tapped.
         * @return true if you handled the tap, otherwise false.
         */
        protected bool OnBalloonTap(int index, OverlayItem item)
        {
            return false;
        }

        /**
         * Override this method to perform actions upon an item being tapped before 
         * its balloon is displayed.
         * 
         * @param index - The index of the item tapped.
         */
        protected void OnBalloonOpen(int index) { }

        protected override bool OnTap(int index)
        {

            _handler.RemoveCallbacks(_balloonRunnable);
            _isInflating = true;
            _handler.PostDelayed(_balloonRunnable, BALLOON_INFLATION_TIME);

            _currentFocusedIndex = index;
            _currentFocusedItem = CreateItem(index) as OverlayItem;
            SetLastFocusedIndex(index);

            OnBalloonOpen(index);
            CreateAndDisplayBalloonOverlay();

            if (_snapToCenter)
            {
                animateTo(index, _currentFocusedItem.Point);
            }

            return true;
        }

        /**
         * Animates to the given center point. Override to customize how the
         * MapView is animated to the given center point
         *
         * @param index The index of the item to center
         * @param center The center point of the item
         */
        protected void animateTo(int index, GeoPoint center)
        {
            _mc.AnimateTo(center);
        }

        /**
         * Creates the balloon view. Override to create a sub-classed view that
         * can populate additional sub-views.
         */
        protected BalloonOverlayView CreateBalloonOverlayView()
        {
            return new BalloonOverlayView(GetMapView().Context, BalloonBottomOffset);
        }

        /**
         * Expose map view to subclasses.
         * Helps with creation of balloon views. 
         */
        protected MapView GetMapView()
        {
            return _mapView;
        }

        /**
         * Makes the balloon the topmost item by calling View.bringToFront().
         */
        public void BringBalloonToFront()
        {
            if (_balloonView != null)
            {
                _balloonView.BringToFront();
            }
        }

        /**
         * Sets the visibility of this overlay's balloon view to GONE and unfocus the item. 
         */
        public void HideBalloon()
        {
            if (_balloonView != null)
            {
                _balloonView.Visibility = ViewStates.Gone;
            }
            _currentFocusedItem = null;
        }

        /**
         * Hides the balloon view for any other BalloonItemizedOverlay instances
         * that might be present on the MapView.
         * 
         * @param overlays - list of overlays (including this) on the MapView.
         */
        private void HideOtherBalloons(List<Overlay> overlays)
        {

            foreach (var overlay in overlays)
            {
                if (overlay is BalloonItemizedOverlay && overlay != this)
                {
                    ((BalloonItemizedOverlay)overlay).HideBalloon();
                }
            }

        }

        public void HideAllBalloons()
        {
            if (!_isInflating)
            {
                List<Overlay> mapOverlays = _mapView.Overlays.ToList();
                if (mapOverlays.Count > 1)
                {
                    HideOtherBalloons(mapOverlays);
                }
                HideBalloon();
            }
        }

        public override Java.Lang.Object Focus
        {
            get
            {
                return _currentFocusedItem;
            }

            set
            {
                _currentFocusedIndex = LastFocusedIndex;
                _currentFocusedItem = (OverlayItem)value;
                if (_currentFocusedItem == null)
                {
                    HideBalloon();
                }
                else
                {
                    CreateAndDisplayBalloonOverlay();
                }
            }
        }

        /**
         * Creates and displays the balloon overlay by recycling the current 
         * balloon or by inflating it from xml. 
         * @return true if the balloon was recycled false otherwise 
         */
        private bool CreateAndDisplayBalloonOverlay()
        {
            bool isRecycled;
            if (_balloonView == null)
            {
                _balloonView = CreateBalloonOverlayView();
                _clickRegion = (View)_balloonView.FindViewById(Resource.Id.balloon_inner_layout);
                _clickRegion.SetOnTouchListener(this);
                _closeRegion = (View)_balloonView.FindViewById(Resource.Id.balloon_close);
                if (_closeRegion != null)
                {
                    if (!_showClose)
                    {
                        _closeRegion.Visibility = ViewStates.Gone;
                    }
                    else
                    {
                        _closeRegion.SetOnClickListener(this);
                    }
                }
                if (_showDisclosure && !_showClose)
                {
                    View v = _balloonView.FindViewById(Resource.Id.balloon_disclosure);
                    if (v != null)
                    {
                        v.Visibility = ViewStates.Visible;
                    }
                }
                isRecycled = false;
            }
            else
            {
                isRecycled = true;
            }

            _balloonView.Visibility = ViewStates.Gone;

            List<Overlay> mapOverlays = _mapView.Overlays.ToList();
            if (mapOverlays.Count > 1)
            {
                HideOtherBalloons(mapOverlays);
            }

            if (_currentFocusedItem != null)
                _balloonView.SetData(_currentFocusedItem);

            GeoPoint point = _currentFocusedItem.Point;
            MapView.LayoutParams layoutParams = new MapView.LayoutParams(
                    MapView.LayoutParams.WrapContent, MapView.LayoutParams.WrapContent, point,
                    MapView.LayoutParams.BottomCenter);
            layoutParams.Mode = MapView.LayoutParams.ModeMap;

            _balloonView.Visibility = ViewStates.Visible;

            if (isRecycled)
            {
                _balloonView.LayoutParameters = layoutParams;
            }
            else
            {
                _mapView.AddView(_balloonView, layoutParams);
            }

            return isRecycled;
        }

        public void SetShowClose(bool showClose)
        {
            _showClose = showClose;
        }

        public void SetShowDisclosure(bool showDisclosure)
        {
            _showDisclosure = showDisclosure;
        }

        public void SetSnapToCenter(bool snapToCenter)
        {
            _snapToCenter = snapToCenter;
        }

        public bool IsInflating
        {
            get { return _isInflating; }
            set { _isInflating = value; }
        }

        private class BalloonRunnable : Java.Lang.Object, IRunnable
        {
            private BalloonItemizedOverlay _item;
            public BalloonRunnable(BalloonItemizedOverlay item)
            {
                _item = item;
            }

            public void Run()
            {
                _item.IsInflating = false;
            }
        }

        public bool OnTouch(View v, MotionEvent e)
        {
            View l = ((View)v.Parent).FindViewById(Resource.Id.balloon_main_layout);
            Drawable d = l.Background;

            if (e.Action == MotionEventActions.Down)
            {
                if (d != null)
                {
                    int[] states = { Android.Resource.Attribute.StatePressed };
                    if (d.SetState(states))
                    {
                        d.InvalidateSelf();
                    }
                }
                _startX = e.GetX();
                _startY = e.GetY();
                return true;
            }
            else if (e.Action == MotionEventActions.Up)
            {
                if (d != null)
                {
                    int[] newStates = { };
                    if (d.SetState(newStates))
                    {
                        d.InvalidateSelf();
                    }
                }
                if (Java.Lang.Math.Abs(_startX - e.GetX()) < 40 && Java.Lang.Math.Abs(_startY - e.GetY()) < 40)
                {
                    // call overridden method
                    OnBalloonTap(_currentFocusedIndex, _currentFocusedItem);
                }
                return true;
            }
            else
            {
                return false;
            }
        }

        public void OnClick(View v)
        {
            HideBalloon();
        }
    }
}
于 2012-09-25T14:04:08.040 回答