Xamarin Forms Grid Boxview 滑动手势多 select

Xamarin Forms Grid Boxview swipe gesture multi select

我有一个简单的 Xamarin.Forms 页面,其中包含 BoxView 的网格布局。我希望能够通过滑动手势同时 select 这些框视图。我怎样才能做到这一点?

我想建立一种瓦片地图,这样 boxviews 更容易 select。我想轻松实现这一目标。只有滑动效果不是很好,因为只会 select 编辑“一个”框视图。

这是我目前拥有的:

XAML

    <ContentPage.Content>
        <Grid x:Name="pageGrid" RowSpacing="1" ColumnSpacing="1" VerticalOptions="Center" HorizontalOptions="Center">
            <Grid.RowDefinitions>
                <RowDefinition Height="*" />
                <RowDefinition Height="*" />
                <RowDefinition Height="*" />
                <RowDefinition Height="*" />
                <RowDefinition Height="*" />
                <RowDefinition Height="*" />
                <RowDefinition Height="*" />
                <RowDefinition Height="*" />
                <RowDefinition Height="*" />
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
        </Grid>
    </ContentPage.Content>

后面的代码:

public Page()
    {
        InitializeComponent();

        int columnIndex = 0;
        for (int rowIndex = 0; rowIndex <= 8; rowIndex++)
        {
            BoxView boxview = new BoxView { BackgroundColor = Color.White };
            SwipeGestureRecognizer swipeGestureRecognizer = new SwipeGestureRecognizer();
            swipeGestureRecognizer.Swiped += (sender, args) =>
            {
                if (boxview.BackgroundColor == Color.White)
                {
                    boxview.BackgroundColor = Color.Gray;
                }
                else if (boxview.BackgroundColor == Color.Gray)
                {
                    boxview.BackgroundColor = Color.White;
                }
            };

            swipeGestureRecognizer.Threshold = 1;
            swipeGestureRecognizer.Direction = SwipeDirection.Left | SwipeDirection.Right;
            
            TapGestureRecognizer tapGestureRecognizer = new TapGestureRecognizer();
            tapGestureRecognizer.Tapped += (sender, args) =>
            {
                if (boxview.BackgroundColor == Color.White)
                {
                    boxview.BackgroundColor = Color.Gray;
                }
                else if (boxview.BackgroundColor == Color.Gray)
                {
                    boxview.BackgroundColor = Color.White;
                }
            };
            
            boxview.GestureRecognizers.Add(swipeGestureRecognizer);
            boxview.GestureRecognizers.Add(tapGestureRecognizer);

            if (rowIndex == 4 && columnIndex == 3)
            {
                boxview.BackgroundColor = Color.Red;
            }

            pageGrid.Children.Add(boxview, columnIndex, rowIndex);

            if (rowIndex != 8) continue;
            if (columnIndex == 6) return;
            columnIndex += 1;
            rowIndex = -1;
        }
    }

现在每次滑动操作,只会select编辑一个框视图!

我试了一下这个,然后提出了一些想法,最后部分实现了。

我认为滑动手势不会让这项工作按照我认为您希望它工作的方式进行。看起来 Swipe 手势恰好触发一次,在手指离开屏幕的那一刻,对我来说这不是理想的体验,因为这意味着即使你能弄清楚总共有哪些框被滑动了(我我不确定是否可以这样做)他们都会等到你松开手指来改变颜色。

我刚刚想到的想法是使用平移手势,因为只要检测到运动,该手势就会非常频繁地触发。平移和滑动似乎都有一个约束,即一旦事件与单个框视图相关联,该事件就不会触发任何其他框的回调,即使您的手指经过其他框也是如此。但是,我认为如果使用平移手势就可以克服这个问题。平移手势会在每次触发时为您提供总的平移偏差,并且鉴于手势回调本身将在平移开始的框视图内不断触发(而不是在任何其他框中),这意味着您同时拥有初始位置和每个平移运动的总偏差。从理论上讲,您拥有完成这项工作所需的所有信息,但您需要对事件进行一些巧妙的处理。这可能会让人头疼,但如果你可以构建你的网格,让它足够聪明,知道每个 boxview 与其他 boxview 的关系,你可以在它们进入时映射出平移手势事件,并使特定的 boxviews 根据需要改变颜色。

编辑:应提问者的要求,我构建了一些示例代码来执行此操作。有必要重新添加单独的点击事件并根据您想要的逻辑使其正确地 "toggle" 而不仅仅是 select 。可能还需要进行其他调整,但这证明了这一概念。

    public Page()
    {
        InitializeComponent();

        var columnIndex = 0;
        for (var rowIndex = 0; rowIndex <= 8; rowIndex++)
        {
            var boxview = new BoxView { BackgroundColor = Color.White };
            var swipeGestureRecognizer = new PanGestureRecognizer();

            swipeGestureRecognizer.PanUpdated += (sender, args) =>
            {
                var boxView = (BoxView) sender;
                var panBaseBounds = boxView.Bounds;
                var eventX = panBaseBounds.X + args.TotalX;
                var eventY = panBaseBounds.Y + args.TotalY;
                foreach (var gridChild in pageGrid.Children)
                {
                    var testBounds = gridChild.Bounds;
                    if (testBounds.X <= eventX && eventX <= testBounds.X + testBounds.Width &&
                        testBounds.Y <= eventY && eventY <= testBounds.Y + testBounds.Height)
                    {
                        gridChild.BackgroundColor = Color.Gray;
                        break;
                    }
                }
            };

            boxview.GestureRecognizers.Add(swipeGestureRecognizer);

            if (rowIndex == 4 && columnIndex == 3)
            {
                boxview.BackgroundColor = Color.Red;
            }

            pageGrid.Children.Add(boxview, columnIndex, rowIndex);

            if (rowIndex != 8) continue;
            if (columnIndex == 6) return;
            columnIndex += 1;
            rowIndex = -1;
        }
    }