Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I add a disclosure indicator / checkmark to my view cell in Xamarin.Forms Android?

Here's what I have implemented so far for iOS:

using System;
using Xamarin.Forms;

namespace Japanese
{
    public class ExtCheckedTextCell: TextCell
    {

        public static readonly BindableProperty IsCheckedProperty =
        BindableProperty.Create(
                "IsChecked", typeof(bool), typeof(ExtCheckedTextCell),
            defaultValue: false);

        public bool IsChecked
        {
            get { return (bool)GetValue(IsCheckedProperty); }
            set { SetValue(IsCheckedProperty, value); }
        }

    }
}

and my renderer looks like this:

using System;
using System.ComponentModel;
using System.Diagnostics;
using Japanese;
using Japanese.iOS;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;

[assembly: ExportRenderer(typeof(ExtCheckedTextCell), typeof(ExtCheckedTextCellRenderer))]
namespace Japanese.iOS
{

    public class ExtCheckedTextCellRenderer : TextCellRenderer
    {
        public override UITableViewCell GetCell(Cell item, UITableViewCell reusableCell, UITableView tv)
        {
            var nativeCell = base.GetCell(item, reusableCell, tv);

            if (item is ExtCheckedTextCell formsCell)
            {
                SetCheckmark(nativeCell, formsCell);
                SetTap(nativeCell, formsCell);
            }

            return nativeCell;
        }

        protected override void HandlePropertyChanged(object sender, PropertyChangedEventArgs args)
        {
            base.HandlePropertyChanged(sender, args);

            System.Diagnostics.Debug.WriteLine($"HandlePropertyChanged {args.PropertyName}");

            var nativeCell = sender as CellTableViewCell;
            if (nativeCell?.Element is ExtCheckedTextCell formsCell)
            {
                if (args.PropertyName == ExtCheckedTextCell.IsCheckedProperty.PropertyName)
                    SetCheckmark(nativeCell, formsCell);

            }
        }

        void SetCheckmark(UITableViewCell nativeCell, ExtCheckedTextCell formsCell)
        {
            if (formsCell.IsChecked)
                nativeCell.Accessory = UITableViewCellAccessory.Checkmark;
            else
                nativeCell.Accessory = UITableViewCellAccessory.None;
        }

}

For reference here's the XAML where it is used:

<TableSection>
   <local:CheckedTextCell Text="{Binding [6].Name}" IsChecked="{Binding [6].IsSelected}" Tapped="atiSelectValue" />
   <local:CheckedTextCell Text="{Binding [7].Name}" IsChecked="{Binding [7].IsSelected}" Tapped="atiSelectValue" />
   <local:CheckedTextCell Text="{Binding [8].Name}" IsChecked="{Binding [8].IsSelected}" Tapped="atiSelectValue" />
</TableSection>

Does anyone have any ideas how can I implement this in Android using a custom renderer or if it is even possible to do it?

Here's an example (not mine) of what it looks like in iOS. What I am hoping for is the Android can show a similar tick mark on the right side.

enter image description here

like image 721
Alan2 Avatar asked Jul 07 '18 09:07

Alan2


People also ask

What is label in xamarin?

The Label view is used for displaying text, both single and multi-line. Labels can have text decorations, colored text, and use custom fonts (families, sizes, and options).

How do I add a border to a label in xamarin?

Despite there already being an answer, the solution I found allows you to choose which borders you specifically want to show and how much. Show activity on this post. In xamarin forms shared project's xaml file use ExLabel instead of Label , you will see a border on it.

What is VIEW cell in xamarin forms?

Gets a value that indicates whether the cell has at least one menu item in its ContextActions list property. (Inherited from Cell)


2 Answers

Custom Renderer

You can build a custom renderer in Android (although, I think an easier approach is to create a custom ViewCell):

using System.ComponentModel;
using Android.Content;
using Android.Views;
using Android.Widget;
using Sof;
using Sof.Droid;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
using AView = Android.Views.View;

[assembly: ExportRenderer(typeof(ExtCheckedTextCell), typeof(ExtCheckedTextCellRenderer))]

namespace Sof.Droid
{
    public class ExtCheckedTextCellRenderer : TextCellRenderer
    {
        public const string CheckedText = "✓";

        private TextView Check { get; set; }

        protected override AView GetCellCore(Cell item, AView convertView, ViewGroup parent, Context context)
        {
            var view = base.GetCellCore(item, convertView, parent, context) as BaseCellView;

            if (this.Check == null)
            {
                this.Check = new TextView(context);
                this.Check.Gravity = GravityFlags.Center;

                using (var lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WrapContent, ViewGroup.LayoutParams.MatchParent))
                {
                    view.AddView(this.Check, lp);
                }

                var paddingRight = context.Resources.GetDimension(Resource.Dimension.abc_list_item_padding_horizontal_material);
                view.SetPadding(view.PaddingLeft, view.PaddingTop, (int)paddingRight, view.PaddingBottom);
            }

            return view;
        }

        protected override void OnCellPropertyChanged(object sender, PropertyChangedEventArgs args)
        {
            base.OnCellPropertyChanged(sender, args);

            if (args.PropertyName.Equals(ExtCheckedTextCell.IsCheckedProperty.PropertyName) && 
                sender is ExtCheckedTextCell extCheckedTextCell && this.Check != null)
            {
                this.Check.Text = extCheckedTextCell.IsChecked ? CheckedText : string.Empty;
            }
        }
    }
}

Custom Xamarin.Forms.ViewCell (no platform-specific code needed)

For a simple layout like you want (label and checkmark), a custom ViewCell seems more appropriate and allows direct control over the style.

ExtCheckedTextCell2.xaml

<?xml version="1.0" encoding="UTF-8"?>
<ViewCell xmlns="http://xamarin.com/schemas/2014/forms" 
          xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
          x:Class="Sof.ExtCheckedTextCell2"
          x:Name="this">
    <ViewCell.View>
        <StackLayout Orientation="Horizontal"
                     Padding="12, 0">
            <Label HorizontalOptions="FillAndExpand"
                   Text="{Binding Text, Source={x:Reference this}}"
                   VerticalTextAlignment="Center" />
            <Label IsVisible="{Binding IsChecked, Source={x:Reference this}}"
                   HorizontalOptions="End"
                   Text="✓" 
                   VerticalTextAlignment="Center"/>
        </StackLayout>
    </ViewCell.View>
</ViewCell>

ExtCheckedTextCell2.xaml.cs

public partial class ExtCheckedTextCell2 : ViewCell
{
    public static readonly BindableProperty IsCheckedProperty =
        BindableProperty.Create(
            nameof(IsChecked),
            typeof(bool),
            typeof(ExtCheckedTextCell2),
            default(bool));

    public static readonly BindableProperty TextProperty =
        BindableProperty.Create(
            nameof(Text),
            typeof(string),
            typeof(ExtCheckedTextCell2),
            default(string));

    public ExtCheckedTextCell2()
    {
        InitializeComponent();
    }

    public bool IsChecked
    {
        get { return (bool)GetValue(IsCheckedProperty); }
        set { SetValue(IsCheckedProperty, value); }
    }

    public string Text
    {
        get { return (string)GetValue(TextProperty); }
        set { SetValue(TextProperty, value); }
    }

    protected override void OnTapped()
    {
        base.OnTapped();
        this.IsChecked = !this.IsChecked;
    }
}

Result

    <TableView>

        <TableSection Title="Custom Renderer">
           <local:ExtCheckedTextCell Text="Test1" Tapped="Handle_Tapped" />
           <local:ExtCheckedTextCell Text="Test2" Tapped="Handle_Tapped" />
           <local:ExtCheckedTextCell Text="Test3" Tapped="Handle_Tapped" />
        </TableSection>

        <TableSection Title="Custom Xamarin.Forms ViewCell">
           <local:ExtCheckedTextCell2 Text="Test1" />
           <local:ExtCheckedTextCell2 Text="Test2" />
           <local:ExtCheckedTextCell2 Text="Test3" />
        </TableSection>

    </TableView>

enter image description here

like image 104
gannaway Avatar answered Nov 06 '22 10:11

gannaway


But you can also do it in xaml ?

This is a xaml only solution :) should work for Android and Ios .

.xaml

<?xml version="1.0" encoding="utf-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" 
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
             x:Class="StackoverflowQ.Views.MainPage" 
             Title="Driving  & Navigation">
    <ContentPage.Resources>
    </ContentPage.Resources>
    <ScrollView>
        <StackLayout>
            <StackLayout x:Name="Header" BackgroundColor="#efeff4" HorizontalOptions="FillAndExpand" HeightRequest="30" Padding="10">
                <Label Text="NAVIGATION VOICE VOLUME" Margin="0, 0, 0, 5" VerticalOptions="EndAndExpand" />
            </StackLayout>
            <StackLayout Orientation="Horizontal" Padding="10">
                <Label Text="No Voice" TextColor="Black" />
                <Image Source="checkboxchecker.png" IsVisible="{Binding IsCheckBoxVisible}" HorizontalOptions="EndAndExpand" />
                <StackLayout.GestureRecognizers>
                    <TapGestureRecognizer Command="{Binding TapCheckBoxCommand}" NumberOfTapsRequired="1" />
                </StackLayout.GestureRecognizers>
            </StackLayout>
            <BoxView HeightRequest="1" HorizontalOptions="FillAndExpand" BackgroundColor="#efeff4" />
        </StackLayout>
    </ScrollView>
</ContentPage>

ViewModel

namespace StackoverflowQ.ViewModels
{
    public class MainPageViewModel : ViewModelBase
    {
        public DelegateCommand TapCheckBoxCommand { get; set; }

        private bool _isCheckBoxVisible;
        public bool IsCheckBoxVisible
        {
            get => _isCheckBoxVisible;
            set => SetProperty(ref _isCheckBoxVisible, value);
        }

        public MainPageViewModel(INavigationService navigationService)
            : base(navigationService)
        {
            Title = "Main Page";

            TapCheckBoxCommand = new DelegateCommand(TapCheckBoxSelected);
        }

        public void TapCheckBoxSelected()
        {
            IsCheckBoxVisible = !IsCheckBoxVisible;
        }
    }
}

enter image description here

like image 27
LeRoy Avatar answered Nov 06 '22 08:11

LeRoy