在设置视图可见后,ListView上的ScrollTo不会直接工作

时间:2018-05-17 12:25:05

标签: listview xamarin xamarin.forms

目前我正试图以对话形式将xamarin表单作为用户控件复制到android日期选择器,以用于练习目的,因为我真的讨厌iPhone日期选择器......不管怎样,现在一切正常好的,我可以选择一天,在几个月之间切换,选择一年等等。

但是现在只能解决我自己无法解决的一个小问题。 日期的起始ui包含年份和所选日期,如

  

2017年 - 2月22日星期三

如果用户点击年份,则会隐藏日期选择器并显示具有可用年份的listView。这也很好,我的问题是我想滚动到选定的年份,如果在提供的年份。但这只适用于我今年两次点击的情况。

因此,让我们说用户点击" 2017",现在他会看到列表视图并且不滚动并显示最上面的第一个项目。现在他轻拍了#34; 2017"再次,最后listView滚动到该位置,以便带有" 2017"显示在用户的中心。 也许下图更好地解释了它(开始 - > 2017年首次点击 - > 2017年第二次点击) Start -> First tap on 2017 -> Second tap on 2017

我做错了什么,有什么我看不到的吗?如果列表视图本身不可见,高度是否可能导致该行为?

注意:我已尝试使用scrollTo的设置或在创建实际视图时(即在构造函数或SelectedDate中)调用OnBindingContextChanged

注意2:第一次if(sender == YearLabel)检查为真,selection不为空但与第二次相同的值

XAML的重要部分

<StackLayout BackgroundColor="{DynamicResource AccentColor}" Spacing="5" Padding="15" Grid.Row="0">
        <Label Text="{Binding SelectedDate, StringFormat='{0:yyyy}', Source={x:Reference this}}" FontSize="Medium" TextColor="LightGray" x:Name="YearLabel">
            <Label.GestureRecognizers>
                <TapGestureRecognizer Tapped="OnDateLabelTapped"/>
            </Label.GestureRecognizers>
        </Label>
        <Label Text="{Binding SelectedDate, StringFormat='{0:ddd, d. MMMM}', Source={x:Reference this}" FontSize="Large" TextColor="White" x:Name="DayLabel">
            <Label.GestureRecognizers>
                <TapGestureRecognizer Tapped="OnDateLabelTapped"/>
            </Label.GestureRecognizers>
        </Label>
    </StackLayout>
    <StackLayout Grid.Row="1">
        <StackLayout x:Name="YearPicker" IsVisible="False" HorizontalOptions="FillAndExpand" Spacing="0">
            <ListView ItemSelected="OnYearSelected" x:Name="YearList" ItemTemplate="{StaticResource dateDataTemplateSelector}" SeparatorVisibility="None" />
            <BoxView HeightRequest="1" HorizontalOptions="FillAndExpand" Color="#efefef" />
        </StackLayout>
    ... other stuff

中的代码

public ObservableCollection<YearViewModel> Years { get; set; }

public DateTime SelectedDate
{
    get { return (DateTime)GetValue(SelectedDateProperty); }
    set { SetValue(SelectedDateProperty, value); }
}

private void OnDateLabelTapped(object sender, EventArgs args)
    {
        if(sender == YearLabel)
        {
            YearLabel.TextColor = Color.White;
            DayLabel.TextColor = Color.LightGray;
            YearPicker.IsVisible = true;
            DayPicker.IsVisible = false;

            var selection = Years.FirstOrDefault(y => y.Date.Year == SelectedDate.Year);
            YearList.ScrollTo(selection, ScrollToPosition.Center, true);
        }
        else if(sender == DayLabel)
        {
            DayLabel.TextColor = Color.White;
            YearLabel.TextColor = Color.LightGray;
            DayPicker.IsVisible = true;
            YearPicker.IsVisible = false;
        }
    }

如果您认为更多代码可能会有所帮助,请告诉我们!

1 个答案:

答案 0 :(得分:1)

所以,因为我一次又一次地调试这个,我猜是因为在设置YearPicker.IsVisible = true;之后直接缺少listView的高度是正确的。我对自己有点恼火,以前我没有看到过这个,但是没问题。

我目前的解决方案是

private void OnDateLabelTapped(object sender, EventArgs args)
    {
        if(sender == YearLabel)
        {
            YearLabel.TextColor = Color.White;
            DayLabel.TextColor = Color.LightGray;
            YearPicker.IsVisible = true;
            DayPicker.IsVisible = false;

            Device.StartTimer(TimeSpan.FromMilliseconds(20), () =>
            {
                var selection = Years.FirstOrDefault(y => y.Date.Year == SelectedDate.Year);
                YearList.ScrollTo(selection, ScrollToPosition.Center, true);
                return false;
            });
        }
        else if(sender == DayLabel)
        {
            DayLabel.TextColor = Color.White;
            YearLabel.TextColor = Color.LightGray;
            DayPicker.IsVisible = true;
            YearPicker.IsVisible = false;
        }
    }

所以基本上我只需要等待几毫秒来确保listview计算出它的高度并显示每个条目。

由于这种感觉很多就像黑客一样,我会感谢任何其他/更好的解决方案。 我已经尝试过侦听listView的sizeChanged事件但没有任何结果

YearList.SizeChanged += (s, e) =>
        {
            var selection = Years.FirstOrDefault(y => y.Date.Year == SelectedDate.Year);
            YearList.ScrollTo(selection, ScrollToPosition.Center, true);

        };