Skip to content

Instantly share code, notes, and snippets.

@alexrainman
Last active August 1, 2022 07:45
Show Gist options
  • Save alexrainman/82b00160ab32bef9e69dee6d460f44fa to your computer and use it in GitHub Desktop.
Save alexrainman/82b00160ab32bef9e69dee6d460f44fa to your computer and use it in GitHub Desktop.
Calculate Xamarin.Forms label height by amount of text
namespace YourNamespace
{
public interface ITextMeter
{
double MeasureTextSize(string text, double width, double fontSize, string fontName = null);
}
}
using System;
using Android.Widget;
using Android.Views;
using Android.Graphics;
using Android.Util;
using Android.Text;
using YourNamespace.Droid;
[assembly: Xamarin.Forms.Dependency(typeof(TextMeterImplementation))]
namespace YourNamespace.Droid
{
public class TextMeterImplementation : ITextMeter
{
private Typeface textTypeface;
//public static Xamarin.Forms.Size MeasureTextSize(string text, double width, double fontSize, string fontName = null)
public double MeasureTextSize(string text, double width, double fontSize, string fontName = null)
{
var textView = new TextView(global::Android.App.Application.Context);
textView.Typeface = GetTypeface(fontName);
textView.SetText(text, TextView.BufferType.Normal);
textView.SetTextSize(ComplexUnitType.Px, (float)fontSize);
int widthMeasureSpec = Android.Views.View.MeasureSpec.MakeMeasureSpec(
(int)width, MeasureSpecMode.AtMost);
int heightMeasureSpec = Android.Views.View.MeasureSpec.MakeMeasureSpec(
0, MeasureSpecMode.Unspecified);
textView.Measure(widthMeasureSpec, heightMeasureSpec);
//return new Xamarin.Forms.Size((double)textView.MeasuredWidth, (double)textView.MeasuredHeight);
return (double)textView.MeasuredHeight;
}
private Typeface GetTypeface(string fontName)
{
if (fontName == null)
{
return Typeface.Default;
}
if (textTypeface == null)
{
textTypeface = Typeface.Create(fontName, TypefaceStyle.Normal);
}
return textTypeface;
}
}
}
using System;
using Foundation;
using UIKit;
using System.Drawing;
using YourNamespace.iOS;
[assembly: Xamarin.Forms.Dependency(typeof(TextMeterImplementation))]
namespace YourNamespace.iOS
{
public class TextMeterImplementation : ITextMeter
{
//public static Xamarin.Forms.Size MeasureTextSize(string text, double width, double fontSize, string fontName = null)
public double MeasureTextSize(string text, double width, double fontSize, string fontName = null)
{
var nsText = new NSString(text);
var boundSize = new SizeF((float)width, float.MaxValue);
var options = NSStringDrawingOptions.UsesFontLeading | NSStringDrawingOptions.UsesLineFragmentOrigin;
if (fontName == null)
{
fontName = "HelveticaNeue";
}
var attributes = new UIStringAttributes {
Font = UIFont.FromName(fontName, (float)fontSize)
};
var sizeF = nsText.GetBoundingRect(boundSize, options, attributes, null).Size;
//return new Xamarin.Forms.Size((double)sizeF.Width, (double)sizeF.Height);
return (double)sizeF.Height + 5;
}
}
}
using YourNamespace.UWP;
using System;
using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
[assembly: Xamarin.Forms.Dependency(typeof(TextMeterImplementation))]
namespace YourNamespace.UWP
{
public class TextMeterImplementation : ITextMeter
{
public double MeasureTextSize(string text, double width, double fontSize, string fontName = null)
{
TextBlock tb = new TextBlock();
if (fontName == null)
{
fontName = "Segoe UI";
}
tb.TextWrapping = TextWrapping.Wrap;
tb.Text = text;
tb.FontFamily = new Windows.UI.Xaml.Media.FontFamily(fontName);
tb.FontSize = fontSize;
tb.Measure(new Size(width, Double.PositiveInfinity));
//Size actualSize = new Size();
//actualSize.Width = tb.ActualWidth;
//actualSize.Height = tb.ActualHeight;
return tb.DesiredSize.Height;
//return actualSize;
}
}
}
@lwinged
Copy link

lwinged commented Aug 18, 2016

Hello, I used TextMeterImplementation it works on iOS but on Android the height seems wrong.

I tested with a simple example :

<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
        xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
        xmlns:resources="clr-namespace:AuxiPress;assembly=AuxiPress"
        x:Class="AuxiPress.AlertView"
        HeightRequest="{Binding HeightContentView}"
        VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand"
        >

    <ContentView.Content>
        <StackLayout BackgroundColor="Blue" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
                <Label Text="{Binding CurrentText}" HeightRequest="{Binding Height}"
                        VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand"
                    FontFamily="Roboto-Regular"  FontSize="15" /> 
        </StackLayout>
    </ContentView.Content>
</ContentView>

// here
HeightContentView = Height

on iOS the contentView has the right size but not on Android.

I think the Android implementation doesn't work correctly. What do you think about it ?

Edit :
With this text :

CurrentText = "Quod cum ita sit, paucae domus studiorum seriis cultibus antea celebratae nunc ludibriis ignaviae torpentis exundant, vocali sonu, perflabili tinnitu fidium resultantes. denique pro philosopho cantor et in locum oratoris doctor artium ludicrarum accitur et bybliothecis sepulcrorum ritu in perpetuum clausis organa fabricantur hydraulica, et lyrae ad speciem carpentorum ingentes tibiaeque et histrionici gestus instrumenta non levia.";

On iOS :
XF Label Height -> 163
TextMeterImplementation Height - > 158
the text appears fully

On Android :
XF Label Height -> 96
TextMeterImplementation Height - > 96
the text doesn't appear fully

I dont know why on iOS we find 158 and on Android 96 for Height

Edit : Fixed for me
alexrainman/CarouselView#1 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment