Xamarin Forms 旋转列表视图调整行宽
Xamarin Forms Rotating Listview adjust row width
在 Xamarin Forms 中,我想实现一个水平列表视图(如下图所示)。通过旋转这是可能的,但我无法更改行宽。是否还有可能让第二个布局在第一个布局下开始?
提前致谢!
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Recipe.Pages.SearchPage"
Title="Search">
<ContentPage.Content>
<StackLayout Spacing="5" x:Name="layout" Orientation="Vertical" >
<StackLayout x:Name="layoutButtons" HorizontalOptions="FillAndExpand" Orientation="Horizontal" Spacing="5" BackgroundColor="Red">
<Button x:Name="btn1" BackgroundColor="White" Image="@drawable/scan" />
<Button x:Name="btn2" BackgroundColor="White" Image="@drawable/menu" />
<Button x:Name="btn3" BackgroundColor="White" Image="@drawable/search" />
</StackLayout>
<StackLayout x:Name="layoutList" >
<ListView x:Name="listView" Rotation="270" RowHeight="75" >
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout BackgroundColor="#eee" Orientation="Vertical" >
<StackLayout Orientation="Horizontal" >
<Button BackgroundColor="White" Rotation="90" Image="{Binding Recipe}" />
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</StackLayout>
</ContentPage.Content>
</ContentPage>
编辑
我还尝试在列表视图中使用网格。有同样的问题。
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Recipe.Pages.SearchPage"
Title="Search">
<ContentPage.Content>
<StackLayout Spacing="5" x:Name="layout" Orientation="Vertical" >
<StackLayout x:Name="layoutButtons" HorizontalOptions="FillAndExpand" Orientation="Horizontal" Spacing="5" BackgroundColor="Red">
<Button x:Name="btn1" BackgroundColor="White" Image="@drawable/scan" />
<Button x:Name="btn2" BackgroundColor="White" Image="@drawable/menu" />
<Button x:Name="btn3" BackgroundColor="White" Image="@drawable/search" />
</StackLayout>
<StackLayout x:Name="layoutList" >
<ListView x:Name="listView" Rotation="270" RowHeight="75" >
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="75" />
</Grid.ColumnDefinitions>
<Button Grid.Column="0" BackgroundColor="White" Rotation="90" Image="{Binding Recipe}" />
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</StackLayout>
</ContentPage.Content>
</ContentPage>
我也遇到了同样的问题。我使用下面的 xaml 代码来管理 ListView
.
的高度和宽度
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="VCRoom.HorizontalScroll">
<ContentPage.Content >
<RelativeLayout>
<ListView x:Name="TestListView"
RowHeight="80"
Rotation="270"
RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width, Factor=0.5, Constant=-40}"
RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width, Factor=-0.5, Constant=40}"
RelativeLayout.WidthConstraint="{ConstraintExpression Type=Constant, Constant=80}"
RelativeLayout.HeightConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width, Factor=1}"
>
</ListView>
</RelativeLayout>
</ContentPage.Content>
</ContentPage>
更改 XConstraint
和 YConstraint
中的 RowHeight
和 Constant
以相应地管理水平 ListView
的宽度和高度。
仅供参考 下面是我用来填充 ListView
项的自定义单元格。我在每个列表项中显示了垂直标签。
<?xml version="1.0" encoding="UTF-8"?>
<ViewCell xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="VCRoom.TestCell">
<ViewCell.View>
<StackLayout Orientation="Horizontal" HorizontalOptions="End" VerticalOptions ="Center">
<Label Rotation="90" Text="{Binding Day}" TextColor="#000000" HorizontalOptions="StartAndExpand" VerticalOptions="Start"/>
<Label Rotation="90" Text="{Binding mDate}" TextColor="#000000" HorizontalOptions="StartAndExpand" VerticalOptions="Start"/>
</StackLayout>
</ViewCell.View>
</ViewCell>
希望这对未来的用户有所帮助。
我发现解决此问题的最佳解决方案是使用 Listview 的属性制作 CustomScrollView,如 Fabio Cozzolino 的 tutorial 中所示。
注意他在评论里有个updated version
He created a custom scrollview:
public class TLScrollView : ScrollView
{ public static readonly BindableProperty ItemsSourceProperty =
BindableProperty.Create("ItemsSource", typeof(IEnumerable), typeof(CustomScrollView), default(IEnumerable),
BindingMode.Default, null, new BindableProperty.BindingPropertyChangedDelegate(HandleBindingPropertyChangedDelegate));
private static object HandleBindingPropertyChangedDelegate(BindableObject bindable, object value)
{
throw new NotImplementedException();
}
public IEnumerable ItemsSource
{
get { return (IEnumerable)GetValue(ItemsSourceProperty); }
set { SetValue(ItemsSourceProperty, value); }
}
public static readonly BindableProperty ItemTemplateProperty =
BindableProperty.Create("ItemTemplate", typeof(DataTemplate), typeof(CustomScrollView), default(DataTemplate));
public DataTemplate ItemTemplate
{
get { return (DataTemplate)GetValue(ItemTemplateProperty); }
set { SetValue(ItemTemplateProperty, value); }
}
public event EventHandler<ItemTappedEventArgs> ItemSelected;
public static readonly BindableProperty SelectedCommandProperty =
BindableProperty.Create("SelectedCommand", typeof(ICommand), typeof(CustomScrollView), null);
public ICommand SelectedCommand
{
get { return (ICommand)GetValue(SelectedCommandProperty); }
set { SetValue(SelectedCommandProperty, value); }
}
public static readonly BindableProperty SelectedCommandParameterProperty =
BindableProperty.Create("SelectedCommandParameter", typeof(object), typeof(CustomScrollView), null);
public object SelectedCommandParameter
{
get { return GetValue(SelectedCommandParameterProperty); }
set { SetValue(SelectedCommandParameterProperty, value); }
}
static void HandleBindingPropertyChangedDelegate(BindableObject bindable, object oldValue, object newValue)
{
var isOldObservable = oldValue?.GetType().GetTypeInfo().ImplementedInterfaces.Any(i => i == typeof(INotifyCollectionChanged));
var isNewObservable = newValue?.GetType().GetTypeInfo().ImplementedInterfaces.Any(i => i == typeof(INotifyCollectionChanged));
var tl = (CustomScrollView)bindable;
if (isOldObservable.GetValueOrDefault(false))
{
((INotifyCollectionChanged)oldValue).CollectionChanged -= tl.HandleCollectionChanged;
}
if (isNewObservable.GetValueOrDefault(false))
{
((INotifyCollectionChanged)newValue).CollectionChanged += tl.HandleCollectionChanged;
}
if (oldValue != newValue)
{
tl.Render();
}
}
private void HandleCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
Render();
}
}
Created a method to render the scrollview:
public void Render ()
{ if (ItemTemplate == null || ItemsSource == null)
{
Content = null;
return;
}
var layout = new StackLayout();
layout.Orientation = Orientation == ScrollOrientation.Vertical ? StackOrientation.Vertical : StackOrientation.Horizontal;
foreach (var item in ItemsSource)
{
var command = SelectedCommand ?? new Command((obj) =>
{
var args = new ItemTappedEventArgs(ItemsSource, item);
ItemSelected?.Invoke(this, args);
});
var commandParameter = SelectedCommandParameter ?? item;
var viewCell = ItemTemplate.CreateContent() as ViewCell;
viewCell.View.BindingContext = item;
viewCell.View.GestureRecognizers.Add(new TapGestureRecognizer
{
Command = command,
CommandParameter = commandParameter,
NumberOfTapsRequired = 1
});
layout.Children.Add(viewCell.View);
}
Content = layout; }
Then, a customRenderer to each platform (Here iOS):
[assembly: ExportRenderer(typeof(TLScrollView), typeof(TLScrollViewRenderer))]
namespace TitiusLabs.Forms.iOS.Controls
{
class CustomScrollViewRenderer : ScrollViewRenderer
{
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
var element = e.NewElement as CustomScrollView;
element?.Render();
}
} }
您可以使用 FlowListView 插件在 xamarin 表单上轻松归档水平列表视图。
在 Xamarin Forms 中,我想实现一个水平列表视图(如下图所示)。通过旋转这是可能的,但我无法更改行宽。是否还有可能让第二个布局在第一个布局下开始? 提前致谢!
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Recipe.Pages.SearchPage"
Title="Search">
<ContentPage.Content>
<StackLayout Spacing="5" x:Name="layout" Orientation="Vertical" >
<StackLayout x:Name="layoutButtons" HorizontalOptions="FillAndExpand" Orientation="Horizontal" Spacing="5" BackgroundColor="Red">
<Button x:Name="btn1" BackgroundColor="White" Image="@drawable/scan" />
<Button x:Name="btn2" BackgroundColor="White" Image="@drawable/menu" />
<Button x:Name="btn3" BackgroundColor="White" Image="@drawable/search" />
</StackLayout>
<StackLayout x:Name="layoutList" >
<ListView x:Name="listView" Rotation="270" RowHeight="75" >
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout BackgroundColor="#eee" Orientation="Vertical" >
<StackLayout Orientation="Horizontal" >
<Button BackgroundColor="White" Rotation="90" Image="{Binding Recipe}" />
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</StackLayout>
</ContentPage.Content>
</ContentPage>
编辑 我还尝试在列表视图中使用网格。有同样的问题。
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Recipe.Pages.SearchPage"
Title="Search">
<ContentPage.Content>
<StackLayout Spacing="5" x:Name="layout" Orientation="Vertical" >
<StackLayout x:Name="layoutButtons" HorizontalOptions="FillAndExpand" Orientation="Horizontal" Spacing="5" BackgroundColor="Red">
<Button x:Name="btn1" BackgroundColor="White" Image="@drawable/scan" />
<Button x:Name="btn2" BackgroundColor="White" Image="@drawable/menu" />
<Button x:Name="btn3" BackgroundColor="White" Image="@drawable/search" />
</StackLayout>
<StackLayout x:Name="layoutList" >
<ListView x:Name="listView" Rotation="270" RowHeight="75" >
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="75" />
</Grid.ColumnDefinitions>
<Button Grid.Column="0" BackgroundColor="White" Rotation="90" Image="{Binding Recipe}" />
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</StackLayout>
</ContentPage.Content>
</ContentPage>
我也遇到了同样的问题。我使用下面的 xaml 代码来管理 ListView
.
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="VCRoom.HorizontalScroll">
<ContentPage.Content >
<RelativeLayout>
<ListView x:Name="TestListView"
RowHeight="80"
Rotation="270"
RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width, Factor=0.5, Constant=-40}"
RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width, Factor=-0.5, Constant=40}"
RelativeLayout.WidthConstraint="{ConstraintExpression Type=Constant, Constant=80}"
RelativeLayout.HeightConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width, Factor=1}"
>
</ListView>
</RelativeLayout>
</ContentPage.Content>
</ContentPage>
更改 XConstraint
和 YConstraint
中的 RowHeight
和 Constant
以相应地管理水平 ListView
的宽度和高度。
仅供参考 下面是我用来填充 ListView
项的自定义单元格。我在每个列表项中显示了垂直标签。
<?xml version="1.0" encoding="UTF-8"?>
<ViewCell xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="VCRoom.TestCell">
<ViewCell.View>
<StackLayout Orientation="Horizontal" HorizontalOptions="End" VerticalOptions ="Center">
<Label Rotation="90" Text="{Binding Day}" TextColor="#000000" HorizontalOptions="StartAndExpand" VerticalOptions="Start"/>
<Label Rotation="90" Text="{Binding mDate}" TextColor="#000000" HorizontalOptions="StartAndExpand" VerticalOptions="Start"/>
</StackLayout>
</ViewCell.View>
</ViewCell>
希望这对未来的用户有所帮助。
我发现解决此问题的最佳解决方案是使用 Listview 的属性制作 CustomScrollView,如 Fabio Cozzolino 的 tutorial 中所示。
注意他在评论里有个updated version
He created a custom scrollview:
public class TLScrollView : ScrollView
{ public static readonly BindableProperty ItemsSourceProperty =
BindableProperty.Create("ItemsSource", typeof(IEnumerable), typeof(CustomScrollView), default(IEnumerable),
BindingMode.Default, null, new BindableProperty.BindingPropertyChangedDelegate(HandleBindingPropertyChangedDelegate));
private static object HandleBindingPropertyChangedDelegate(BindableObject bindable, object value)
{
throw new NotImplementedException();
}
public IEnumerable ItemsSource
{
get { return (IEnumerable)GetValue(ItemsSourceProperty); }
set { SetValue(ItemsSourceProperty, value); }
}
public static readonly BindableProperty ItemTemplateProperty =
BindableProperty.Create("ItemTemplate", typeof(DataTemplate), typeof(CustomScrollView), default(DataTemplate));
public DataTemplate ItemTemplate
{
get { return (DataTemplate)GetValue(ItemTemplateProperty); }
set { SetValue(ItemTemplateProperty, value); }
}
public event EventHandler<ItemTappedEventArgs> ItemSelected;
public static readonly BindableProperty SelectedCommandProperty =
BindableProperty.Create("SelectedCommand", typeof(ICommand), typeof(CustomScrollView), null);
public ICommand SelectedCommand
{
get { return (ICommand)GetValue(SelectedCommandProperty); }
set { SetValue(SelectedCommandProperty, value); }
}
public static readonly BindableProperty SelectedCommandParameterProperty =
BindableProperty.Create("SelectedCommandParameter", typeof(object), typeof(CustomScrollView), null);
public object SelectedCommandParameter
{
get { return GetValue(SelectedCommandParameterProperty); }
set { SetValue(SelectedCommandParameterProperty, value); }
}
static void HandleBindingPropertyChangedDelegate(BindableObject bindable, object oldValue, object newValue)
{
var isOldObservable = oldValue?.GetType().GetTypeInfo().ImplementedInterfaces.Any(i => i == typeof(INotifyCollectionChanged));
var isNewObservable = newValue?.GetType().GetTypeInfo().ImplementedInterfaces.Any(i => i == typeof(INotifyCollectionChanged));
var tl = (CustomScrollView)bindable;
if (isOldObservable.GetValueOrDefault(false))
{
((INotifyCollectionChanged)oldValue).CollectionChanged -= tl.HandleCollectionChanged;
}
if (isNewObservable.GetValueOrDefault(false))
{
((INotifyCollectionChanged)newValue).CollectionChanged += tl.HandleCollectionChanged;
}
if (oldValue != newValue)
{
tl.Render();
}
}
private void HandleCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
Render();
}
}
Created a method to render the scrollview:
public void Render ()
{ if (ItemTemplate == null || ItemsSource == null)
{
Content = null;
return;
}
var layout = new StackLayout();
layout.Orientation = Orientation == ScrollOrientation.Vertical ? StackOrientation.Vertical : StackOrientation.Horizontal;
foreach (var item in ItemsSource)
{
var command = SelectedCommand ?? new Command((obj) =>
{
var args = new ItemTappedEventArgs(ItemsSource, item);
ItemSelected?.Invoke(this, args);
});
var commandParameter = SelectedCommandParameter ?? item;
var viewCell = ItemTemplate.CreateContent() as ViewCell;
viewCell.View.BindingContext = item;
viewCell.View.GestureRecognizers.Add(new TapGestureRecognizer
{
Command = command,
CommandParameter = commandParameter,
NumberOfTapsRequired = 1
});
layout.Children.Add(viewCell.View);
}
Content = layout; }
Then, a customRenderer to each platform (Here iOS):
[assembly: ExportRenderer(typeof(TLScrollView), typeof(TLScrollViewRenderer))]
namespace TitiusLabs.Forms.iOS.Controls
{
class CustomScrollViewRenderer : ScrollViewRenderer
{
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
var element = e.NewElement as CustomScrollView;
element?.Render();
}
} }
您可以使用 FlowListView 插件在 xamarin 表单上轻松归档水平列表视图。