I am looking for a way to make parts of the text of a Label in Xamarin Forms clickable, performing different functions, and ideally have different formatting. I understand that a clickable Label is straightforward and can be done something like this:
Label label = new Label { Text = "Click me" };
label.Click += () => { label.Text = "Clicked"; };
Essentially, I'm looking to mimic behavior in an app that I've done in native Android. My app must work for Android and iOS and ideally UWP. In Android, CharSequence objects can be added to a TextView (the control similar to Label). In Android, I might create a CharSequence object like this:
Runnable doSomething; //equivalent to C# Action; assuming initialized somewhere
String myString = "My Clickable String"; //the clickable string
Spannable span = Spannable.Factory.getInstance().newSpannable(myString); //this is the clickable text to add to TextView
span.setSpan(new ClickableSpan() {
@Override
public void onClick(View v) {
doSomething.run(); //perform the action
}
@Override
public void updateDrawState(TextPaint ds) {
ds.setUnderlineText(true); //make underlined
ds.setColor(Color.rgb(color.r, color.g, color.b)); //change the color
ds.setFakeBoldText(true); //make it bold
ds.setTextSize((float) largeFont); //change the text size
}
}, 0, a.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //style and function for the entire string
As you can see, it performs a function and has style attributes. I can then add this to TextView (Spannable implements Spanned which implements CharSequence). I can add multiple CharSequences in addition to non-clickable Strings as I desire.
I'm hoping for a way that I can do this in Xamarin but I haven't found a solution yet. I've considered the possibility of custom renderers though I feel that a cross-platform solution would be preferable, if possible. I'm far less familiar with iOS but it seems that it's possible to add NSMutableAttributedString objects to a UILabel to similar effect. I've also seen the FancyLabel object. I'm not quite sure how I would do this for UWP as I really didn't find much in my research.
Any assistance would be very appreciated!
Just to provide an updated answer to this using Xamarin Forms 3.4 (and over). You can use the FormattedText
property of the Label
. There is an in-depth overview on how to use it over in the Xamarin Docs.
Fundamentally, it works like so:
<Label
LineBreakMode="WordWrap">
<Label.FormattedText>
<FormattedString>
<Span
Text="Red Bold, "
TextColor="Red"
FontAttributes="Bold" />
<Span
Text="default, "
Style="{DynamicResource BodyStyle}">
<Span.GestureRecognizers>
<TapGestureRecognizer Command="{Binding TapCommand}" />
</Span.GestureRecognizers>
</Span>
<Span
Text="italic small."
FontAttributes="Italic"
FontSize="Small" />
</FormattedString>
</Label.FormattedText>
</Label>
In the above, tapping on the text default
will execute TapCommand
.
This answer may be extremely after-the-fact but may help others in the future.
What I've done and tested is to use a grid with your string split up appropriately, say you want to change the behaviour of a word:
In your ViewModel/View:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/> //for first few words
<ColumnDefinition Width="Auto"/> //the target word
<ColumnDefinition Width="Auto"/> //the rest of the string
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/> //one row for one line of text
</Grid.RowDefinitions>
<Label Grid.Column="0" Grid.ColumnSpan="1" Grid.Row="0" Text="First part of string"/>
<Label Grid.Column="1" Grid.ColumnSpan="1" Grid.Row="0" Text="TARGET-WORD">
<Label.GestureRecognizers>
<TapGestureRecognizer Command="{Binding <YOUR_COMMAND>}"/>
</Label.GestureRecognizers>
</Label>
<Label Grid.Column="2" Grid.ColumnSpan="1" Grid.Row="0" Text="rest of the string"/>
</Grid>
This way you can isolate specific portions of grid and amend behaviour/aethetics (data triggers, styling, gestures). Remember that <Span></Span>
tags do not support all the features of a <Label></Label>
.
Clearly, in XAML you would need to know the position of the word, or if the string is dynamic, you could dynamically search for it and also construct your Grid in the code behind.
*Tested on Xamarin.Forms 2.3.4.247
Considering an example to answer this question which may help somebody in future,
Eg. i need to write "By signing up, you agree to the Terms of Services and Privacy Policy" with some formatting:
Rest part of the string should be simple.
Code in XAML:
`<Label Text="By signing up, you agree to the " Grid.Row="0"/>
<Label Text="Terms of Services" TextColor="DarkOrange" WidthRequest="150"
HorizontalOptions="End" Grid.Row="0">
<Label.GestureRecognizers>
<TapGestureRecognizer Tapped="TapGestureRecognizer_Tapped_Terms"/>
</Label.GestureRecognizers>
</Label>
<Label Text=" and " HorizontalOptions="End" Grid.Row="0" />
<Label Text="Privacy Policy" TextColor="DarkOrange" HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" Grid.Row="0">
<Label.GestureRecognizers>
<TapGestureRecognizer Tapped="TapGestureRecognizer_Tapped_Policy"/>
</Label.GestureRecognizers>
</Label>
`
Code in C# for tapped callbacks:
private void TapGestureRecognizer_Tapped_Terms(object sender, EventArgs e)
{
Navigation.PushAsync(new TermsofServicesPage());
}
private void TapGestureRecognizer_Tapped_Policy(object sender, EventArgs e)
{
Navigation.PushAsync(new PrivacyPolicyPage());
}
Different formattings of the string can be performed and works fine for cross platforms.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With