代码之家  ›  专栏  ›  技术社区  ›  Johannes

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

  •  1
  • Johannes  · 技术社区  · 7 年前

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

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

    2017年3月22日星期三。二月

    如果用户点击年份,则会隐藏日期选择器,并显示包含可用年份的列表视图。这也很好,我的问题是,如果点击显示的年份,我想滚动到所选年份。但这只有在一年中我点击两次才有效。

    假设用户点击“2017”,他现在看到的是列表视图,它没有滚动,而是在顶部显示第一个项目。现在,他再次点击“2017”,最后listView滚动到该位置,以便带有“2017”的项目显示在用户的中心。 也许下面的图片可以更好地解释这一点(开始->2017年第一次点击->2017年第二次点击) Start -> First tap on 2017 -> Second tap on 2017

    我做错什么了吗?有什么我看不见的吗?如果listview本身不可见,可能是高度导致了这种行为吗?

    注意:我已经打过电话了 scrollTo 设置 SelectedDate 或在创建实际视图时(即在构造函数中或 OnBindingContextChanged ).

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

    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 回复  |  直到 7 年前
        1
  •  1
  •   Johannes    7 年前

    所以,由于我一次又一次地调试它,我猜测这可能是因为在设置之后,listView的高度直接丢失了 YearPicker.IsVisible = true; 他说得对。我对自己有点恼火,因为我以前没有看到这一点,但还好。

    我当前的解决方案是

    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已计算出其高度并显示每个条目。

    因为这种感觉 很多 像黑客一样,我希望有其他/更好的解决方案。 我已经试过听 sizeChanged listView的事件,但没有任何结果

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