Recently I have come across a business need where I have to show strikethrough text in the Entry of Xamarin Forms. Now there is a Text decoration property for strikethrough in Label, But there is no such property that exists for Entry. Now we have an entry like this,
But we need to show a strikethrough over sddad. There are some resources that say to use effects or Unicode’s strikethrough character set. But it does not fulfill our needs. Does anybody know how to implement this so that we can change the text to have a strikethrough via a property binding?
Any help will be greatly appreciated.
CodePudding user response:
Whenever you want custom UI behaviour in Xamarin.Forms that is not exposed through the Forms API, you will need to go down to the platform level.
The strikethrough text can be achieved using any of: CustomRenderer
, Effect
, Behaviour
.
Below is an example of a platform effect that will strikethrough the whole text:
Define An Effect
In your cross platform project create a new RoutingEffect
:
using Xamarin.Forms;
namespace StrikethroughEntry.Effects
{
public class StrikethroughEntryEffect : RoutingEffect
{
public StrikethroughEntryEffect()
: base("StrikethroughEntry.Effects.StrikethroughEntryEffect")
{
}
}
}
Implement On iOS
Somewhere in your iOS project create a PlatformEffect
using Foundation;
using StrikethroughEntry.Effects;
using StrikethroughEntry.iOS;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
[assembly: ResolutionGroupName("StrikethroughEntry.Effects")]
[assembly: ExportEffect(typeof(iOSStrikethroughEntryEffect), nameof(StrikethroughEntryEffect))]
namespace StrikethroughEntry.iOS
{
public class iOSStrikethroughEntryEffect : PlatformEffect
{
private static NSNumber _strikethroughStyle => new NSNumber((int)NSUnderlineStyle.Single);
private string _originalText;
protected override void OnAttached()
{
var textField = Control as UITextField;
if (textField is null)
return;
_originalText = textField.Text;
var attributedText = new NSMutableAttributedString(textField.Text);
attributedText.AddAttribute(UIStringAttributeKey.StrikethroughStyle, _strikethroughStyle, new NSRange(0, textField.Text.Length));
textField.AttributedText = attributedText;
}
protected override void OnDetached()
{
var textField = Control as UITextField;
if (textField is null)
return;
textField.AttributedText = null;
textField.Text = _originalText;
}
}
}
This sample shows how you can cleanup the effect once it is no longer needed. The way attributed strings works on iOS would make is very easy to extend your strikethrough behaviour to target parts of the entry. Perhaps you only want to strikethrough specific words etc.
Implement On Android
Somewhere in your Android project create a PlatformEffect
:
using Android.Graphics;
using Android.Widget;
using StrikethroughEntry.Droid;
using StrikethroughEntry.Effects;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ResolutionGroupName("StrikethroughEntry.Effects")]
[assembly: ExportEffect(typeof(AndroidStrikethroughEntryEffect), nameof(StrikethroughEntryEffect))]
namespace StrikethroughEntry.Droid
{
public class AndroidStrikethroughEntryEffect : PlatformEffect
{
private PaintFlags _originalFlags;
protected override void OnAttached()
{
var editText = Control as EditText;
if (editText is null)
return;
_originalFlags = editText.PaintFlags;
editText.PaintFlags = PaintFlags.StrikeThruText;
}
protected override void OnDetached()
{
var editText = Control as EditText;
if (editText is null)
return;
editText.PaintFlags = _originalFlags;
}
}
}
This implementation would require updating if you wanted to strikethrough specific areas of your Entry
.
Consume The Effect
This example will be through xaml:
- Import the effects namespace:
xmlns:effects="clr-namespace:StrikethroughEntry.Effects"
- Add effect to target
Entry
:
<Entry Text="This entry has strikethrough">
<Entry.Effects>
<effects:StrikethroughEntryEffect />
</Entry.Effects>
</Entry>
Results
Now you have a lovely Entry
with strikethrough text!
Android | iOS |
---|---|