Xamarin Forms Grid Boxview滑动手势多选

时间:2018-12-05 14:56:11

标签: xamarin.forms grid multi-select swipe-gesture

我有一个简单的Xamarin.Forms页面,其中的网格布局位于BoxViews内部。我希望能够通过滑动手势同时选择这些框视图。我该如何实现?

我想构建一种平铺地图,以便更轻松地选择Boxview。我想轻松实现这一目标。仅刷卡效果不佳,因为只会选择“一个”框视图。

这是我到目前为止所拥有的:

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

现在,每项滑动操作都只会选择一个框视图!

Layout

1 个答案:

答案 0 :(得分:0)

我对此进行了一些尝试,并提出了一些想法,这些想法将在随后的部分实现中实现。

我认为滑动手势不会像我认为那样使它起作用。看起来Swipe手势正好触发一次,从屏幕上抬起手指时,这对我来说不是理想的体验,因为这意味着即使您可以算出总共滑过哪些框(我'不确定是否可以这样做),他们都会等到您抬起手指来改变颜色。

我刚想到的想法是使用平移手势,因为一旦检测到运动,就会非常频繁地触发。平移和滑动似乎都具有这样的约束条件:一旦事件与单个BoxView相关联,即使手指移过其他框,该事件也不会触发其他任何回调。但是,我认为使用平移手势可以解决此问题。平移手势会为您提供每次触发时的总平移偏差,并且鉴于手势回调本身会在平移开始的Boxview内部(而不是在其他任何框内)持续触发,这意味着您既有初始位置又有每个平移运动的总偏差。从理论上讲,您拥有完成此工作所需的所有信息,但是您需要对事件进行一些智能处理。可能会让人头疼,但是如果您可以构建自己的网格,那么足够聪明地知道每个BoxView与其他BoxView的关系,则可以在它们进入时绘制出平移手势事件,并根据需要更改特定BoxView的颜色。

编辑:应询问者的要求,我建立了一些示例代码来执行此操作。有必要重新添加单个敲击事件,并使其正确地“切换”,而不是仅根据所需的逻辑进行选择。可能还需要进行其他调整,但这证明了这一概念。

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