public XamagonXuzzlePage()
        {
            InitializeComponent();

            for (int row = 0; row < NUM; row++)
            {
                for (int col = 0; col < NUM; col++)
                {
                    if (row == NUM - 1 && col == NUM - 1)
                    {
                        break;
                    }

                    ImageSource imageSource =
                        ImageSource.FromResource("Animation.Images.Bitmap" + row + col + ".png");

                    XamagonXuzzleTile tile = new XamagonXuzzleTile(row, col, imageSource);

                    TapGestureRecognizer tapGestureRecognizer = new TapGestureRecognizer
                    {
                        Command          = new Command(OnTileTapped),
                        CommandParameter = tile
                    };

                    tile.GestureRecognizers.Add(tapGestureRecognizer);

                    tiles[row, col] = tile;
                    absoluteLayout.Children.Add(tile);
                }
            }
        }
        async private void OnTileTapped(object parameter)
        {
            if (isBusy)
            {
                return;
            }

            isBusy = true;
            XamagonXuzzleTile tappedTile = (XamagonXuzzleTile)parameter;

            await ShiftIntoEmpty(tappedTile.Row, tappedTile.Col);

            isBusy = false;
        }
        async private Task AnimateTile(int row, int col, int newRow, int newCol, uint length)
        {
            XamagonXuzzleTile animaTile = tiles[row, col];
            Rectangle         rect      = new Rectangle(emptyCol * tileSize, emptyRow * tileSize, tileSize, tileSize);

            await animaTile.LayoutTo(rect, length);

            AbsoluteLayout.SetLayoutBounds(animaTile, rect);

            tiles[newRow, newCol] = animaTile;
            animaTile.Row         = newRow;
            animaTile.Col         = newCol;
            tiles[row, col]       = null;
            emptyRow = row;
            emptyCol = col;
        }
        private void OnContentViewSizeChanged(object sender, EventArgs e)
        {
            ContentView contentView = (ContentView)sender;
            double      width       = contentView.Width;
            double      height      = contentView.Height;

            if (width <= 0 || height <= 0)
            {
                return;
            }

            stackLayout.Orientation = (width < height) ? StackOrientation.Vertical : StackOrientation.Horizontal;

            tileSize = Math.Min(width, height) / NUM;
            absoluteLayout.WidthRequest  = NUM * tileSize;
            absoluteLayout.HeightRequest = NUM * tileSize;

            foreach (View view in absoluteLayout.Children)
            {
                XamagonXuzzleTile tile = (XamagonXuzzleTile)view;

                AbsoluteLayout.SetLayoutBounds(tile, new Rectangle(tile.Col * tileSize, tile.Row * tileSize, tileSize, tileSize));
            }
        }