【问题标题】:How can I add a disclosure indicator / checkmark to my view cell in Xamarin.Forms Android?如何在 Xamarin.Forms Android 中向我的视图单元格添加披露指示器/复选标记?
【发布时间】:2018-07-20 14:24:46
【问题描述】:

这是我迄今为止为 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); }
        }

    }
}

我的渲染器看起来像这样:

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;
        }

}

这里是使用它的 XAML 供参考:

<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>

有没有人知道如何在 Android 中使用自定义渲染器实现这一点,或者甚至可以做到这一点?

这是一个例子(不是我的)它在 iOS 中的样子。我希望 Android 可以在右侧显示类似的刻度线。

【问题讨论】:

  • 你能否展示一个屏幕截图/gif,说明它在 iOS 上的外观或预期的最终结果
  • 我添加了一张图片
  • 您是否尝试过使用 android 示例来自定义 viewcells 渲染器? github.com/xamarin/xamarin-forms-samples/blob/master/…
  • 嗨 Hichame,我认为该样本可能是我需要的。也许有人会使用它作为解决方案来编写答案。我会拭目以待。

标签: xamarin xamarin.forms


【解决方案1】:

自定义渲染器

您可以在 Android 中构建自定义渲染器(不过,我认为更简单的方法是创建自定义 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;
            }
        }
    }
}

自定义 Xamarin.Forms.ViewCell(不需要特定于平台的代码)

对于您想要的简单布局(标签和复选标记),自定义ViewCell 似乎更合适,并允许直接控制样式。

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;
    }
}

结果

    <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>

【讨论】:

  • 这确实是正确的答案。 Xamarin 的方式根本不是使用自定义渲染器,而是像 gannaway 那样使用自定义视图单元格。
【解决方案2】:

但是你也可以在 xaml 中做到这一点?

这是一个仅限 xaml 的解决方案 :) 应该适用于 Android 和 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>

视图模型

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;
        }
    }
}

【讨论】:

  • 感谢 LeRoy,我将对此进行测试,并查看其他人是否有其他解决方案。由于 iOS 有一个复选标记功能,我也想看看其他人想出的 Android 方面是否有任何东西。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-23
  • 2012-07-09
  • 2011-10-24
  • 2018-10-20
  • 1970-01-01
相关资源
最近更新 更多