Xaml 如何在Xamarin表单中显示工具栏项图标的徽章计数

Xaml 如何在Xamarin表单中显示工具栏项图标的徽章计数,xaml,xamarin,xamarin.android,xamarin.forms,xamarin-studio,Xaml,Xamarin,Xamarin.android,Xamarin.forms,Xamarin Studio,它不是关于如何显示通知徽章,也不是关于如何显示工具栏项目图标。很明显,如何在工具栏项目图标上显示徽章是个问题 我正在共享在XF内容页中创建带有图标的工具栏项目的代码: 在cs文件中: ToolbarItem cartItem = new ToolbarItem(); scanItem.Text = "My Cart"; scanItem.Order = ToolbarItemOrder.Primary; scanItem.Icon = "carticon.png"

它不是关于如何显示通知徽章,也不是关于如何显示工具栏项目图标。很明显,如何在工具栏项目图标上显示徽章是个问题

我正在共享在XF内容页中创建带有图标的工具栏项目的代码:

在cs文件中:

    ToolbarItem cartItem = new ToolbarItem();
    scanItem.Text = "My Cart";
    scanItem.Order = ToolbarItemOrder.Primary;
    scanItem.Icon = "carticon.png";

    ToolbarItems.Add(cartItem );
在Xaml文件中:

<ContentPage.ToolbarItems>
    <ToolbarItem Text="Cart" Priority="0" x:Name="menu1"> 
    </ToolbarItem>   
  </ContentPage.ToolbarItems>


现在我想在上面添加的工具栏项目图标上放置一个徽章计数。如何实现这一目标

在本机工具栏中放置徽章图标实际上比它的价值更大。如果我需要徽章图标,我会删除导航页面

NavigationPage.SetHasNavigationBar(myPageInstance, false);
然后我从头开始创建自己的工具栏。在这个工具栏中,我可以在其中覆盖一个图像,你也可以根据需要在其中放置一个数字。比如说

 <Grid>           
        <Grid.GestureRecognizers>
            <TapGestureRecognizer Command="{Binding IconCommand}" />
        </Grid.GestureRecognizers>

        <iconize:IconImage
                     Icon="fa-drawer"
                     IconColor="white"
                     IconSize="20" />

        <Grid Margin="15,-15,0,0">
            <iconize:IconImage Grid.Row="0"
                       HeightRequest="40"
                       WidthRequest="40"
                       Icon="fa-circle"
                       IconColor="red"
                       IsVisible="{Binding IsCircleVisible}"
                       IconSize="10" />
        </Grid>

    </Grid>

我使用wtih FontAwesome作为图标

在的帮助下,我实现了它。在实施之前,阅读并理解完整的讨论。感谢“斯拉瓦·切尼科夫”、“伊曼纽尔·萨贝塔”、“米尔扎·西坎德”、“萨蒂什”与您讨论并分享您的代码

SETP1:在PCL中创建一个助手类,并从nugget安装NGraphics包

 public class CartIconHelper
{
    private static Graphic _svgGraphic = null;
    public const string ResourcePath = "ToolBarAndroidBadge.Resources.cartIcon.svg";

    private static PathOp[] RoundRect(NGraphics.Rect rect, double radius)
    {
        return new PathOp[]
                   {
                   new NGraphics.MoveTo(rect.X + radius, rect.Y),
                   new NGraphics.LineTo(rect.X + rect.Width - radius, rect.Y),
                   new NGraphics.ArcTo(new NGraphics.Size(radius, radius), true, false, new NGraphics.Point(rect.X + rect.Width, rect.Y + radius)),
                   new NGraphics.LineTo(rect.X + rect.Width, rect.Y + rect.Height - radius),
                   new NGraphics.ArcTo(new NGraphics.Size(radius, radius), true, false, new NGraphics.Point(rect.X + rect.Width - radius, rect.Y + rect.Height)),
                   new NGraphics.LineTo(rect.X + radius, rect.Y + rect.Height),
                   new NGraphics.ArcTo(new NGraphics.Size(radius, radius), true, false, new NGraphics.Point(rect.X, rect.Y + rect.Height - radius)),
                   new NGraphics.LineTo(rect.X, rect.Y + radius), new NGraphics.ArcTo(new NGraphics.Size(radius, radius), true, false, new NGraphics.Point(rect.X + radius, rect.Y)),
                   new NGraphics.ClosePath()
                   };
    }

    public static string DrawCartIcon(int count, string path, double iconSize = 30, double scale = 2, string fontName = "Arial", double fontSize = 12, double textSpacing = 4)
    {
        var service = DependencyService.Get<IService>();

        var canvas = service.GetCanvas();

        if (_svgGraphic == null) using (var stream = typeof(CartIconHelper).GetTypeInfo().Assembly.GetManifestResourceStream(path))
                _svgGraphic = new SvgReader(new StreamReader(stream)).Graphic; 
                 //st = ReadFully(stream);

        var minSvgScale = Math.Min(canvas.Size.Width / _svgGraphic.Size.Width, canvas.Size.Height / _svgGraphic.Size.Height) / 1.15;

        var w = _svgGraphic.Size.Width / minSvgScale;
        var h = _svgGraphic.Size.Height / minSvgScale;

        _svgGraphic.ViewBox = new NGraphics.Rect(0, -14, w, h);
        _svgGraphic.Draw(canvas);

        if (count > 0)
        {
            var text = count > 99 ? "99+" : count.ToString();
            var font = new NGraphics.Font(fontName, fontSize);
            var textSize = canvas.MeasureText(text, font);

            var textRect = new NGraphics.Rect(canvas.Size.Width - textSize.Width - textSpacing, textSpacing, textSize.Width, textSize.Height);

            if (count < 10)
            {
                var side = Math.Max(textSize.Width, textSize.Height);
                var elipseRect = new NGraphics.Rect(canvas.Size.Width - side - 2 * textSpacing, 0, side + 2 * textSpacing, side + 2 * textSpacing);
                canvas.FillEllipse(elipseRect, NGraphics.Colors.Red);
                textRect -= new NGraphics.Point(side - textSize.Width, side - textSize.Height) / 2.0;
            }
            else
            {
                var elipseRect = new NGraphics.Rect(textRect.Left - textSpacing, textRect.Top - textSpacing, textRect.Width + 2 * textSpacing, textSize.Height + 2 * textSpacing);
                canvas.FillPath(RoundRect(elipseRect, 6), NGraphics.Colors.Red);
            }
            var testReact1= new NGraphics.Rect(20,12,0,0);
            // canvas.DrawText(text, textRect + new NGraphics.Point(0, textSize.Height), font, NGraphics.TextAlignment.Center, NGraphics.Colors.Black);
            canvas.DrawText("5", testReact1, font, NGraphics.TextAlignment.Left, NGraphics.Colors.White);

        }

        service.SaveImage(canvas.GetImage());
        string imagePath = service.GetImage();
        return imagePath;
       // return st;
    }

}
步骤3:在Android项目中实现此接口

 class CanvasServices:IService
{
        private readonly AndroidPlatform _platform;
        public CanvasServices()
        {
            _platform = new AndroidPlatform();
        }

        public void SaveImage(IImage image)
        {
        var dir = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
        var filePath = System.IO.Path.Combine(dir, "cart.png");
        var stream = new FileStream(filePath, FileMode.Create);
        image.SaveAsPng(stream);
        //bitmap.Compress(image., 100, stream);
        stream.Close();
    }

        public string GetImage()
        {
            var dir = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
            var filePath = System.IO.Path.Combine(dir, "cart.png");
            using (var streamReader = new StreamReader(filePath))
            {
                string content = streamReader.ReadToEnd();
                System.Diagnostics.Debug.WriteLine(content);
            }
            return filePath;
        }

        public IImageCanvas GetCanvas()
        {
            NGraphics.Size size = new NGraphics.Size(30);
            return _platform.CreateImageCanvas(size);
        }

        public NGraphics.AndroidPlatform GetPlatform()
        {
            return _platform;
        }
}
SETP4:现在,在PCL项目中使用CartIcon助手在TabBarItem中显示徽章

 public partial class MainPage : ContentPage
{
    public MainPage()
    {
        InitializeComponent();


        var imagePath = CartIconHelper.DrawCartIcon(2, "ToolBarAndroidBadge.Resources.cartIcon.svg");
        string deviceSepecificFolderPath = Device.OnPlatform(null, imagePath, null);
        object convertedObject = new FileImageSourceConverter().ConvertFromInvariantString(deviceSepecificFolderPath);
        FileImageSource fileImageSource = (FileImageSource)convertedObject;                

        ToolbarItem cartItem = new ToolbarItem();
        cartItem.Text = "My Cart";
        cartItem.Order = ToolbarItemOrder.Primary;
        cartItem.Icon = fileImageSource;




        ToolbarItems.Add(cartItem);

    }
}

实现下面的代码,在工具栏图标上用文本绘制一个地圆

  • BarbuttonieMextensions.cs
  • 使用CoreAnimation;
    使用核心图形;
    使用基础;
    使用ObjectRuntime;
    使用制度;
    使用System.Linq;
    使用System.Runtime.InteropServices;
    使用UIKit;
    命名空间TeamCollaXform.Views.Services
    {
    公共静态类BarButtonItemExtensions
    {
    枚举关联策略
    {
    赋值=0,
    保留_非原子=1,
    复制_非原子=3,
    RETAIN=01401,
    副本=01403,
    }
    静态NSString BadgeKey=新NSString(@“BadgeKey”);
    [DllImport(Constants.ObjectiveLibrary)]
    静态外部无效对象jc_setAssociatedObject(IntPtr对象、IntPtr键、IntPtr值、AssociationPolicy策略);
    [DllImport(Constants.ObjectiveLibrary)]
    静态外部IntPtr objc_getAssociatedObject(IntPtr obj,IntPtr key);
    静态CAShapeLayer GetBadgeLayer(UIBarButtonItem barButtonItem)
    {
    var handle=objc_getAssociatedObject(barButtonItem.handle,BadgeKey.handle);
    if(handle!=IntPtr.Zero)
    {
    var value=ObjCRuntime.Runtime.GetNSObject(句柄);
    if(值!=null)
    返回值为CAShapeLayer;
    其他的
    返回null;
    }
    返回null;
    }
    静态空白DrawRoundedRect(CAShapeLayer层、CGRect rect、浮动半径、UIColor颜色、bool填充)
    {
    layer.FillColor=filled?color.CGColor:UIColor.White.CGColor;
    layer.StrokeColor=color.CGColor;
    layer.Path=UIBezierPath.FromRoundedRect(rect,radius).CGPath;
    }
    public static void AddBadge(此UIBarButtonItem barButtonItem,字符串文本,UIColor backgroundColor,UIColor textColor,bool filled=true,float fontSize=11.0f)
    {
    if(string.IsNullOrEmpty(text))
    {
    返回;
    }
    CGPoint offset=CGPoint.Empty;
    if(backgroundColor==null)
    backgroundColor=UIColor.Red;
    var font=UIFont.SystemFontOfSize(fontSize);
    if(UIDevice.CurrentDevice.CheckSystemVersion(9,0))
    {
    font=UIFont.monospacedGitSystemFontOfsize(fontSize,UIFontWeight.Regular);
    }
    var view=barButtonItem.ValueForKey(新的NSString(@“视图”))作为UIView;
    var bLayer=GetBadgeLayer(巴布通体);
    bLayer?.RemoveFromSuperLayer();
    var badgeSize=text.StringSize(字体);
    var高度=徽章大小。高度;
    var width=badgeSize.width+5;/*填充*/
    //确保我们至少有一个圆圈
    if(宽度<高度)
    {
    宽度=高度;
    }
    //x位置从右侧偏移
    var x=view.Frame.Width-宽度+偏移量.x;
    var badgeFrame=新的CGRect(新的CGPoint(x:x-4,y:offset.y+5),大小:新的CGSize(宽度:宽度,高度:高度));
    bLayer=新的CAShapeLayer();
    DrawRoundedRect(bLayer,徽章框架,7.0f,背景色,填充);
    view.Layer.AddSublayer(bLayer);
    //初始化徽章标签
    var label=new CATextLayer();
    label.String=文本;
    label.TextAlignmentMode=CATextLayerAlignmentMode.Center;
    label.SetFont(CGFont.CreateWithFontName(font.Name));
    label.FontSize=font.PointSize;
    label.Frame=badgeFrame;
    label.ForegroundColor=filled?textColor.CGColor:UIColor.White.CGColor;
    label.BackgroundColor=UIColor.Clear.CGColor;
    label.ContentsScale=UIScreen.MainScreen.Scale;
    bLayer.AddSublayer(标签);
    //将徽章另存为UIBarButtonItem属性
    objc_setAssociatedObject(barButtonItem.Handle、BadgeKey.Handle、bLayer.Handle、AssociationPolicy.RETAIN_非原子);
    }
    公共静态void updateEdge(此UIBarButtonim BarButtonim、字符串文本、UIColor backgroundColor、UIColor textColor)
    {
    var bLayer=GetBadgeLayer(巴布通体);
    if(string.IsNullOrEmpty(text)| | text==“0”)
    {
    bLayer?.RemoveFromSuperLayer();
    objc_setAssociatedObject(barButtonItem.Handle、BadgeKey.Handle、new CAShapeLayer().Handle、AssociationPolicy.ASSIGN);
    返回;
    }
    变量文本
    
     public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();
    
    
            var imagePath = CartIconHelper.DrawCartIcon(2, "ToolBarAndroidBadge.Resources.cartIcon.svg");
            string deviceSepecificFolderPath = Device.OnPlatform(null, imagePath, null);
            object convertedObject = new FileImageSourceConverter().ConvertFromInvariantString(deviceSepecificFolderPath);
            FileImageSource fileImageSource = (FileImageSource)convertedObject;                
    
            ToolbarItem cartItem = new ToolbarItem();
            cartItem.Text = "My Cart";
            cartItem.Order = ToolbarItemOrder.Primary;
            cartItem.Icon = fileImageSource;
    
    
    
    
            ToolbarItems.Add(cartItem);
    
        }
    }
    
    using CoreAnimation;    
    using CoreGraphics;    
    using Foundation;    
    using ObjCRuntime;    
    using System;    
    using System.Linq;
    using System.Runtime.InteropServices;
    using UIKit;
    
    namespace TeamCollaXform.Views.Services
    {
        public static class BarButtonItemExtensions
        {
            enum AssociationPolicy
            {
                ASSIGN = 0,
                RETAIN_NONATOMIC = 1,
                COPY_NONATOMIC = 3,
                RETAIN = 01401,
                COPY = 01403,
            }
    
            static NSString BadgeKey = new NSString(@"BadgeKey");
    
            [DllImport(Constants.ObjectiveCLibrary)]
            static extern void objc_setAssociatedObject(IntPtr obj, IntPtr key, IntPtr value, AssociationPolicy policy);
    
    
            [DllImport(Constants.ObjectiveCLibrary)]
            static extern IntPtr objc_getAssociatedObject(IntPtr obj, IntPtr key);
    
            static CAShapeLayer GetBadgeLayer(UIBarButtonItem barButtonItem)
            {
                var handle = objc_getAssociatedObject(barButtonItem.Handle, BadgeKey.Handle);
    
                if (handle != IntPtr.Zero)
                {
                    var value = ObjCRuntime.Runtime.GetNSObject(handle);
                    if (value != null)
                        return value as CAShapeLayer;
                    else
                        return null;
                }
                return null;
            }
    
            static void DrawRoundedRect(CAShapeLayer layer, CGRect rect, float radius, UIColor color, bool filled)
            {
                layer.FillColor = filled ? color.CGColor : UIColor.White.CGColor;
                layer.StrokeColor = color.CGColor;
                layer.Path = UIBezierPath.FromRoundedRect(rect, radius).CGPath;
            }
    
            public static void AddBadge(this UIBarButtonItem barButtonItem, string text, UIColor backgroundColor, UIColor textColor, bool filled = true, float fontSize = 11.0f)
            {
    
                if (string.IsNullOrEmpty(text))
                {
                    return;
                }
    
                CGPoint offset = CGPoint.Empty;
    
                if (backgroundColor == null)
                    backgroundColor = UIColor.Red;
    
                var font = UIFont.SystemFontOfSize(fontSize);
    
                if (UIDevice.CurrentDevice.CheckSystemVersion(9, 0))
                {
                    font = UIFont.MonospacedDigitSystemFontOfSize(fontSize, UIFontWeight.Regular);
                }
    
                var view = barButtonItem.ValueForKey(new NSString(@"view")) as UIView;
                var bLayer = GetBadgeLayer(barButtonItem);
                bLayer?.RemoveFromSuperLayer();
    
    
                var badgeSize = text.StringSize(font);
    
    
                var height = badgeSize.Height;
                var width = badgeSize.Width + 5; /* padding */
    
                //make sure we have at least a circle
                if (width < height)
                {
                    width = height;
                }
    
                //x position is offset from right-hand side
                var x = view.Frame.Width - width + offset.X;
    
    
                var badgeFrame = new CGRect(new CGPoint(x: x - 4, y: offset.Y + 5), size: new CGSize(width: width, height: height));
    
                bLayer = new CAShapeLayer();
                DrawRoundedRect(bLayer, badgeFrame, 7.0f, backgroundColor, filled);
                view.Layer.AddSublayer(bLayer);
    
                // Initialiaze Badge's label
                var label = new CATextLayer();
                label.String = text;
                label.TextAlignmentMode = CATextLayerAlignmentMode.Center;
                label.SetFont(CGFont.CreateWithFontName(font.Name));
                label.FontSize = font.PointSize;
                label.Frame = badgeFrame;
                label.ForegroundColor = filled ? textColor.CGColor : UIColor.White.CGColor;
                label.BackgroundColor = UIColor.Clear.CGColor;
                label.ContentsScale = UIScreen.MainScreen.Scale;
                bLayer.AddSublayer(label);
    
                // Save Badge as UIBarButtonItem property
                objc_setAssociatedObject(barButtonItem.Handle, BadgeKey.Handle, bLayer.Handle, AssociationPolicy.RETAIN_NONATOMIC);
    
            }
            public static void UpdateBadge(this UIBarButtonItem barButtonItem, string text, UIColor backgroundColor, UIColor textColor)
            {
                var bLayer = GetBadgeLayer(barButtonItem);
    
                if (string.IsNullOrEmpty(text) || text == "0")
                {
                    bLayer?.RemoveFromSuperLayer();
    
                    objc_setAssociatedObject(barButtonItem.Handle, BadgeKey.Handle, new CAShapeLayer().Handle, AssociationPolicy.ASSIGN);
                    return;
                }
    
                var textLayer = bLayer?.Sublayers?.First(p => p is CATextLayer) as CATextLayer;
                if (textLayer != null)
                {
                    textLayer.String = text;
                }
                else
                {
                    barButtonItem.AddBadge(text, backgroundColor, textColor);
                }
            }
    
        }
    }
    
    using TeamCollaXform.Views.Services; 
    using Xamarin.Forms; 
    using Xamarin.Forms.Platform.iOS;
    
    [assembly: Dependency(typeof(ToolbarItemBadgeService))] 
    namespace TeamCollaXform.Views.Services 
    {
        /// <summary>
        /// 
        /// </summary>
        public interface IToolbarItemBadgeService
        {
            void SetBadge(Page page, ToolbarItem item, string value, Color backgroundColor, Color textColor);
        }
    
        /// <summary>
        /// 
        /// </summary>
        public class ToolbarItemBadgeService : IToolbarItemBadgeService
        {
            public void SetBadge(Page page, ToolbarItem item, string value, Color backgroundColor, Color textColor)
            {
                Device.BeginInvokeOnMainThread(() =>
                {
                    var renderer = Platform.GetRenderer(page);
                    if (renderer == null)
                    {
                        renderer = Platform.CreateRenderer(page);
                        Platform.SetRenderer(page, renderer);
                    }
                    var vc = renderer.ViewController;
    
                    var rightButtomItems = vc?.ParentViewController?.NavigationItem?.RightBarButtonItems;
                    var idx = rightButtomItems.Length - page.ToolbarItems.IndexOf(item) - 1;            //Revert
    
                    if (rightButtomItems != null && rightButtomItems.Length > idx)
                    {
                        var barItem = rightButtomItems[idx];
                        if (barItem != null)
                        {
                            barItem.UpdateBadge(value, backgroundColor.ToUIColor(), textColor.ToUIColor());
                        }
                    }
    
                });
            }
        } 
    }
    
        void OnAttachClicked(object sender, EventArgs e)
        {
            //var answer = await DisplayAlert("Question?", "Would you like to play a game", "Yes", "No");
            //Debug.WriteLine("Answer: " + answer);
    
            ToolbarItem cmdItem = sender as ToolbarItem;
    
            DependencyService.Get<IToolbarItemBadgeService>().SetBadge(this, cmdItem, $"2", Color.DarkOrange, Color.White);
        }
    
     private void Button_Clicked(object sender, System.EventArgs e)
            {
                MessagingCenter.Send(this, "presnt");           
            }
    
    MessagingCenter.Subscribe<YourPage>(this, "presnt", (sender) =>
                {
                    IsPresented = true;
                });