locked
How to calculate or measure width of a string ? RRS feed

  • Question

  • User167365 posted

    Hi All, My requirement is to calculate the width of a text that is inside a Label. This calculated width is set as the width of the Label. In other words the labels width is equal to the width of the text inside it. Is there any method to achieve this in XForms like we have methods in Xamarin.Android and Xamarin.iOS ? Or is there any workaround ?

    Note : I dont want the text length that returns the number of characters in the string, instead the extent width of the string. Thanks in Advance !!

    Thursday, May 26, 2016 4:01 AM

Answers

  • User167365 posted

    Hey Guys i sorted out a solution long back !!! My bad that i did not post the answer.

    You can achieve the requirement by using the concept of Dependency Services. You declare an interface in the PCL project where you expose a method to calculate the text length. You can implement this interface in the Forms android,iOS and Windows projects.

    You pass the text to the individual platform specific implementation, where you create a equivalent view ( TextView for Android, UILabel for iOS etc) and set the text as the text of the view and then measure it using native codes. Please refer the code snippets incase my description is unclear.

    PCL INTERFACE DECLARATION

    public interface CalculateTextWidth { double calculateWidth (string text); }

    ANDROID IMPLEMENTATION

    `public class CalculateTextWidthAndroid : CalculateTextWidth { public CalculateTextWidthAndroid () {}

            public double calculateWidth (string text)
            {
                Rect bounds = new Rect();
                TextView textView = new TextView(Forms.Context);
                textView.Paint.GetTextBounds(text, 0, text.Length, bounds);
                var length = bounds.Width();           
                return length / Resources.System.DisplayMetrics.ScaledDensity;
            }
    }`
    

    iOS IMPLEMENTATION

    `public class CalculateTextWidthiOS : CalculateTextWidth { UILabel uiLabel ; CGSize length; public CalculateTextWidthiOS () { }

        public double calculateWidth (string text)
        {
            uiLabel = new UILabel ();
            uiLabel.Text = text;
            length = uiLabel.Text.StringSize (uiLabel.Font);
            return length.Width;
        }
    }`
    

    WINDOWS PHONE IMPLEMENTATION `public class CalculateTextWidthWinPhone : CalculateTextWidth { public CalculateTextWidthWinPhone() {}

        public double calculateWidth(string text)
        {
            var textBlock = new TextBlock() { FontSize = 12 };
            textBlock.Text = text;
            var parentBorder = new Border { Child = textBlock };
            textBlock.MaxHeight = 50;
            textBlock.MaxWidth = double.PositiveInfinity;
            parentBorder.Measure(new System.Windows.Size(textBlock.MaxWidth, textBlock.MaxHeight));
            parentBorder.Child = null;
            return parentBorder.DesiredSize.Width;
    
       }
    }`
    

    WinRT IMPLEMENTATION public double calculateWidth(string text) { var textBlock = new TextBlock() { FontSize = 12 }; textBlock.Text = text; var parentBorder = new Border { Child = textBlock }; textBlock.MaxHeight = 50; textBlock.MaxWidth = double.PositiveInfinity; parentBorder.Measure(new System.Windows.Size(textBlock.MaxWidth, textBlock.MaxHeight)); parentBorder.Child = null; return parentBorder.DesiredSize.Width; }

    Please leave a comment in case of any queries

    Regards, Vimal Prabhu

    • Marked as answer by Anonymous Thursday, June 3, 2021 12:00 AM
    Monday, July 4, 2016 4:07 AM

All replies

  • User227171 posted

    I also need to do this in Xamarin.Forms. I have an absolute layout that I store labels in. I need them to go at specific locations which requires me to get the width/height at runtime based on the text/Font. How can this be achieved? Something similar to the graphics.MeasureString would be optimal.

    Friday, July 1, 2016 5:30 PM
  • User125713 posted

    @JeffreyVoigt you can override the Measure function of the parent layout (create a custom layout similar to AbsoluteLayout) and call measure for the individual labels in that phase. However, that might be overkill depending on what exactly you're trying to achieve.

    Sunday, July 3, 2016 3:39 AM
  • User89714 posted

    I have a similar requirement. I have a number of fixed-size Views on a row, but in the space remaining what to put a timer (as a Label) in HH:MM:SS format. If the screen width cannot fit the whole of that in, I want it to fallback to just HH:MM , or even just HH if it cannot fit HH:MM in.

    Given a FontFamily, FontSize and FontAttributes, I'd be after a method that calculates the horizontal text extent for the text that would go in a particular View (most important being a Label, but it would be good if it worked for Button too).

    I do have workarounds for my particular scenario, but a method that gets the horizontal text extent, that works across platforms, would be the ideal.

    An alternative (which I know Xamarin have been asked for previously) is to have an API that specifies that the FontSize should be set automatically such that the specified Text fits within the Width available using the largest font that results in the text fitting.

    Sunday, July 3, 2016 11:29 AM
  • User167365 posted

    Hey Guys i sorted out a solution long back !!! My bad that i did not post the answer.

    You can achieve the requirement by using the concept of Dependency Services. You declare an interface in the PCL project where you expose a method to calculate the text length. You can implement this interface in the Forms android,iOS and Windows projects.

    You pass the text to the individual platform specific implementation, where you create a equivalent view ( TextView for Android, UILabel for iOS etc) and set the text as the text of the view and then measure it using native codes. Please refer the code snippets incase my description is unclear.

    PCL INTERFACE DECLARATION

    public interface CalculateTextWidth { double calculateWidth (string text); }

    ANDROID IMPLEMENTATION

    `public class CalculateTextWidthAndroid : CalculateTextWidth { public CalculateTextWidthAndroid () {}

            public double calculateWidth (string text)
            {
                Rect bounds = new Rect();
                TextView textView = new TextView(Forms.Context);
                textView.Paint.GetTextBounds(text, 0, text.Length, bounds);
                var length = bounds.Width();           
                return length / Resources.System.DisplayMetrics.ScaledDensity;
            }
    }`
    

    iOS IMPLEMENTATION

    `public class CalculateTextWidthiOS : CalculateTextWidth { UILabel uiLabel ; CGSize length; public CalculateTextWidthiOS () { }

        public double calculateWidth (string text)
        {
            uiLabel = new UILabel ();
            uiLabel.Text = text;
            length = uiLabel.Text.StringSize (uiLabel.Font);
            return length.Width;
        }
    }`
    

    WINDOWS PHONE IMPLEMENTATION `public class CalculateTextWidthWinPhone : CalculateTextWidth { public CalculateTextWidthWinPhone() {}

        public double calculateWidth(string text)
        {
            var textBlock = new TextBlock() { FontSize = 12 };
            textBlock.Text = text;
            var parentBorder = new Border { Child = textBlock };
            textBlock.MaxHeight = 50;
            textBlock.MaxWidth = double.PositiveInfinity;
            parentBorder.Measure(new System.Windows.Size(textBlock.MaxWidth, textBlock.MaxHeight));
            parentBorder.Child = null;
            return parentBorder.DesiredSize.Width;
    
       }
    }`
    

    WinRT IMPLEMENTATION public double calculateWidth(string text) { var textBlock = new TextBlock() { FontSize = 12 }; textBlock.Text = text; var parentBorder = new Border { Child = textBlock }; textBlock.MaxHeight = 50; textBlock.MaxWidth = double.PositiveInfinity; parentBorder.Measure(new System.Windows.Size(textBlock.MaxWidth, textBlock.MaxHeight)); parentBorder.Child = null; return parentBorder.DesiredSize.Width; }

    Please leave a comment in case of any queries

    Regards, Vimal Prabhu

    • Marked as answer by Anonymous Thursday, June 3, 2021 12:00 AM
    Monday, July 4, 2016 4:07 AM
  • User89714 posted

    @Vimal.4745 - Many thanks. When I have time, I'll tweak it so that this uses a FontSize that is passed in, rather than a hard-coded size, but this is a great starting point.

    Monday, July 4, 2016 8:59 AM
  • User295648 posted

    WinRT IMPLEMENTATION public double calculateWidth(string text) { var textBlock = new TextBlock() { FontSize = 12 }; textBlock.Text = text; var parentBorder = new Border { Child = textBlock }; textBlock.MaxHeight = 50; textBlock.MaxWidth = double.PositiveInfinity; parentBorder.Measure(new System.Windows.Size(textBlock.MaxWidth, textBlock.MaxHeight)); parentBorder.Child = null; return parentBorder.DesiredSize.Width; }

    Please leave a comment in case of any queries

    Regards, Vimal Prabhu

    Thanks Vimal but I am facing some problems in implementing that function. Some how the function is not returning correct values for height. It is always returning height for one line unless there is carriage return in the text. I have implemented it like this

    private int MeasureTextSize(string text, double width,Xamarin.Forms.Font font)
            {
                var textBlock = new TextBlock();
                textBlock.ApplyFont(font);
                textBlock.Text = text;
                var parentBorder = new Border { Child = textBlock };
                textBlock.MaxHeight = double.PositiveInfinity;
                textBlock.MaxWidth = width;
                parentBorder.Measure(new Size(textBlock.MaxWidth, textBlock.MaxHeight));
                parentBorder.Child = null;
                return (int)parentBorder.DesiredSize.Height;
    
            }
    

    Can you please help

    Tuesday, February 28, 2017 9:59 AM
  • User295648 posted

    WinRT IMPLEMENTATION public double calculateWidth(string text) { var textBlock = new TextBlock() { FontSize = 12 }; textBlock.Text = text; var parentBorder = new Border { Child = textBlock }; textBlock.MaxHeight = 50; textBlock.MaxWidth = double.PositiveInfinity; parentBorder.Measure(new System.Windows.Size(textBlock.MaxWidth, textBlock.MaxHeight)); parentBorder.Child = null; return parentBorder.DesiredSize.Width; }

    Thanks Vimal. I have implemented your code in windows RT but I am facing some problems in getting the desired results for height. I have implemented this code

    private int MeasureTextSize(string text, double width,Xamarin.Forms.Font font)
            {
                var textBlock = new TextBlock();
                textBlock.ApplyFont(font);
                textBlock.Text = text;
                var parentBorder = new Border { Child = textBlock };
                textBlock.MaxHeight = double.PositiveInfinity;
                textBlock.MaxWidth = width;
                parentBorder.Measure(new Size(textBlock.MaxWidth, textBlock.MaxHeight));
                parentBorder.Child = null;
                return (int)parentBorder.DesiredSize.Height;
    
            }
    

    I am not getting correct height. I am always getting height for one line unless there is carriage return in the text

    Tuesday, February 28, 2017 10:02 AM
  • User295648 posted

    @HabibAli_Subhan said:

    WinRT IMPLEMENTATION public double calculateWidth(string text) { var textBlock = new TextBlock() { FontSize = 12 }; textBlock.Text = text; var parentBorder = new Border { Child = textBlock }; textBlock.MaxHeight = 50; textBlock.MaxWidth = double.PositiveInfinity; parentBorder.Measure(new System.Windows.Size(textBlock.MaxWidth, textBlock.MaxHeight)); parentBorder.Child = null; return parentBorder.DesiredSize.Width; }

    Thanks Vimal. I have implemented your code in windows RT but I am facing some problems in getting the desired results for height. I have implemented this code

    private int MeasureTextSize(string text, double width,Xamarin.Forms.Font font)
            {
                var textBlock = new TextBlock();
                textBlock.ApplyFont(font);
                textBlock.Text = text;
                var parentBorder = new Border { Child = textBlock };
                textBlock.MaxHeight = double.PositiveInfinity;
                textBlock.MaxWidth = width;
                parentBorder.Measure(new Size(textBlock.MaxWidth, textBlock.MaxHeight));
                parentBorder.Child = null;
                return (int)parentBorder.DesiredSize.Height;
    
            }
    

    I am not getting correct height. I am always getting height for one line unless there is carriage return in the text

    Problem resolved just insert textBlocktb.TextWrapping = TextWrapping.Wrap;

    Tuesday, February 28, 2017 10:34 AM
  • User350813 posted

    I want to know how to measure textview height .Please answer to me.

    Friday, November 24, 2017 6:48 AM
  • User389556 posted

    I like @Vimal.4745's answer, but there are several things I am having trouble figuring out how to do. First, I need to calculate the size in the Xamarin.Forms project, but I need a TextView in your method. This makes since, and I understand why, but I would like to know if there is a way to use the Renderer to convert my Label to a TextView to be used in the measurer (so that I do not need to manually set all the properties by hand)? My Label(s) use Style(s) which are located in my Xamarin.Forms project, and the Style(s) obviously target Label(s) (not TextView(s)) I think my basic question is how do I use your code from my Xamarin.Forms project? Thanks.

    Wednesday, December 16, 2020 3:34 AM
  • User399043 posted

    Some things have changed since the original post, so here's the Android code as of 2021:

        public double CalculateWidth(string text)
        {
            Android.Graphics.Rect bounds = new Android.Graphics.Rect();
            TextView textView = new TextView(Android.App.Application.Context);
            textView.Paint.GetTextBounds(text, 0, text.Length, bounds);
            var length = bounds.Width();
            return length / Android.Content.Res.Resources.System.DisplayMetrics.ScaledDensity;
        }
    
    Tuesday, January 26, 2021 4:52 PM