Формы Xamarin, RecyclerView, рендеринг ячеек из xaml
Я хочу создать элемент управления в Xamarin.Forms, который использует родной андроид RecyclerView в качестве средства визуализации.
Моя проблема возникает, когда я пытаюсь создать ячейку, которая содержит метки или другие элементы управления с HorizontalOptions, отличными от: Default, Fill и FillAndExpand. Эти ярлыки просто не отображаются сами по себе ( Снимок экрана). это мой код.xaml
<?xml version="1.0" encoding="utf-8" ?>
<self:FormsRecyclerCell xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:self="clr-namespace:FormsRecyclerViewApp;assembly:FormsRecyclerViewApp" x:Class="FormsRecyclerViewApp.FormsRecyclerCellTemplate">
<Grid>
<Label Grid.Row="0" Text="{Binding .}" BackgroundColor="Blue" />
<Label Grid.Row="1" HorizontalOptions="Start" Text="Horizontal Start" BackgroundColor="AliceBlue"/>
<Label Grid.Row="2" HorizontalOptions="StartAndExpand" Text="Horizontal StartAndExpand" BackgroundColor="AliceBlue" />
<Label Grid.Row="3" HorizontalOptions="Fill" Text="Horizontal Fill" BackgroundColor="Aqua" />
<Label Grid.Row="4" HorizontalOptions="FillAndExpand" Text="Horizontal FillAndExpand" BackgroundColor="Aqua" />
<Label Grid.Row="5" HorizontalOptions="Center" Text="Horizontal Center" BackgroundColor="Bisque" />
<Label Grid.Row="6" HorizontalOptions="CenterAndExpand" Text="Horizontal CenterAndExpand" BackgroundColor="Bisque" />
<Label Grid.Row="7" HorizontalOptions="End" Text="Horizontal End" BackgroundColor="BlanchedAlmond" />
<Label Grid.Row="8" HorizontalOptions="EndAndExpand" Text="Horizontal EndAndExpand" BackgroundColor="BlanchedAlmond" />
<Label Grid.Row="9" Text="Horizontal Default" BackgroundColor="Azure"/>
<BoxView Grid.Row="10" BackgroundColor="Green" />
</Grid>
</self:FormsRecyclerCell>
Для рендеринга вещей внутри RecyclerView я использую CellContainer, который создает PlatformRenderer и переопределяет методы OnLayout и OnMeasure
FormsRecyclerViewCellContainer.cs
protected override void OnLayout(bool changed, int l, int t, int r, int b)
{
using (var handler = new Handler(Looper.MainLooper))
{
handler.Post(() =>
{
double width = Context.FromPixels(r - l);
double height = Context.FromPixels(b - t);
Xamarin.Forms.Layout.LayoutChildIntoBoundingRegion(this.view.Element, new XForms.Rectangle(0, 0, width, height));
this.view.UpdateLayout();
});
}
}
protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
if (this.view == null || this.view.Element == null)
{
base.SetMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
return;
}
XForms.SizeRequest measure = this.view.Element.Measure(this.initialWidth, double.PositiveInfinity, XForms.MeasureFlags.IncludeMargins);
int height = (int)Context.ToPixels(this.fastCell.Height > 0 ? this.fastCell.Height : measure.Request.Height);
this.SetMeasuredDimension((int)Context.ToPixels(this.initialWidth), height);
}
Мои вопросы:
Наилучший способ получить нативные объекты из форм.xaml?
- Почему некоторые ярлыки не отображаются сами?
Я должен сделать, чтобы правильно визуализировать все VisualElemts?
Не стесняйтесь скачать мой пример проекта.
2 ответа
Я нашел ответ. Моя проблема действительно была связана с HorizontalOptions, ваша заметка была полезной.
(...) Кроме того, он указывает, должен ли элемент занимать оставшееся пространство по оси X от родительского макета. (...)
Я только что добавил родителя в XF-версию моего viewHolder. Здесь вы можете увидеть, что я изменил:
public override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int viewType)
{
FormsRecyclerCell fastCell;
fastCell = this.Element.ItemTemplate.CreateContent() as FormsRecyclerCell;
var view = new FormsRecyclerViewCellContainer(parent.Context, fastCell, parent, this.Element.ItemWidth, this.Element);
if (this.SelectionEnabled)
{
view.Click += MainView_Click;
}
//--------------**-----------------
//Here i added XF parent to XF cell
fastCell.Parent = this.Element;
var dpW = this.ConvertDpToPixels(this.Element.ItemWidth);
var dpH = this.ConvertDpToPixels(this.Element.ItemHeight);
view.SetMinimumWidth(dpW);
view.SetMinimumHeight(dpH);
view.LayoutParameters = new GridLayoutManager.LayoutParams(dpW, GridLayoutManager.LayoutParams.WrapContent);
return new FormsRecyclerViewCell(view);
}
Это всего лишь одна строка кода, теперь метки отлично работают с каждым параметром HorizontalOptions. Это было очень трудно выяснить, потому что у родного (android) ViewHolder был родной родитель, поэтому я думал, что XF VievHolder мгновенно получит того же родителя, но в виде версии XF (от средства визуализации). Я ошибся, и мне пришлось установить это самостоятельно.
Теперь я знаю, что все вычисления из.xaml реализованы в ядре Xamarin.Forms, и для правильных расчетов дети должны иметь своих родителей.
Я лично думаю, что это ошибка, используя HorizontalOptions
из Label
внутри Grid
, Не уверен, что вы можете попытаться подать эту проблему в Bugzilla.
По умолчанию для параметра HorizontalOptions установлено значение LayoutOptions.Fill
, это работает, когда это свойство установлено по умолчанию или FillAndExpand
остальные с разными HorizontalOptions
имеет ширину 0 на моей стороне, поэтому отображаются только некоторые из ваших ярлыков.
Обходной путь для решения этой проблемы - дать WidthRequest
на эти метки шириной 0, но обратите внимание, что
Присвоение HorizontalOptions изменяет расположение элемента при наличии избыточного пространства, доступного вдоль оси X из родительского макета. Кроме того, он указывает, должен ли элемент занимать оставшееся пространство по оси X от родительского макета. Если несколько дочерних элементов макета настроены на расширение, дополнительное пространство распределяется пропорционально.
Ваша ширина здесь должна быть меньше, чем родительская, чтобы увидеть результаты разных LayoutOptions
,