Search code examples
xamarinxamarin.formsxamarin.ios

How to make focus event / effect for every IOS element?


I have made the following focus effect for Xamarin.Forms.Android so when the keyboard is focused on the element it shows blue rectangle around it.:

protected override void OnAttached()
    {
        try
        {
            OriginalBackground = Container.Background;
            if(Control != null)
            {
                Control.FocusChange += Control_FocusChange;
            }
            else
            {
                Container.FocusChange += Control_FocusChange;
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine("Cannot set property on attached control. Error: ", ex.Message);
        }
    }

    protected override void OnDetached()
    {
    }

    protected override void OnElementPropertyChanged(System.ComponentModel.PropertyChangedEventArgs args)
    {
        base.OnElementPropertyChanged(args);
    }

    private void Control_FocusChange(object sender, FocusChangeEventArgs e)
    {
        if(Control != null)
        {
            if (Control.HasFocus)
            {
                Control.SetBackgroundColor(Android.Graphics.Color.Transparent);
                Control.SetBackgroundResource(Resource.Drawable.focusFrame);
            }
            else
            {
                Control.SetBackground(OriginalBackground);
            }
        }
        else
        {
            if (Container.HasFocus)
            {
                Container.SetBackgroundColor(Android.Graphics.Color.Red);
                Container.SetBackgroundResource(Resource.Drawable.focusFrame);
            }
            else
            {
                Container.SetBackground(OriginalBackground);
            }
        }
    }

Can someone tell me how to the same effect for Xamarin.Forms.IOS ? I tried the following code but it doesn't work on focusing the app the same way as Android. Somehow there isn't an event or perhaps I am missing it for IOS:

        UIColor backgroundColor;
    UIView  view;
    public Func<Brush, CALayer> OriginalBackground { get; private set; }

    protected override void OnAttached()
    {
        try
        {
            OriginalBackground = Container.GetBackgroundLayer;
            if (Container != null)
            {
                this.Container.DidUpdateFocus()
                CreateRectange();
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine("Cannot set property on attached control. Error: ", ex.Message);
        }
    }

    private void CreateRectange()
    {
        view = new UIView();
        view.BackgroundColor = UIColor.Clear;
        view.Frame = new CGRect(30, 100, 36, 36);
        var maskLayer = new CAShapeLayer();

        UIBezierPath bezierPath = UIBezierPath.FromRoundedRect(view.Bounds, (UIRectCorner.TopLeft | UIRectCorner.BottomLeft), new CGSize(18.0, 18.0));


        maskLayer.Path = bezierPath.CGPath;
        maskLayer.Frame = view.Bounds;

        maskLayer.StrokeColor = UIColor.Black.CGColor; //set the borderColor
        maskLayer.FillColor = UIColor.Red.CGColor;   //set the background color
        maskLayer.LineWidth = 1;  //set the border width

        view.Layer.AddSublayer(maskLayer);

        Container.AddSubview(view);
    }

    protected override void OnDetached()
    {
    }

    protected override void OnElementPropertyChanged(PropertyChangedEventArgs args)
    {
        base.OnElementPropertyChanged(args);

        try
        {
            if (args.PropertyName == "IsFocused")
            {
                Control.AddSubview(view);
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine("Cannot set property on attached control. Error: ", ex.Message);
        }
    }

Solution

  • At first, the frame's size should fit the control. And then you need to set the maskLayer.FillColor as UIColor.Clear.CGColor to make the control's content will show correctly.

    You can try the following code:

        UIView view;
        float width,height;
        public Func<Brush, CALayer> OriginalBackground { get; private set; }
    
        protected override void OnAttached()
        {
        }
    
        private void CreateRectange()
        {
            height = (float)Control.Frame.Height;
            width = (float)Control.Frame.Width;
            view = new UIView();
            view.BackgroundColor = UIColor.Clear;
            view.Frame = new CGRect(0,0,width,height);
            var maskLayer = new CAShapeLayer();
            UIBezierPath bezierPath = UIBezierPath.FromRoundedRect(view.Bounds, (UIRectCorner.TopLeft | UIRectCorner.BottomLeft), new CGSize(0,0));
            maskLayer.Path = bezierPath.CGPath;
            maskLayer.Frame = view.Bounds;
            maskLayer.StrokeColor = UIColor.Red.CGColor; //set the borderColor
            maskLayer.FillColor = UIColor.Clear.CGColor;  //set the background color
            maskLayer.LineWidth = 1;  //set the border width
            view.Layer.AddSublayer(maskLayer);
        }
    
        protected override void OnDetached()
        {
        }
    
        protected override void OnElementPropertyChanged(PropertyChangedEventArgs args)
        {
            base.OnElementPropertyChanged(args);   
            try
            {
                if (args.PropertyName == "IsFocused")
                {
                    CreateRectange();
                    Control.AddSubview(view);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Cannot set property on attached control. Error: ", ex.Message);
            }
        }