Xamarin 形成 ViewCell 滑动以显示按钮

Xamarin Forms ViewCell Swipe to Show Buttons

tl;dr:如何使用滑动来显示 Xamarin Forms 中的按钮,例如 iOS 邮件应用程序

我正在尝试为类似于 iOS 邮件的 UI 的 Xamarin Forms iOS 应用实现 滑动以显示按钮 应用程序或此 https://components.xamarin.com/view/swtableviewcell。在我发现的许多其他示例中,该组件非常适合 iOS 本机实现,但我需要通过 Xamarin 表单显示此 UI。

目前我有一个像这样的自定义滑动手势识别器:

    [assembly: ExportRenderer(typeof(SwipeViewCell), typeof(SwipeIosRenderer))]

namespace MyApp.iOS.Renderers
   {
    public class SwipeIosRenderer : ViewCellRenderer
       {


    UISwipeGestureRecognizer swipeRightGestureRecognizer;
    UISwipeGestureRecognizer swipeLeftGestureRecognizer;

    protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
    {
        base.OnElementChanged(e);


        swipeRightGestureRecognizer = new UISwipeGestureRecognizer(() => UpdateRight()) { Direction = UISwipeGestureRecognizerDirection.Right };
        swipeLeftGestureRecognizer = new UISwipeGestureRecognizer(() => UpdateLeft()) { Direction = UISwipeGestureRecognizerDirection.Left };

        if (e.NewElement == null)
        {

            if (swipeRightGestureRecognizer != null)
            {
                this.RemoveGestureRecognizer(swipeRightGestureRecognizer);
            }
            if (swipeLeftGestureRecognizer != null)
            {
                this.RemoveGestureRecognizer(swipeLeftGestureRecognizer);
            }
        }

        if (e.OldElement == null)
        {

            this.AddGestureRecognizer(swipeRightGestureRecognizer);
            this.AddGestureRecognizer(swipeLeftGestureRecognizer);                
        }

    }

    private void UpdateLeft()
    {

        Console.WriteLine("Left swipe");

    }
    private void UpdateRight()
    {

        Console.WriteLine("Right swipe");

    }
}

绑定到列表中的视单元。现在我可以识别 "swipe" 手势,我需要有关如何实际移动视图单元格并显示按钮的帮助,就像我上面给出的示例一样?

如果能够在视图中执行此操作会很棒 XAML 但我对任何事情都持开放态度。我有一个 UpdateLeft 和 UpdateRight 函数,如果可以使用的话,它们也会在相应的滑动动作上被调用吗?

**编辑:我需要对左右滑动都执行此操作。 ContextActions 只提供左滑功能。

希望这是有道理的!

Context Actions 适合你吗?我没有在其他平台上尝试过,但在 iOS 上它会创建一个滑动菜单,就像邮件应用程序一样。您应该能够使用 XAML 并绑定到命令属性。

编辑: 由于您阐明了您需要 ContextActions 中不存在的左侧和右侧滑动按钮,因此您可以利用已经具有所需行为的现有 SWTableViewCell 组件并将其调整为 Xamarin.Forms.

iOS渲染器:

public class SwipeIosRenderer : TextCellRenderer
{

static NSString rid = new NSString("SWTableViewCell");

public override UITableViewCell GetCell(Cell item, UITableViewCell reusableCell, UITableView tv)
{
    var forms_cell = (SwipeCell)item;

    SWTableViewCell native_cell = reusableCell as SWTableViewCell;
    if (native_cell == null)
    {
        native_cell = new SWTableViewCell(UITableViewCellStyle.Default, rid);

        if (forms_cell != null)
        {
            var cellDelegate = new CellDelegate(forms_cell);
            native_cell.Delegate = cellDelegate;

            if (forms_cell.LeftContextActions != null)
            {
                var left = new NSMutableArray();
                foreach (var btn in forms_cell.LeftContextActions)
                {
                    AddButton(left, btn);
                }
                native_cell.LeftUtilityButtons = NSArray.FromArray<UIButton>(left);
            }

            if (forms_cell.RightContextActions != null)
            {
                var right = new NSMutableArray();
                foreach (var btn in forms_cell.RightContextActions)
                {
                    AddButton(right, btn);
                }
                native_cell.RightUtilityButtons = NSArray.FromArray<UIButton>(right);
                }
            }
            native_cell.TextLabel.Text = forms_cell.Text;
    }
    var fs = forms_cell.ImageSource as FileImageSource;
    if (fs != null)
    {
        native_cell.ImageView.Image = UIImage.FromBundle(fs.File);
    }
    return native_cell;
}
void AddButton(NSMutableArray array,Button btn){
    if (!String.IsNullOrEmpty(btn.Image?.File))
    {
        array.AddUtilityButton(btn.BorderColor.ToUIColor(), UIImage.FromBundle(btn.Image.File));
    }
    else
    {
        array.AddUtilityButton(btn.BorderColor.ToUIColor(), btn.Text);
    }
}

public class CellDelegate : SWTableViewCellDelegate
{
    SwipeCell forms_cell;

    public CellDelegate(SwipeCell forms_cell)
    {
        this.forms_cell = forms_cell;
    }

    public override void DidTriggerLeftUtilityButton(SWTableViewCell cell, nint index)
    {
        if (forms_cell.LeftContextActions.Count > index)
        {
            var c = forms_cell.LeftContextActions[(int)index];
            var cmd = c.Command;
            if (cmd != null)
            {
                cmd.Execute(c.CommandParameter);
            }
        }
    }

    public override void DidTriggerRightUtilityButton(SWTableViewCell cell, nint index)
    {
        if (forms_cell.RightContextActions.Count > index)
        {
            var c = forms_cell.RightContextActions[(int)index];
            var cmd = c.Command;
            if (cmd != null)
            {
                cmd.Execute(c.CommandParameter);
            }
        }
    }
}

示例XAML:

<ListView x:Name="SwipeList">
        <ListView.ItemTemplate>
            <DataTemplate>

            <test:SwipeCell Text="{Binding Data}" ImageSource="{Binding Image}">
                    <test:SwipeViewCell.LeftContextActions>
                        <Button Text="L1" Command="{Binding LeftAction}" BorderColor="Aqua"/>
                        <Button Command="{Binding LeftAction2}" BorderColor="Gray" Image="xamarin.png"/>
                    </test:SwipeViewCell.LeftContextActions>
                    <test:SwipeViewCell.RightContextActions>
                        <Button Text="R1" Command="{Binding RightAction}" BorderColor="Blue" />
                        <Button Text="R2" Command="{Binding RightAction2}" BorderColor="Purple" />
                    </test:SwipeViewCell.RightContextActions>
                </test:SwipeViewCell>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>

后面的示例代码

public class MyListItem
{
    Page page;
    public MyListItem(Page page)
    {
        this.page = page;
        this.LeftAction= new Command(() => this.page.DisplayAlert("Left 1", this.Data, "OK"));
        this.LeftAction2= new Command(() => this.page.DisplayAlert("Left 2", this.Data, "OK"));
        this.RightAction= new Command(() => this.page.DisplayAlert("Right 1", this.Data, "OK"));
        this.RightAction2= new Command(() => this.page.DisplayAlert("Right 2", this.Data, "OK"));
    }
    public string Image{ get; set; }
    string data;
    public string Data
    {
        get
        {
            return data;
        }
        set
        {
            data = value;
        }
    }
    ICommand leftAction;
    public ICommand LeftAction
    {
        get
        {
            return leftAction;
        }
        set
        {
            leftAction = value;
        }
    }
    ICommand leftAction2;
    public ICommand LeftAction2
    {
        get
        {
            return leftAction2;
        }
        set
        {
            leftAction2 = value;
        }
    }
    ICommand rightAction;
    public ICommand RightAction
    {
        get
        {
            return rightAction;
        }
        set
        {
            rightAction = value;
        }
    }
    ICommand rightAction2;
    public ICommand RightAction2
    {
        get
        {
            return rightAction2;
        }
        set
        {
            rightAction2 = value;
        }
    }
    public override string ToString()
    {
        return this.Data;
    }
    }
    public TestPage()
    {
        InitializeComponent();
        this.SwipeList.ItemsSource = new List<MyListItem>(){
            new MyListItem(this){Data="A"},
            new MyListItem(this){Data="B", Image="xamarin.png"},
            new MyListItem(this){Data="C"},
            new MyListItem(this){Data="D"},
        };
    }

上下文操作并不是我的客户想要的。滑动时没有出现行菜单。当他们按住行时出现,菜单出现在屏幕顶部。

我能够使用新的 Xamarin.Forms 完成滑动行行为 SwipeView

将当前行传递给 CommandParameter,并在事件处理程序中使用它。

仅供参考:出于某种原因,SwipeView 的默认背景颜色为白色,您可以用其他颜色覆盖它以匹配您的主题。

Xaml:

            <ListView Margin="-20,0,0,0" x:Name="photosListView" ItemSelected="OnItemSelected" VerticalOptions="FillAndExpand" SeparatorColor="Gray" VerticalScrollBarVisibility="Default" HasUnevenRows="true"  SeparatorVisibility="Default" Background="{StaticResource PrimaryDark}">
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <ViewCell>
                            <SwipeView BackgroundColor="{StaticResource PrimaryDark}" >
                                <SwipeView.RightItems>
                                    <SwipeItems>
                                        <SwipeItem Text="Delete" BackgroundColor="LightPink" Clicked="OnDeleteRow" CommandParameter="{Binding .}" />
                                    </SwipeItems>
                                </SwipeView.RightItems>
                                <Grid>
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition Width="Auto" />
                                        <ColumnDefinition Width="*" />
                                    </Grid.ColumnDefinitions>

                                    <StackLayout Orientation="Horizontal">
                                        <CheckBox IsVisible="{Binding SelectEnabled}" Color="{StaticResource White}" IsChecked="{Binding Selected}" Margin="20,0,-15,0"  CheckedChanged="OnItemCheckedChanged" />
                                        <Grid WidthRequest="70" HeightRequest="50">
                                            <Grid.Margin>
                                                <OnPlatform x:TypeArguments="Thickness" Android="15,0,0,0" iOS="10,0,0,0" />
                                            </Grid.Margin>
                                            <Image Aspect="AspectFill"  Source="{Binding ThumbImageSource}" HorizontalOptions="Fill" />
                                        </Grid>
                                    </StackLayout>

                                    <StackLayout Grid.Column="1" Spacing="0" Padding="0" Margin="0,5,0,0">
                                        <Label Text="{Binding Photo.Description}" TextColor="{StaticResource TextColour}" FontSize="16" FontAttributes="Bold"  />
                                        <Label Text="{Binding DateTakenString}" TextColor="{StaticResource TextColour}" FontSize="14" />
                                    </StackLayout>
                                </Grid>
                            </SwipeView>
                        </ViewCell>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
        </StackLayout>

cs:

    public async void OnDeleteRow(object sender, EventArgs e)
    {
        if (await GetDeleteRowConfirmationFromUser())
        {
            SwipeItem si = sender as SwipeItem;
            PhotoListItem itemToDelete = si.CommandParameter as PhotoListItem;
            LocalDatabaseService db = new LocalDatabaseService();
            db.DeletePhoto(itemToDelete.Photo);
            _listItems.Remove(itemToDelete);
        }
    }