我正在尝试使用弹出式气球覆盖Mono for Android中的自定义叠加项目。我找到了这个项目https://github.com/jgilfelt/android-mapviewballoons,但它是用Java编写的。我已经开始手动将其转换为C#,但这有点过头了。我已经读过你可以将java文件导入Mono,但是我不确定哪个路径更容易。如果某人有我在C#中链接的预测会更好。谢谢你的帮助!
答案 0 :(得分:3)
我已经冒昧地在c#中为你重写了第一堂课,如果你只是清理java与c#之间的区别,这是相当容易的。
希望您可以将此作为将所有其他类转换为c#的基础,以满足您的需求。
您需要确保使用作者在其github示例中使用的布局文件,drawable和选择器。在项目中包含这些内容并根据需要进行调整。
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();
}
}
}