来自url的图像未出现在Xamarin Forms无限列表视图中

时间:2018-08-17 20:23:53

标签: image listview asynchronous xamarin.forms

闲逛了一会儿之后,我收集了一些想法,并完善了自己的无限滚动方式,该方式不会扩展ListView,但反过来,它仅使用VM:

public class UpcomingMoviesViewModel
{
    private readonly int scollingThreshold = 15;
    private int loadStartIndex;
    private int page;

    public ObservableCollection<Movie> Movies { get; private set; }
    private IRestService service;

    public string Title { get { return "Upcoming Movies"; } }

    public UpcomingMoviesViewModel(IRestService service)
    {
        loadStartIndex = scollingThreshold;
        page = 1;
        Movies = new ObservableCollection<Movie>();
        this.service = service;
    }

    public async Task<bool> LoadUpcomingMovies()
    {
        var upcoming = await service.GetUpcomingMovies(page);
        var allGenres = await service.GetGenres();

        if (upcoming == null)
            return false;

        ConvertToBindableData(upcoming, allGenres);
        return true;
    }

    public async Task<bool> LoadMoreMovies(Movie e)
    {

        if (e.Position != loadStartIndex)
            return true;

        loadStartIndex = scollingThreshold + Movies.Count;
        page++;

        return await LoadUpcomingMovies();
    }


    private void ConvertToBindableData(List<Movie> upcoming, List<Genre> allGenres) 
    {
        int totalPagesInResponse = upcoming.Count;

        for (int i = 0; i < totalPagesInResponse; i++)
        {
            var movie = upcoming[i];
            //... 
            movie.Position = page == 1 ? i : i  + totalPagesInResponse * (page - 1); 
            Movies.Add(movie);
        }
    }
}

API响应发送的页面各包含20个项目,如果我想要整个列表,则必须在递增page的同时迭代所有页面。请注意,上面的scrollingThreshold设置为15。这意味着在滚动了15项而不是20项后,将对API进行新的调用。

这是我的模特

public class Movie
{
    public int Id { get; set; }
    public int Position { get; set; }
    public string Title { get; set; }
    public string PosterPath { get; set; }
    public string Overview { get; set; }
    public string ReleaseDate { get; set; }
    public List<int> GenreIds { get; set; }
    public string DisplayGenre { get; set; }
}

这就是事实。我首先在代码背后的LoadUpcomingMovies()事件中调用OnAppearing方法:

protected async override void OnAppearing()
{
    base.OnAppearing();

    var resultOk = await ((UpcomingMoviesViewModel)BindingContext).LoadUpcomingMovies();

    if (!resultOk)
        await DisplayAlert("Communication Error", 
        "An error has occurred while trying to communicate with the REST API", "OK");
}

那就像一种魅力。然后,我从LoadMoreMovies处理程序中调用ListView_ItemAppearing方法,它将获取所有数据,但不会加载图像:

private async void ListView_ItemAppearing(object sender, ItemVisibilityEventArgs e)
    {
        var resultOk = await ((UpcomingMoviesViewModel)BindingContext).LoadMoreMovies((Movie)e.Item);
        if (!resultOk)
            await DisplayAlert("Communication Error", 
            "An error has occurred while trying to communicate with the REST API", "OK");
    }

XAML文件:

<?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="MovieDbApp.View.UpcomingMoviesPage"
         Title="{Binding Title}">
    <ContentPage.Content>
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>

            <ListView x:Name="listView" Grid.Row="0" HasUnevenRows="True" SeparatorColor="DarkBlue" ItemsSource="{Binding Movies}">
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <ViewCell>
                            <StackLayout HorizontalOptions="StartAndExpand" Padding="5,5,5,5">
                                <Label Text="{Binding Title}"
                                   TextColor="MidnightBlue"
                                   FontSize="Medium"/>
                                <Image Source="{Binding PosterPath}" HorizontalOptions="Start" />
                                <Label Text="{Binding ReleaseDate}" 
                                   TextColor="DimGray"
                                   FontSize="Micro"/>
                                <Label Text="{Binding DisplayGenre}" 
                                   TextColor="MediumSlateBlue"
                                   FontSize="Micro"/>
                            </StackLayout>
                        </ViewCell>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
        </Grid>
    </ContentPage.Content>
</ContentPage>      

我研究了xamarin中的异步图像加载,它们都指向特定于平台的第三方库,但是找不到适合我需要的第三方库(我只是试图将其全部塞入PCL中,以便现在)。因此,我决定自己处理问题,并尝试创建一个异步图像加载器:

public class AsyncImageService
{
    private bool isLoading;

    public async Task<ImageSource> LoadImage(string imageUrl, ImageSource target)
    {
        Stream stream;
        ImageSource imageSource = null;
        if (!isLoading)
        {
            isLoading = true;
            if (!string.IsNullOrEmpty(imageUrl))
            {
                HttpClient client = new HttpClient();
                var uri = new Uri(imageUrl);
                stream = await client.GetStreamAsync(uri);
                imageSource = ImageSource.FromStream(() => stream);
            }
        }
        isLoading = false;

        return imageSource;
    }
}

但是由于经验不足,我不知道如何将其绑定到ListView单元格图像源。

我认为这里有各种各样的可能的解决方案,任何都会受到赞赏

0 个答案:

没有答案