Dpedrinha
Dpedrinha

Reputation: 4230

How to create a clickable label to open an external url using external browser in Xamarin.Forms?

Isn't there anything like a LinkButton in Xamarin?

I want to create a label with the looks of an url link that once tapped opens the external browser.

I also need to know how to open the device's external browser (to open an specified url) in a Portable Project.

Thanks

Upvotes: 12

Views: 10175

Answers (3)

toumir
toumir

Reputation: 641

For Xamarin.Forms 3.2 and above

<Label>
    <Label.FormattedText>
        <FormattedString>
            <Span Text="{Binding Url, Mode=OneWay}" TextColor="Blue">
                <Span.GestureRecognizers>
                        <TapGestureRecognizer 
                            Command="{Binding TapCommand, Mode=OneWay}"
                            CommandParameter="https://www.xamarin.com"/>
                </Span.GestureRecognizers>
            </Span>
        </FormattedString>
    </Label.FormattedText>
</Label>

You may use commands with or without parameters, or just the tapped event.

Example :

<Label>
            <Label.FormattedText>
                <FormattedString>
                    <Span Text="Xamarin" TextColor="Blue">
                        <Span.GestureRecognizers>
                            <TapGestureRecognizer 
                                Command="{Binding TapCommand, Mode=OneWay}"
                                CommandParameter="https://www.xamarin.com"/>
                        </Span.GestureRecognizers>
                    </Span>
                </FormattedString>
            </Label.FormattedText>
        </Label>

in the ViewModel :

private ICommand _tapCommand;
public ICommand TapCommand =>
_tapCommand ?? (_tapCommand = new Command<string>(OpenUrl));

void OpenUrl(string url)
{
   Device.OpenUri(new Uri(url));
}

Upvotes: 0

dbr
dbr

Reputation: 61

Create a label that can display underlined (or use Xamarin Forms Labs ExtendedLabel):

using Xamarin.Forms;

public class ExtendedLabel : Label
{
    public static readonly BindableProperty IsUnderlinedProperty = BindableProperty.Create<ExtendedLabel, bool>(p => p.IsUnderlined, false);

    public bool IsUnderlined
    {
        get { return (bool)GetValue(IsUnderlinedProperty); }
        set { SetValue(IsUnderlinedProperty, value); }
    }

    // ...other custom properties

}

Handle the IsUnderlined property in your custom renderers:

public class ExtendedLabelRenderer : LabelRenderer
{
    protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
    {
        base.OnElementChanged(e);

        // ...
    }

    protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        base.OnElementPropertyChanged(sender, e);

        if (e.PropertyName == ExtendedLabel.IsUnderlinedProperty.PropertyName)
        {
            RefreshControl(Control);
        }
    }

    private void RefreshControl(UILabel control)
    {
        if (control == null) return;

        // Apply based on IsUnderlined property
        if (!string.IsNullOrEmpty(control.Text)) control.AttributedText = new NSMutableAttributedString(control.Text, underlineStyle: view.IsUnderlined ? NSUnderlineStyle.Single : NSUnderlineStyle.None);            

        // ...apply based on other custom properties
    }
}

Add your label control to YourPage.xaml and add a gesture recognizer to handle tap:

<controls:ExtendedLabel
    Text="View in browser"
    TextColor="Blue"
    IsUnderlined="True">
    <controls:ExtendedLabel.GestureRecognizers>
        <!--TODO:<TapGestureRecognizer Command="TapCommand" /> Couldn't do this for some reason so use Tapped handler-->
        <TapGestureRecognizer
            Tapped="OnOpenInBrowserTapGestureRecognizerTapped"
            NumberOfTapsRequired="1" />
    </controls:ExtendedLabel.GestureRecognizers>
</controls:ExtendedLabel>

Handle the tap in code behind YourPage.xaml.cs:

private void OnOpenInBrowserTapGestureRecognizerTapped(object sender, EventArgs args)
{
    var labelViewSender = (ExtendedLabel)sender;

    labelViewSender.Opacity = 0.6;
    labelViewSender.FadeTo(1);

    var viewModel = BindingContext as YourPageViewModel;
    if (viewModel == null) return;

    if (viewModel.NavigateToUrlCommand.CanExecute(null)) viewModel.NavigateToUrlCommand.Execute(null);
}

The view model:

public class YourPageViewModel : ViewModelBase
{
    public const string NavigateToUrlMessage = "NavigateToUrl";

    private string _url;
    public string Url
    {
        get { return _url; }
        set { SetProperty(ref _url, value); }
    }

    //...

    private Command _navigateToUrlCommand;
    public ICommand NavigateToUrlCommand
    {
        get { return _navigateToUrlCommand ?? (_navigateToUrlCommand = new Command(param => NavigateToUrl(), CanNavigateToUrl)); }
    }

    public bool CanNavigateToUrl(object parameter) => true;

    private void NavigateToUrl()
    {
        MessagingCenter.Send(this, NavigateToUrlMessage, Url);
    }

    //...
}

Subscribe to and handle the NavigateToUrlMessage message in the YourPage.xaml.cs code behind:

    protected override void OnAppearing()
    {
        MessagingCenter.Subscribe<YourPageViewModel, string>(this, YourPageViewModel.NavigateToUrlMessage, (sender, args) =>
        {
            var context = (BindingContext as YourPageViewModel);
            if (context == null) return;

            if (string.IsNullOrEmpty(args)) return;

            Device.BeginInvokeOnMainThread(() =>
            {
                Device.OpenUri(new Uri(args));
            });
        });

        //...

        base.OnAppearing();
    }

    protected override void OnDisappearing()
    {
        MessagingCenter.Unsubscribe<YourPageViewModel, string>(this, YourPageViewModel.NavigateToUrlMessage);

        //...

        base.OnDisappearing();
    }

Upvotes: 2

SushiHangover
SushiHangover

Reputation: 74209

The Xamarin.Forms way to open an URL string in the default mobile browser:

Device.OpenUri(new Uri("http://example.com"))

While a Forms' Label does not have a click event, you can add a TapGestureRecognizer so when the label is tapped it executes Device.OpenUri.

Example:

var myURLLabel = new Label
{
    Text = "https://xamarin.com"
};

myURLLabel.GestureRecognizers.Add(new TapGestureRecognizer
{
    Command = new Command(() => {
        Device.OpenUri(new Uri(myURLLabel.Text));
    })
});

Xamarin-Forms-Labs' ExtendedLabel allows you style a label's text as underlined....

Ref: https://github.com/XLabs/Xamarin-Forms-Labs/wiki/ExtendedLabel

Upvotes: 11

Related Questions