Thursday, July 19, 2018

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

Leave a Comment

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

2 Answers

Answers 1

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

Answers 2

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

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment