如何使用正方形创建响应式网格?

时间:2014-06-26 13:31:55

标签: mobile grid xamarin xamarin.forms

我正在创建一个充满按钮的网格。现在我希望这个网格能够响应并且按钮是方形的。我想要创建的东西看起来像iOS或Android主屏幕(只是按钮)。

Grid grid = new Grid
        {

            HorizontalOptions = LayoutOptions.StartAndExpand,
            RowSpacing = 15,
            ColumnSpacing = 15,
            ColumnDefinitions = 
            {
                new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) },
                new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) },
                new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) }
            }
        };

        for (int i = 0; i < 12; i++)
        {
            MonitorButton button = new MonitorButton();
            grid.Children.Add(button, i % 3, i / 3);
        }

        this.Content = new ScrollView
        {
            Padding = new Thickness(15),
            Orientation = ScrollOrientation.Vertical,
            Content = grid
        };

所以就在这里我正在创建一个包含3列的网格,其中包含12个MonitorButtons(背景上带有图像的按钮)。看起来没问题。现在,当我以横向模式打开屏幕时,屏幕会充满矩形,因为列数仍然相同...... 我怎么解决这个问题?我希望有某种动态可能性(例如:itemscontrol @ XAML)。

2 个答案:

答案 0 :(得分:0)

当您旋转屏幕时,当前页面会自行调整大小,因此它会在您的页面中调用OnSizeRequest方法。如果覆盖该方法,则可以检测大小和方向。

YourPage.cs || YourPage.xaml.cs

protected override SizeRequest OnSizeRequest(double widthConstraint, double heightConstraint)
{
    if(widthConstraint>heightConstraint)
    {
        //landscape mode
        //set your grid row & columndefinitions
    }
    else
    {
        //portait mode
        //set your grid row & columndefinitions
    }
    return base.OnSizeRequest(widthConstraint, heightConstraint);
}

答案 1 :(得分:0)

我认为这个自定义(自定义网格控制)网格将更好用,它有命令,因此您可以识别哪个项目被点击,因此我认为您的UI上也可能不需要这么多按钮。 并且您可以在网格单元格中添加您想要的任何控件(在Square中添加按钮)

GridView.Xaml

<?xml version="1.0" encoding="utf-8" ?>
<Grid xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="Test.Controls.GridView">

</Grid>

GridView.Xaml.cs

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using Test.Views;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;

namespace Test.Controls
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class GridView : Grid
    {
        public GridView()
        {
            InitializeComponent();
            for (var i = 0; i < MaxColumns; i++)
                ColumnDefinitions.Add(new ColumnDefinition());
        }

        public static readonly BindableProperty CommandParameterProperty = BindableProperty.Create<GridView, object>(p => p.CommandParameter, null);
        public static readonly BindableProperty CommandProperty = BindableProperty.Create<GridView, ICommand>(p => p.Command, null);
        public static readonly BindableProperty ItemsSourceProperty = BindableProperty.Create<GridView, IEnumerable<object>>(p => p.ItemsSource, null, BindingMode.OneWay, null, (bindable, oldValue, newValue) => { ((GridView)bindable).BuildTiles(newValue); });

        private int _maxColumns = 2;
        private float _tileHeight = 0;

        public Type ItemTemplate { get; set; } = typeof(SubControlsView);

        public int MaxColumns
        {
            get { return _maxColumns; }
            set { _maxColumns = value; }
        }

        public float TileHeight
        {
            get { return _tileHeight; }
            set { _tileHeight = value; }
        }

        public object CommandParameter
        {
            get { return GetValue(CommandParameterProperty); }
            set { SetValue(CommandParameterProperty, value); }
        }

        public ICommand Command
        {
            get { return (ICommand)GetValue(CommandProperty); }
            set { SetValue(CommandProperty, value); }
        }

        public IEnumerable<object> ItemsSource
        {
            get { return (IEnumerable<object>)GetValue(ItemsSourceProperty); }
            set { SetValue(ItemsSourceProperty, value); }
        }

        public void BuildTiles(IEnumerable<object> tiles)
        {
            try
            {
                if (tiles == null || tiles.Count() == 0)
                    Children?.Clear();

                // Wipe out the previous row definitions if they're there.
                RowDefinitions?.Clear();

                var enumerable = tiles as IList ?? tiles.ToList();
                var numberOfRows = Math.Ceiling(enumerable.Count / (float)MaxColumns);

                for (var i = 0; i < numberOfRows; i++)
                    RowDefinitions?.Add(new RowDefinition { Height = TileHeight });

                for (var index = 0; index < enumerable.Count; index++)
                {
                    var column = index % MaxColumns;
                    var row = (int)Math.Floor(index / (float)MaxColumns);

                    var tile = BuildTile(enumerable[index]);

                    Children?.Add(tile, column, row);
                }
            }
            catch
            { // can throw exceptions if binding upon disposal
            }
        }

        private Layout BuildTile(object item1)
        {
            var buildTile = (Layout)Activator.CreateInstance(ItemTemplate, item1);
            buildTile.InputTransparent = false;

            var tapGestureRecognizer = new TapGestureRecognizer
            {
                Command = Command,
                CommandParameter = item1,
                NumberOfTapsRequired = 1
            };

            buildTile?.GestureRecognizers.Add(tapGestureRecognizer);


            return buildTile;
        }
    }
}

在这里,您可以创建内部UI(视图)。即每个网格方块的内部视图。在这个例子中,我只添加了一个标签。

SubControlsView.Xaml

<?xml version="1.0" encoding="utf-8" ?>
<Grid xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="Test.Views.SubControlsView" BackgroundColor="CornflowerBlue">
    <StackLayout VerticalOptions="CenterAndExpand">
        <!--You can add any controls which you want--> 
        <!--<Label Text="{Binding id}" HorizontalOptions="CenterAndExpand" TextColor="White" />-->

    </StackLayout>
</Grid>

SubControlsView.Xaml.cs

using Xamarin.Forms;
using Xamarin.Forms.Xaml;

namespace Test.Views
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class SubControlsView : Grid
    {
        public SubControlsView()
        {
            InitializeComponent();
        }

        public SubControlsView(object item)
        {
            InitializeComponent();
            BindingContext = item;
        }
    }
}

然后在任何地方使用此控件。即在任何内容页面上。这将是您的实际视图(仪表板)

SubCarriers.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"
             xmlns:control="clr-namespace:Test.Controls"
            x:Class="Test.Views.SubCarriers" Title="Details Dashboard">
    <ContentPage.Content>
        <ScrollView Margin="5">
            <control:GridView HorizontalOptions="FillAndExpand"
                        Grid.Row="1"
                        VerticalOptions="FillAndExpand"
                        RowSpacing="5"
                        ColumnSpacing="5"
                        MaxColumns="2"
                        ItemsSource="{Binding SubCarriersCnt}"
                        CommandParameter="{Binding SubCarriersCnt}"
                        Command="{Binding ClickCommand}"
                        IsClippedToBounds="False">
                <control:GridView.TileHeight>
                    <OnPlatform x:TypeArguments="x:Single"
                      iOS="60"
                      Android="90"
                      WinPhone="90" />
                </control:GridView.TileHeight>
            </control:GridView>
        </ScrollView>
    </ContentPage.Content>
</ContentPage>

然后将ViewModel绑定到您的视图。并在YourViewModel中实现ClickCommand

SubCarriers.Xaml.cs

using System;
using Test.ViewModels;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
using CommonUtility;

namespace Test.Views
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class SubCarriers : ContentPage
    {
        private YourViewModel viewModel;

        public SubCarriers()
        {
            InitializeComponent();
            this.BindingContext = new SubCarriersViewModel();
            viewModel = (YourViewModel)this.BindingContext;
        }

    }
}