我想知道如何像下面的图片一样在TabbedPage
或CarouselPage
中添加指示滑动屏幕的点吗?
我尝试为此添加图像,但是它们看起来不自然,所以有真正的方法吗?
我的上述变通方法说明以3页为例:
我创建3张图像,每张图像都有3个点,其中一个突出显示:
第一个突出显示图像的点是第一个。
第二个图像突出显示的点是第二个。
等
答案 0 :(得分:1)
您可以使用Xamarin.Forms.CarouselView并为页面指示器编写一个用户控件。请按照以下步骤操作,
在所有3个项目(PCL,iOS和Android)中,使用来自NuGet的Xamarin.Forms.CarouselView版本2.3.0-pre2(Xamarin.Forms.CarouselView)软件包安装软件包控制台。
在页面指令中添加对Carousel视图的引用,
xmlns:cv="clr-namespace:Xamarin.Forms;assembly=Xamarin.Forms.CarouselView"
和下面的Xaml代码,
<StackLayout Padding="0,0,0,5" BackgroundColor="#d8d8d8" >
<cv:CarouselView x:Name="cview" ItemsSource="{Binding DataSource}" Position="{Binding Position, Mode=TwoWay}">
<cv:CarouselView.ItemTemplate>
<DataTemplate>
<Image Aspect="AspectFill" HorizontalOptions="Center" VerticalOptions="Center" Source="{Binding PickedImage}" />
</DataTemplate>
</cv:CarouselView.ItemTemplate>
</cv:CarouselView>
<cutomControl:CarouselIndicators IndicatorHeight="16" IndicatorWidth="16" UnselectedIndicator="unselected_circle.png" SelectedIndicator="selected_circle.png" Position="{Binding Position}" ItemsSource="{Binding DataSource}" />
</StackLayout>
注意,Position和您的ViewModel应该具有
private int _position;
public int Position
{
get { return _position; }
set
{
_position = value;
OnPropertyChanged();
}
}
注意,CarouselView下面的customControl。是的,您需要为其编写一个自定义控件。只需使用下面的自定义控制代码,然后在page指令中添加引用,
因此您的页面指令将如下所示,
xmlns:cutomControl="clr-namespace:XXXX.CustomControls;assembly=XXXX"
xmlns:cv="clr-namespace:Xamarin.Forms;assembly=Xamarin.Forms.CarouselView"
和自定义控制代码是
public class CarouselIndicators : Grid
{
private ImageSource UnselectedImageSource = null;
private ImageSource SelectedImageSource = null;
private readonly StackLayout _indicators = new StackLayout() { Orientation = StackOrientation.Horizontal, HorizontalOptions = LayoutOptions.CenterAndExpand };
public CarouselIndicators()
{
this.HorizontalOptions = LayoutOptions.CenterAndExpand;
this.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
this.Children.Add(_indicators);
}
public static readonly BindableProperty PositionProperty = BindableProperty.Create(nameof(Position), typeof(int), typeof(CarouselIndicators), 0, BindingMode.TwoWay, propertyChanging: PositionChanging);
public static readonly BindableProperty ItemsSourceProperty = BindableProperty.Create(nameof(ItemsSource), typeof(IEnumerable), typeof(CarouselIndicators), Enumerable.Empty<object>(), BindingMode.OneWay, propertyChanged: ItemsChanged);
public static readonly BindableProperty SelectedIndicatorProperty = BindableProperty.Create(nameof(SelectedIndicator), typeof(string), typeof(CarouselIndicators), "", BindingMode.OneWay);
public static readonly BindableProperty UnselectedIndicatorProperty = BindableProperty.Create(nameof(UnselectedIndicator), typeof(string), typeof(CarouselIndicators), "", BindingMode.OneWay);
public static readonly BindableProperty IndicatorWidthProperty = BindableProperty.Create(nameof(IndicatorWidth), typeof(double), typeof(CarouselIndicators), 0.0, BindingMode.OneWay);
public static readonly BindableProperty IndicatorHeightProperty = BindableProperty.Create(nameof(IndicatorHeight), typeof(double), typeof(CarouselIndicators), 0.0, BindingMode.OneWay);
public string SelectedIndicator
{
get { return (string)this.GetValue(SelectedIndicatorProperty); }
set { this.SetValue(SelectedIndicatorProperty, value); }
}
public string UnselectedIndicator
{
get { return (string)this.GetValue(UnselectedIndicatorProperty); }
set { this.SetValue(UnselectedIndicatorProperty, value); }
}
public double IndicatorWidth
{
get { return (double)this.GetValue(IndicatorWidthProperty); }
set { this.SetValue(IndicatorWidthProperty, value); }
}
public double IndicatorHeight
{
get { return (double)this.GetValue(IndicatorHeightProperty); }
set { this.SetValue(IndicatorHeightProperty, value); }
}
public int Position
{
get { return (int)this.GetValue(PositionProperty); }
set { this.SetValue(PositionProperty, value); }
}
public IEnumerable ItemsSource
{
get { return (IEnumerable)this.GetValue(ItemsSourceProperty); }
set { this.SetValue(ItemsSourceProperty, (object)value); }
}
private void Clear()
{
_indicators.Children.Clear();
}
private void Init(int position)
{
if (UnselectedImageSource == null)
UnselectedImageSource = ImageSource.FromFile(UnselectedIndicator);
if (SelectedImageSource == null)
SelectedImageSource = ImageSource.FromFile(SelectedIndicator);
if (_indicators.Children.Count > 0)
{
for (int i = 0; i < _indicators.Children.Count; i++)
{
if (((Image)_indicators.Children[i]).ClassId == nameof(State.Selected) && i != position)
_indicators.Children[i] = BuildImage(State.Unselected, i);
else if (((Image)_indicators.Children[i]).ClassId == nameof(State.Unselected) && i == position)
_indicators.Children[i] = BuildImage(State.Selected, i);
}
}
else
{
var enumerator = ItemsSource.GetEnumerator();
int count = 0;
while (enumerator.MoveNext())
{
Image image = null;
if (position == count)
image = BuildImage(State.Selected, count);
else
image = BuildImage(State.Unselected, count);
_indicators.Children.Add(image);
count++;
}
}
}
private Image BuildImage(State state, int position)
{
var image = new Image()
{
WidthRequest = IndicatorWidth,
HeightRequest = IndicatorHeight,
ClassId = state.ToString()
};
switch (state)
{
case State.Selected:
image.Source = SelectedImageSource;
break;
case State.Unselected:
image.Source = UnselectedImageSource;
break;
default:
throw new Exception("Invalid state selected");
}
image.GestureRecognizers.Add(new TapGestureRecognizer() { Command = new Command(() => { Position = position; }) });
return image;
}
private static void PositionChanging(object bindable, object oldValue, object newValue)
{
var carouselIndicators = bindable as CarouselIndicators;
carouselIndicators.Init(Convert.ToInt32(newValue));
}
private static void ItemsChanged(object bindable, object oldValue, object newValue)
{
var carouselIndicators = bindable as CarouselIndicators;
carouselIndicators.Clear();
carouselIndicators.Init(0);
}
public enum State
{
Selected,
Unselected
}
}