Özel düzenler
.NET Çok Platformlu Uygulama Kullanıcı Arabirimi (.NET MAUI), her birinin alt öğelerini farklı bir şekilde yerleştiren birden çok düzen sınıfı tanımlar. Düzen, bu görünümlerin düzen içinde nasıl düzenlendiğini tanımlayan kurallar ve özelliklere sahip görünümlerin listesi olarak düşünülebilir. Düzenlere örnek olarak Grid, AbsoluteLayoutve VerticalStackLayoutverilebilir.
.NET MAUI düzen sınıfları soyut Layout sınıftan türetilir. Bu sınıf, platformlar arası düzeni ve ölçümü düzen yöneticisi sınıfına devreder. sınıfı Layout , türetilmiş düzenlerin düzen yöneticisini belirtmek için kullanabileceği geçersiz kılınabilir CreateLayoutManager() bir yöntem de içerir.
Her düzen yöneticisi sınıfı, ve ArrangeChildren uygulamalarının ILayoutManager sağlanması gerektiğini belirten Measure arabirimini uygular:
- Uygulama Measure , düzendeki her görünümü çağırır IView.Measure ve kısıtlamalara göre düzenin toplam boyutunu döndürür.
- Uygulama, ArrangeChildren her görünümün düzenin sınırları içinde nereye yerleştirileceğini belirler ve her görünüme uygun sınırlarıyla çağrılar Arrange . Dönüş değeri, düzenin gerçek boyutudur.
.NET MAUI'nin düzenleri, düzenlerini işlemek için önceden tanımlanmış düzen yöneticilerine sahiptir. Ancak bazen sayfa içeriğini .NET MAUI tarafından sağlanmayan bir düzen kullanarak düzenlemek gerekir. Bu, .NET MAUI'nin platformlar arası düzen sürecinin nasıl çalıştığını anlamanızı gerektiren kendi özel düzeninizi oluşturarak elde edilebilir.
Düzen işlemi
.NET MAUI'nin platformlar arası düzen süreci, her platformdaki yerel düzen işleminin üzerine inşa eder. Genellikle, düzen işlemi yerel düzen sistemi tarafından başlatılır. Platformlar arası işlem, yerel düzen sistemi tarafından ölçülmesinin veya düzenlenmesinin bir sonucu olarak bir düzen veya içerik denetimi tarafından başlatıldığında çalıştırılır.
Not
Her platform düzeni biraz farklı işler. Ancak.NET MAUI'nin platformlar arası düzen süreci mümkün olduğunca platformdan bağımsız olmayı hedeflemektedir.
Aşağıdaki diyagramda yerel düzen sisteminin düzen ölçümlerini başlattığı işlem gösterilmektedir:
Tüm .NET MAUI düzenleri her platformda tek bir yedekleme görünümüne sahiptir:
- Android'de bu destek görünümü şeklindedir
LayoutViewGroup
. - iOS ve Mac Catalyst'te bu destek görünümü şeklindedir
LayoutView
. - Windows'ta bu destek görünümü şeklindedir
LayoutPanel
.
Bir platform için yerel düzen sistemi bu yedekleme görünümlerinden birinin ölçümünün istendiğinde, yedekleme görünümü yöntemini çağırır Layout.CrossPlatformMeasure . Bu, denetimin yerel düzen sisteminden .NET MAUI'nin düzen sistemine geçirildiği noktadır. Layout.CrossPlatformMeasure düzen yöneticilerinin Measure yöntemini çağırır. Bu yöntem, düzendeki her görünümü çağırarak IView.Measure alt görünümleri ölçmekle sorumludur. Görünüm yerel denetimini ölçer ve özelliğini bu ölçüme göre güncelleştirir DesiredSize . Bu değer, yönteminin sonucu olarak yedekleme görünümüne CrossPlatformMeasure
döndürülür. Yedekleme görünümü, yapması gereken iç işlemeyi gerçekleştirir ve ölçülen boyutunu platforma döndürür.
Aşağıdaki diyagramda yerel düzen sisteminin düzen düzenlemesini başlattığı işlem gösterilmektedir:
Bir platform için yerel düzen sistemi bu yedekleme görünümlerinden birinin düzenlemesini veya düzenini istediğinde, yedekleme görünümü yöntemini çağırır Layout.CrossPlatformArrange . Bu, denetimin yerel düzen sisteminden .NET MAUI'nin düzen sistemine geçirildiği noktadır. Layout.CrossPlatformArrange düzen yöneticilerinin ArrangeChildren yöntemini çağırır. Bu yöntem, her görünümün düzenin sınırları içinde nereye yerleştirilmesi gerektiğini belirlemekle sorumludur ve konumunu ayarlamak için her görünüme çağrılar Arrange . Düzenin boyutu, yönteminin sonucu olarak yedekleme görünümüne CrossPlatformArrange
döndürülür. Yedekleme görünümü, yapması gereken tüm iç işlemleri gerçekleştirir ve gerçek boyutu platforma döndürür.
Not
ILayoutManager.Measure çağrılmadan önce ArrangeChildren birden çok kez çağrılabilir, çünkü bir platformun görünümleri düzenlemeden önce bazı tahmini ölçümler yapması gerekebilir.
Özel düzen yaklaşımları
Özel düzen oluşturmak için iki ana yaklaşım vardır:
- Genellikle var olan bir düzen türünün veya Layoutöğesinin alt sınıfı olan özel bir düzen türü oluşturun ve özel düzen türünüzde geçersiz kılın CreateLayoutManager() . Ardından, özel düzen mantığınızı içeren bir ILayoutManager uygulama sağlayın. Daha fazla bilgi için bkz . Özel düzen türü oluşturma.
- uygulayan ILayoutManagerFactorybir tür oluşturarak mevcut düzen türünün davranışını değiştirin. Ardından, .NET MAUI'nin var olan düzen için varsayılan düzen yöneticisini özel düzen mantığınızı içeren kendi ILayoutManager uygulamanızla değiştirmek için bu düzen yöneticisi fabrikasını kullanın. Daha fazla bilgi için bkz . Var olan düzenin davranışını değiştirme.
Özel düzen türü oluşturma
Özel düzen türü oluşturma işlemi şu şekildedir:
Var olan bir düzen türünü veya sınıfı alt sınıfa ekleyen Layout ve özel düzen türünüzde geçersiz kılan CreateLayoutManager() bir sınıf oluşturun. Daha fazla bilgi için bkz . Düzeni alt sınıflama.
Mevcut bir düzen yöneticisinden türetilen veya arabirimi doğrudan uygulayan ILayoutManager bir düzen yöneticisi sınıfı oluşturun. Düzen yöneticisi sınıfınızda şunları yapmalısınız:
- Kısıtlamalarına göre düzenin Measure toplam boyutunu hesaplamak için yöntemini geçersiz kılın veya uygulayın.
- Düzenin ArrangeChildren içindeki tüm alt öğeleri boyutlandırmak ve konumlandırmak için yöntemini geçersiz kılın veya uygulayın.
Daha fazla bilgi için bkz . Düzen yöneticisi oluşturma.
Özel düzen türünüzü bir Pageöğesine ekleyerek ve düzene alt öğeler ekleyerek kullanın. Daha fazla bilgi için bkz . Düzen türünü kullanma.
Bu işlemi göstermek için yönlendirmeye duyarlı HorizontalWrapLayout
bir kullanılır. HorizontalWrapLayout
, alt öğelerini sayfada yatay olarak düzenlemesine benzer HorizontalStackLayout . Ancak kapsayıcısının sağ kenarıyla karşılaştığında alt öğeleri yeni bir satıra sarmalar
Not
Örnek, özel düzen oluşturmayı anlamak için kullanılabilecek ek özel düzenler tanımlar.
Düzeni alt sınıflama
Özel bir düzen türü oluşturmak için önce var olan bir düzen türünü veya sınıfını alt sınıflamanız Layout gerekir. Ardından, düzen türünüzde geçersiz kılın CreateLayoutManager() ve düzen türünüz için düzen yöneticisinin yeni bir örneğini döndürin:
using Microsoft.Maui.Layouts;
public class HorizontalWrapLayout : HorizontalStackLayout
{
protected override ILayoutManager CreateLayoutManager()
{
return new HorizontalWrapLayoutManager(this);
}
}
HorizontalWrapLayout
, düzen işlevselliğini kullanmak için 'den HorizontalStackLayout türetilir. .NET MAUI düzenleri, platformlar arası düzeni ve ölçümü düzen yöneticisi sınıfına devreder. Bu nedenle geçersiz kılma, CreateLayoutManager() sonraki bölümde ele alınan düzen yöneticisi olan sınıfın yeni bir örneğini HorizontalWrapLayoutManager
döndürür.
Düzen yöneticisi oluşturma
Düzen yöneticisi sınıfı, özel düzen türünüz için platformlar arası düzen ve ölçüm gerçekleştirmek için kullanılır. Var olan bir düzen yöneticisinden türetilmelidir veya doğrudan arabirimi uygulamalıdır ILayoutManager . HorizontalWrapLayoutManager
, temel işlevselliğini kullanabilmesi ve devralma hiyerarşisindeki üyelere erişebilmesi için şu kaynaktan HorizontalStackLayoutManager türetilir:
using Microsoft.Maui.Layouts;
using HorizontalStackLayoutManager = Microsoft.Maui.Layouts.HorizontalStackLayoutManager;
public class HorizontalWrapLayoutManager : HorizontalStackLayoutManager
{
HorizontalWrapLayout _layout;
public HorizontalWrapLayoutManager(HorizontalWrapLayout horizontalWrapLayout) : base(horizontalWrapLayout)
{
_layout = horizontalWrapLayout;
}
public override Size Measure(double widthConstraint, double heightConstraint)
{
}
public override Size ArrangeChildren(Rect bounds)
{
}
}
HorizontalWrapLayoutManager
Oluşturucu, türün HorizontalWrapLayout
bir örneğini bir alanda depolar, böylece düzen yöneticisinin tamamında erişilebilir. Düzen yöneticisi ayrıca sınıfından Measure ve ArrangeChildren yöntemlerini HorizontalStackLayoutManager geçersiz kılar. Bu yöntemler, özel düzeninizi uygulamak için mantığı tanımlayabileceğiniz yöntemlerdir.
Düzen boyutunu ölçme
Uygulamanın amacı ILayoutManager.Measure , düzenin toplam boyutunu hesaplamaktır. Bunu, düzendeki her alt öğeyi çağırarak IView.Measure yapmalıdır. Ardından bu verileri kullanarak kısıtlamalarına göre düzenin toplam boyutunu hesaplamalı ve döndürmelidir.
Aşağıdaki örnekte sınıfı için Measure uygulama gösterilmektedir HorizontalWrapLayoutManager
:
public override Size Measure(double widthConstraint, double heightConstraint)
{
var padding = _layout.Padding;
widthConstraint -= padding.HorizontalThickness;
double currentRowWidth = 0;
double currentRowHeight = 0;
double totalWidth = 0;
double totalHeight = 0;
for (int n = 0; n < _layout.Count; n++)
{
var child = _layout[n];
if (child.Visibility == Visibility.Collapsed)
{
continue;
}
var measure = child.Measure(double.PositiveInfinity, heightConstraint);
// Will adding this IView put us past the edge?
if (currentRowWidth + measure.Width > widthConstraint)
{
// Keep track of the width so far
totalWidth = Math.Max(totalWidth, currentRowWidth);
totalHeight += currentRowHeight;
// Account for spacing
totalHeight += _layout.Spacing;
// Start over at 0
currentRowWidth = 0;
currentRowHeight = measure.Height;
}
currentRowWidth += measure.Width;
currentRowHeight = Math.Max(currentRowHeight, measure.Height);
if (n < _layout.Count - 1)
{
currentRowWidth += _layout.Spacing;
}
}
// Account for the last row
totalWidth = Math.Max(totalWidth, currentRowWidth);
totalHeight += currentRowHeight;
// Account for padding
totalWidth += padding.HorizontalThickness;
totalHeight += padding.VerticalThickness;
// Ensure that the total size of the layout fits within its constraints
var finalWidth = ResolveConstraints(widthConstraint, Stack.Width, totalWidth, Stack.MinimumWidth, Stack.MaximumWidth);
var finalHeight = ResolveConstraints(heightConstraint, Stack.Height, totalHeight, Stack.MinimumHeight, Stack.MaximumHeight);
return new Size(finalWidth, finalHeight);
}
Measure
yöntemi, düzendeki tüm görünür alt öğeleri numaralandırır ve yöntemi her alt öğede çağırırIView.Measure. Ardından ve özelliklerinin kısıtlamalarını ve değerlerini dikkate alarak düzenin PaddingSpacing toplam boyutunu döndürür. Düzenin ResolveConstraints toplam boyutunun kısıtlamalarına uyduğundan emin olmak için yöntemi çağrılır.
Önemli
Uygulamadaki ILayoutManager.Measure alt öğeleri numaralandırırken, özelliği olarak ayarlanmış Collapsedolan Visibility tüm alt öğeleri atlayın. Bu, özel düzenin görünmez çocuklar için alan bırakmamasını sağlar.
Düzende alt öğeleri düzenleme
Uygulamanın amacı ArrangeChildren , tüm alt öğeleri düzen içinde boyutlandırmak ve konumlandırmaktır. Her çocuğun düzenin sınırları içinde nereye yerleştirilmesi gerektiğini belirlemek için, her alt öğeyi uygun sınırlarıyla çağırmalıdır Arrange . Daha sonra düzenin gerçek boyutunu temsil eden bir değer döndürmelidir.
Uyarı
Düzendeki her alt öğede yönteminin çağrılmaması ArrangeChildren , çocuğun hiçbir zaman doğru boyut veya konum almamasına neden olur ve bu nedenle çocuk sayfada görünmez.
Aşağıdaki örnekte sınıfı için ArrangeChildren uygulama gösterilmektedir HorizontalWrapLayoutManager
:
public override Size ArrangeChildren(Rect bounds)
{
var padding = Stack.Padding;
double top = padding.Top + bounds.Top;
double left = padding.Left + bounds.Left;
double currentRowTop = top;
double currentX = left;
double currentRowHeight = 0;
double maxStackWidth = currentX;
for (int n = 0; n < _layout.Count; n++)
{
var child = _layout[n];
if (child.Visibility == Visibility.Collapsed)
{
continue;
}
if (currentX + child.DesiredSize.Width > bounds.Right)
{
// Keep track of our maximum width so far
maxStackWidth = Math.Max(maxStackWidth, currentX);
// Move down to the next row
currentX = left;
currentRowTop += currentRowHeight + _layout.Spacing;
currentRowHeight = 0;
}
var destination = new Rect(currentX, currentRowTop, child.DesiredSize.Width, child.DesiredSize.Height);
child.Arrange(destination);
currentX += destination.Width + _layout.Spacing;
currentRowHeight = Math.Max(currentRowHeight, destination.Height);
}
var actual = new Size(maxStackWidth, currentRowTop + currentRowHeight);
// Adjust the size if the layout is set to fill its container
return actual.AdjustForFill(bounds, Stack);
}
yöntemi, ArrangeChildren
düzendeki görünür tüm alt öğeleri düzen içinde boyutlandırmak ve konumlandırmak için numaralandırır. Bunu, temel alınan düzenin ve Spacing değerlerini dikkate Padding alan uygun sınırlara sahip her alt öğeyi çağırarak Arrange yapar. Ardından düzenin gerçek boyutunu döndürür. yöntemi AdjustForFill , boyutun düzenin HorizontalLayoutAlignment ve VerticalLayoutAlignment özelliklerinin olarak ayarlanıp ayarlanmadığını hesaba katmasını sağlamak için çağrılır LayoutOptions.Fill.
Önemli
Uygulamadaki ArrangeChildren alt öğeleri numaralandırırken, özelliği olarak ayarlanmış Collapsedolan Visibility tüm alt öğeleri atlayın. Bu, özel düzenin görünmez çocuklar için alan bırakmamasını sağlar.
Düzen türünü kullanma
Sınıf HorizontalWrapLayout
, türetilmiş bir Page türe yerleştirilerek kullanılabilir:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:layouts="clr-namespace:CustomLayoutDemos.Layouts"
x:Class="CustomLayoutDemos.Views.HorizontalWrapLayoutPage"
Title="Horizontal wrap layout">
<ScrollView Margin="20">
<layouts:HorizontalWrapLayout Spacing="20">
<Image Source="img_0074.jpg"
WidthRequest="150" />
<Image Source="img_0078.jpg"
WidthRequest="150" />
<Image Source="img_0308.jpg"
WidthRequest="150" />
<Image Source="img_0437.jpg"
WidthRequest="150" />
<Image Source="img_0475.jpg"
WidthRequest="150" />
<Image Source="img_0613.jpg"
WidthRequest="150" />
<!-- More images go here -->
</layouts:HorizontalWrapLayout>
</ScrollView>
</ContentPage>
Denetimler öğesine gerektiği gibi eklenebilir HorizontalWrapLayout
. Bu örnekte, öğesini içeren sayfa göründüğünde HorizontalWrapLayout
Image denetimler görüntülenir:
Her satırdaki sütun sayısı, görüntü boyutuna, sayfanın genişliğine ve cihazdan bağımsız birim başına piksel sayısına bağlıdır:
Not
Kaydırma, öğesini bir ScrollViewiçinde kaydırarak HorizontalWrapLayout
desteklenir.
Mevcut düzenin davranışını değiştirme
Bazı senaryolarda, özel düzen türü oluşturmak zorunda kalmadan var olan bir düzen türünün davranışını değiştirmek isteyebilirsiniz. Bu senaryolar için uygulayan ILayoutManagerFactory bir tür oluşturabilir ve bunu kullanarak mevcut düzen için .NET MAUI'nin varsayılan düzen yöneticisini kendi ILayoutManager uygulamanızla değiştirebilirsiniz. Bu, var olan bir düzen için yeni bir düzen yöneticisi tanımlamanızı sağlar; örneğin için Gridözel bir düzen yöneticisi sağlar. Bu, bir düzene yeni bir davranış eklemek istediğiniz ancak uygulamanızda yaygın olarak kullanılan mevcut bir düzenin türünü güncelleştirmek istemediğiniz senaryolar için yararlı olabilir.
Düzen yöneticisi fabrikasıyla var olan bir düzenin davranışını değiştirme işlemi şöyledir:
- .NET MAUI'nin düzen yöneticisi türlerinden birinden türetilen bir düzen yöneticisi oluşturun. Daha fazla bilgi için bkz . Özel düzen yöneticisi oluşturma.
- uygulayan ILayoutManagerFactorybir tür oluşturun. Daha fazla bilgi için bkz . Düzen yöneticisi fabrikası oluşturma.
- Düzen yöneticisi fabrikanızı uygulamanın hizmet sağlayıcısına kaydedin. Daha fazla bilgi için bkz . Düzen yöneticisi fabrikasını kaydetme.
Özel düzen yöneticisi oluşturma
Düzen yöneticisi, bir düzen için platformlar arası düzen ve ölçüm gerçekleştirmek için kullanılır. Mevcut bir düzenin davranışını değiştirmek için, düzenin düzen yöneticisinden türetilen özel bir düzen yöneticisi oluşturmanız gerekir:
using Microsoft.Maui.Layouts;
public class CustomGridLayoutManager : GridLayoutManager
{
public CustomGridLayoutManager(IGridLayout layout) : base(layout)
{
}
public override Size Measure(double widthConstraint, double heightConstraint)
{
EnsureRows();
return base.Measure(widthConstraint, heightConstraint);
}
void EnsureRows()
{
if (Grid is not Grid grid)
{
return;
}
// Find the maximum row value from the child views
int maxRow = 0;
foreach (var child in grid)
{
maxRow = Math.Max(grid.GetRow(child), maxRow);
}
// Add more rows if we need them
for (int n = grid.RowDefinitions.Count; n <= maxRow; n++)
{
grid.RowDefinitions.Add(new RowDefinition(GridLength.Star));
}
}
}
Bu örnekte.NET CustomGridLayoutManager
MAUI'nin GridLayoutManager sınıfından türetilir ve yöntemini geçersiz kılar Measure . Bu özel düzen yöneticisi, çalışma zamanında RowDefinitions için Grid öğesinin alt görünümde ayarlanan her Grid.Row
ekli özelliği hesaba eklemek için yeterli satır içermesini sağlar. Bu değişiklik olmadan için öğesinin RowDefinitionsGrid tasarım zamanında belirtilmesi gerekir.
Önemli
Mevcut düzen yöneticisinin davranışını değiştirirken, yöntemi uygulamanızdan Measure çağırdığınızdan base.Measure
emin olun.
Düzen yöneticisi fabrikası oluşturma
Özel düzen yöneticisi bir düzen yöneticisi fabrikasında oluşturulmalıdır. Bu, arabirimi uygulayan bir tür oluşturularak elde edilir ILayoutManagerFactory :
using Microsoft.Maui.Layouts;
public class CustomLayoutManagerFactory : ILayoutManagerFactory
{
public ILayoutManager CreateLayoutManager(Layout layout)
{
if (layout is Grid)
{
return new CustomGridLayoutManager(layout as IGridLayout);
}
return null;
}
}
Bu örnekte, düzen bir ise bir CustomGridLayoutManager
Gridörnek döndürülür.
Düzen yöneticisi fabrikasını kaydetme
Düzen yöneticisi fabrikası, sınıfınızdaki uygulamanızın hizmet sağlayıcısına MauiProgram
kayıtlı olmalıdır:
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
});
// Setup a custom layout manager so the default manager for the Grid can be replaced.
builder.Services.Add(new ServiceDescriptor(typeof(ILayoutManagerFactory), new CustomLayoutManagerFactory()));
return builder.Build();
}
}
Ardından, uygulama bir Grid işlendiğinde, çalışma zamanında RowDefinitions için öğesinin alt görünümlerde ayarlanan her Grid.Row
ekli özellik için hesaba eklemek için yeterli satır içerdiğinden emin olmak için Grid özel düzen yöneticisini kullanır.
Aşağıdaki örnekte, alt görünümlerde ekli özelliği ayarlayan Grid.Row
ancak özelliğini ayarlamayan RowDefinitions bir Grid gösterilir:
<Grid>
<Label Text="This Grid demonstrates replacing the LayoutManager for an existing layout type." />
<Label Grid.Row="1"
Text="In this case, it's a LayoutManager for Grid which automatically adds enough rows to accommodate the rows specified in the child views' attached properties." />
<Label Grid.Row="2"
Text="Notice that the Grid doesn't explicitly specify a RowDefinitions collection." />
<Label Grid.Row="3"
Text="In MauiProgram.cs, an instance of an ILayoutManagerFactory has been added that replaces the default GridLayoutManager. The custom manager will automatically add the necessary RowDefinitions at runtime." />
<Label Grid.Row="5"
Text="We can even skip some rows, and it will add the intervening ones for us (notice the gap between the previous label and this one)." />
</Grid>
Düzen yöneticisi fabrikası, özelliği ayarlanmasa da bu örnekteki öğesinin Grid doğru şekilde görüntülendiğinden emin olmak için özel düzen yöneticisini RowDefinitions kullanır: