Hey guys! 最近在开发xamarin forms发现iOS系统对Secondary ToolbarItem显示不太友好,在Android上二级菜单是采用Popup Menu的方式展示,在IOS居然是Tab方式占据屏幕上方。在国内很少人用Xamarin 开发ios吧,资源不足后来在国外论坛找到一个解决方法,论坛地址Content Page Secondary Toolbar Items in iOS same as Android — Xamarin Community Forums
非常感谢AmitManchanda外国友人给我们提供这个解决方案 GitHub地址:GitHub - AmitManchanda/iOSSecondaryToolbarMenubar: This is a Xamarin forms based repository in which I created a menu bar in iPhone and iPad toolbar for secondary toolbar items same as android.
OK 开始正文
1.定义一个Secondary ToolbarItem Menu settings interface
public interface ISecondaryToolbarMenuSetting
{
Color CellBackgroundColor { get; }
Color CellTextColor { get; }
Color MenuBackgroundColor { get; }
float RowHeight { get; }
Color ShadowColor { get; }
float ShadowOpacity { get; }
float ShadowRadius { get; }
float ShadowOffsetDimension { get; }
float TableWidth { get; }
}
2.定义通用ContentPage
/// <summary>
/// 需要Secondary toolbarItem的page 请用BaseContentPage
/// 已做IOS二级菜单适配处理
/// </summary>
public class BaseContentPage : ContentPage, ISecondaryToolbarMenuSetting
{
public Color CellBackgroundColor => Color.White;
public Color CellTextColor => Color.Black;
public Color MenuBackgroundColor => Color.White;
public float RowHeight => 50;
public Color ShadowColor => Color.Black;
public float ShadowOpacity => 0.3f;
public float ShadowRadius => 5.0f;
public float ShadowOffsetDimension => 5.0f;
public float TableWidth => 250;
public BaseContentPage()
{
}
}
3.在IOS项目添加一个CustomPageRenderer
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
[assembly: Xamarin.Forms.ExportRenderer(typeof(BaseContentPage), typeof(RightToolbarMenuCustomRenderer))]
namespace SGS.SIO.iOS.CustomRender
{
public class RightToolbarMenuCustomRenderer : PageRenderer
{
private List<ToolbarItem> _secondaryItems;
private UITableView _table;
private UITapGestureRecognizer _tapGestureRecognizer;
private UIView _transparentView;
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
if (e.NewElement is BaseContentPage)
{
ToolbarItemInit();
}
base.OnElementChanged(e);
}
private void ToolbarItemInit()
{
if (Element is ContentPage page)
{
_secondaryItems = page.ToolbarItems.Where(i => i.Order == ToolbarItemOrder.Secondary).ToList();
_secondaryItems.ForEach(t => page.ToolbarItems.Remove(t));
if (_secondaryItems?.Count == 0 && page.ToolbarItems.Any(a => a.StyleId == "options"))
{
page.ToolbarItems.Clear();
}
else if (_secondaryItems?.Count >= 1 && !page.ToolbarItems.Any(a => a.StyleId == "options"))
{
page.ToolbarItems.Add(new ToolbarItem()
{
Order = ToolbarItemOrder.Primary,
IconImageSource = "options.png",
StyleId = "options",
Priority = 1,
Command = new Command(ToggleDropDownMenuVisibility)
});
}
}
}
private void ToggleDropDownMenuVisibility()
{
if (!IsTableExists())
{
if ((View?.Subviews != null)
&& (View.Subviews.Length > 0)
&& (View.Bounds != null)
&& (_secondaryItems != null)
&& (_secondaryItems.Count > 0))
{
_table = OpenDropDownMenu(Element as ISecondaryToolbarMenuSetting);
Add(_table);
}
}
else
CloseDropDownMenu();
}
private bool IsTableExists()
{
if (View?.Subviews != null)
{
foreach (var subview in View.Subviews)
{
if (_table != null && subview == _table)
{
return true;
}
}
}
if (_tapGestureRecognizer != null)
{
_transparentView?.RemoveGestureRecognizer(_tapGestureRecognizer);
_tapGestureRecognizer = null;
}
_table = null;
_tapGestureRecognizer = null;
return false;
}
private UITableView OpenDropDownMenu(ISecondaryToolbarMenuSetting secondaryMenuSupport)
{
_transparentView = _transparentView = new UIView(new CGRect(0, 0, View.Bounds.Width, View.Bounds.Height))
{
BackgroundColor = UIColor.FromRGBA(0, 0, 0, 0)
};
_tapGestureRecognizer = new UITapGestureRecognizer(CloseDropDownMenu);
_transparentView.AddGestureRecognizer(_tapGestureRecognizer);
Add(_transparentView);
UITableView table = null;
if (_secondaryItems != null && _secondaryItems.Count > 0)
{
table = new UITableView(GetPositionForDropDownMenu(secondaryMenuSupport.RowHeight, secondaryMenuSupport.TableWidth))
{
Source = new TableSource(_secondaryItems, _transparentView, secondaryMenuSupport.RowHeight),
ClipsToBounds = false
};
table.ScrollEnabled = false;
table.Layer.ShadowColor = secondaryMenuSupport.ShadowColor.ToCGColor();
table.Layer.ShadowOpacity = secondaryMenuSupport.ShadowOpacity;
table.Layer.ShadowRadius = secondaryMenuSupport.ShadowRadius;
table.Layer.ShadowOffset = new System.Drawing.SizeF(secondaryMenuSupport.ShadowOffsetDimension, secondaryMenuSupport.ShadowOffsetDimension);
table.BackgroundColor = secondaryMenuSupport.MenuBackgroundColor.ToUIColor();
}
return table;
}
public override void ViewWillDisappear(bool animated)
{
CloseDropDownMenu();
base.ViewWillDisappear(animated);
}
private RectangleF GetPositionForDropDownMenu(float rowHeight, float tableWidth)
{
if ((View?.Bounds != null)
&& (_secondaryItems != null)
&& (_secondaryItems.Count > 0))
{
return new RectangleF(
(float)View.Bounds.Width - tableWidth,
0,
tableWidth,
_secondaryItems.Count() * rowHeight);
}
else
{
return new RectangleF(0.0f, 0.0f, 0.0f, 0.0f);
}
}
private void CloseDropDownMenu()
{
if (_table != null)
{
if (_tapGestureRecognizer != null)
{
_transparentView?.RemoveGestureRecognizer(_tapGestureRecognizer);
_tapGestureRecognizer = null;
}
if (View?.Subviews != null)
{
foreach (var subview in View.Subviews)
{
if (subview == _table)
{
_table.RemoveFromSuperview();
break;
}
}
if (_transparentView != null)
{
foreach (var subview in View.Subviews)
{
if (subview == _transparentView)
{
_transparentView.RemoveFromSuperview();
break;
}
}
}
}
_table = null;
_transparentView = null;
}
}
public override void ViewDidLayoutSubviews()
{
base.ViewDidLayoutSubviews();
if (_table != null)
{
if (Element is ISecondaryToolbarMenuSetting secondaryMenuSupport)
PositionExistingDropDownMenu(secondaryMenuSupport.RowHeight, secondaryMenuSupport.TableWidth);
}
}
private void PositionExistingDropDownMenu(float rowHeight, float tableWidth)
{
if ((View?.Bounds != null)
&& (_secondaryItems != null)
&& (_secondaryItems.Count > 0)
&& (_table != null))
{
_table.Frame = GetPositionForDropDownMenu(rowHeight, tableWidth);
}
}
}
}
4.还有一个TableSource
public class TableSource : UITableViewSource
{
List<ToolbarItem> _tableItems;
string[] _tableItemTexts;
string CellIdentifier = "TableCell";
UIView _tableSuperView = null;
float RowHeight;
public TableSource(List<ToolbarItem> items, UIView tableSuperView,float rowHeight)
{
_tableItems = items;
_tableSuperView = tableSuperView;
_tableItemTexts = items.Select(a => a.Text).ToArray();
RowHeight = rowHeight;
}
public override nint RowsInSection(UITableView tableview, nint section)
{
return _tableItemTexts?.Length ?? 0;
}
public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
{
UITableViewCell cell = tableView.DequeueReusableCell(CellIdentifier);
string item = _tableItemTexts[indexPath.Row];
if (cell == null)
{ cell = new UITableViewCell(UITableViewCellStyle.Default, CellIdentifier); }
cell.TextLabel.Text = item;
return cell;
}
public override nfloat GetHeightForRow(UITableView tableView, NSIndexPath indexPath)
{
return RowHeight;
}
public override void RowSelected(UITableView tableView, NSIndexPath indexPath)
{
var command = _tableItems[indexPath.Row].Command;
if (command != null)
command.Execute(_tableItems[indexPath.Row].CommandParameter);
tableView.DeselectRow(indexPath, true);
tableView.RemoveFromSuperview();
if (_tableSuperView != null)
{
_tableSuperView.RemoveFromSuperview();
}
}
}
到此基本就可以啦。以上代码在Github源码基础上修改一丁点。